LCOV - code coverage report
Current view: top level - source4/rpc_server/drsuapi - getncchanges.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 1181 1597 74.0 %
Date: 2024-05-31 13:13:24 Functions: 39 39 100.0 %

          Line data    Source code
       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 "../libcli/drsuapi/drsuapi.h"
      35             : #include "lib/util/binsearch.h"
      36             : #include "lib/util/tsort.h"
      37             : #include "auth/session.h"
      38             : #include "dsdb/common/util.h"
      39             : #include "lib/dbwrap/dbwrap.h"
      40             : #include "lib/dbwrap/dbwrap_rbt.h"
      41             : #include "librpc/gen_ndr/ndr_misc.h"
      42             : 
      43             : #undef DBGC_CLASS
      44             : #define DBGC_CLASS            DBGC_DRS_REPL
      45             : 
      46             : #define DRS_GUID_SIZE       16
      47             : #define DEFAULT_MAX_OBJECTS 1000
      48             : #define DEFAULT_MAX_LINKS   1500
      49             : 
      50             : /*
      51             :  * state of a partially-completed replication cycle. This state persists
      52             :  * over multiple calls to dcesrv_drsuapi_DsGetNCChanges()
      53             :  */
      54             : struct drsuapi_getncchanges_state {
      55             :         struct db_context *obj_cache;
      56             :         struct GUID *guids;
      57             :         uint32_t num_records;
      58             :         uint32_t num_processed;
      59             :         struct ldb_dn *ncRoot_dn;
      60             :         struct GUID ncRoot_guid;
      61             :         bool is_schema_nc;
      62             :         bool is_get_anc;
      63             :         bool broken_samba_4_5_get_anc_emulation;
      64             :         bool is_get_tgt;
      65             :         bool send_nc_root_first;
      66             :         uint64_t min_usn;
      67             :         uint64_t max_usn;
      68             :         struct drsuapi_DsReplicaHighWaterMark last_hwm;
      69             :         struct ldb_dn *last_dn;
      70             :         struct drsuapi_DsReplicaHighWaterMark final_hwm;
      71             :         struct drsuapi_DsReplicaCursor2CtrEx *final_udv;
      72             :         struct drsuapi_DsReplicaLinkedAttribute *la_list;
      73             :         uint32_t la_count;
      74             :         uint32_t la_idx;
      75             : 
      76             :         /* these are just used for debugging the replication's progress */
      77             :         uint32_t links_given;
      78             :         uint32_t total_links;
      79             : };
      80             : 
      81             : /* We must keep the GUIDs in NDR form for sorting */
      82             : struct la_for_sorting {
      83             :         const struct drsuapi_DsReplicaLinkedAttribute *link;
      84             :         uint8_t target_guid[DRS_GUID_SIZE];
      85             :         uint8_t source_guid[DRS_GUID_SIZE];
      86             : };
      87             : 
      88             : /*
      89             :  * stores the state for a chunk of replication data. This state information
      90             :  * only exists for a single call to dcesrv_drsuapi_DsGetNCChanges()
      91             :  */
      92             : struct getncchanges_repl_chunk {
      93             :         uint32_t max_objects;
      94             :         uint32_t max_links;
      95             :         uint32_t tgt_la_count;
      96             :         bool immediate_link_sync;
      97             :         time_t max_wait;
      98             :         time_t start;
      99             : 
     100             :         /* stores the objects to be sent in this chunk */
     101             :         uint32_t object_count;
     102             :         struct drsuapi_DsReplicaObjectListItemEx *object_list;
     103             : 
     104             :         /* the last object added to this replication chunk */
     105             :         struct drsuapi_DsReplicaObjectListItemEx *last_object;
     106             : };
     107             : 
     108        4355 : static int drsuapi_DsReplicaHighWaterMark_cmp(const struct drsuapi_DsReplicaHighWaterMark *h1,
     109             :                                               const struct drsuapi_DsReplicaHighWaterMark *h2)
     110             : {
     111        4355 :         if (h1->highest_usn < h2->highest_usn) {
     112           0 :                 return -1;
     113        4355 :         } else if (h1->highest_usn > h2->highest_usn) {
     114           0 :                 return 1;
     115        4355 :         } else if (h1->tmp_highest_usn < h2->tmp_highest_usn) {
     116        1832 :                 return -1;
     117        2523 :         } else if (h1->tmp_highest_usn > h2->tmp_highest_usn) {
     118          20 :                 return 1;
     119        2503 :         } else if (h1->reserved_usn < h2->reserved_usn) {
     120           0 :                 return -1;
     121        2503 :         } else if (h1->reserved_usn > h2->reserved_usn) {
     122           1 :                 return 1;
     123             :         }
     124             : 
     125        2502 :         return 0;
     126             : }
     127             : 
     128             : /*
     129             :   build a DsReplicaObjectIdentifier from a ldb msg
     130             :  */
     131      674883 : static struct drsuapi_DsReplicaObjectIdentifier *get_object_identifier(TALLOC_CTX *mem_ctx,
     132             :                                                                        const struct ldb_message *msg)
     133             : {
     134           0 :         struct drsuapi_DsReplicaObjectIdentifier *identifier;
     135           0 :         struct dom_sid *sid;
     136             : 
     137      674883 :         identifier = talloc(mem_ctx, struct drsuapi_DsReplicaObjectIdentifier);
     138      674883 :         if (identifier == NULL) {
     139           0 :                 return NULL;
     140             :         }
     141             : 
     142      674883 :         identifier->dn = ldb_dn_alloc_linearized(identifier, msg->dn);
     143      674883 :         identifier->guid = samdb_result_guid(msg, "objectGUID");
     144             : 
     145      674883 :         sid = samdb_result_dom_sid(identifier, msg, "objectSid");
     146      674883 :         if (sid) {
     147      108633 :                 identifier->sid = *sid;
     148             :         } else {
     149      566250 :                 ZERO_STRUCT(identifier->sid);
     150             :         }
     151      674883 :         return identifier;
     152             : }
     153             : 
     154     2142020 : static int udv_compare(const struct GUID *guid1, struct GUID guid2)
     155             : {
     156     2142020 :         return GUID_compare(guid1, &guid2);
     157             : }
     158             : 
     159             : /*
     160             :   see if we can filter an attribute using the uptodateness_vector
     161             :  */
     162     8205676 : static bool udv_filter(const struct drsuapi_DsReplicaCursorCtrEx *udv,
     163             :                        const struct GUID *originating_invocation_id,
     164             :                        uint64_t originating_usn)
     165             : {
     166           0 :         const struct drsuapi_DsReplicaCursor *c;
     167     8205676 :         if (udv == NULL) return false;
     168     2152104 :         BINARY_ARRAY_SEARCH(udv->cursors, udv->count, source_dsa_invocation_id,
     169             :                             originating_invocation_id, udv_compare, c);
     170     1331405 :         if (c && originating_usn <= c->highest_usn) {
     171      909443 :                 return true;
     172             :         }
     173      421962 :         return false;
     174             : }
     175             : 
     176     3689588 : static int uint32_t_cmp(uint32_t a1, uint32_t a2)
     177             : {
     178     3689588 :         if (a1 == a2) return 0;
     179     3315345 :         return a1 > a2 ? 1 : -1;
     180             : }
     181             : 
     182     3766331 : static int uint32_t_ptr_cmp(uint32_t *a1, uint32_t *a2)
     183             : {
     184     3766331 :         if (*a1 == *a2) return 0;
     185     3766331 :         return *a1 > *a2 ? 1 : -1;
     186             : }
     187             : 
     188      771277 : static WERROR getncchanges_attid_remote_to_local(const struct dsdb_schema *schema,
     189             :                                                  const struct dsdb_syntax_ctx *ctx,
     190             :                                                  enum drsuapi_DsAttributeId remote_attid_as_enum,
     191             :                                                  enum drsuapi_DsAttributeId *local_attid_as_enum,
     192             :                                                  const struct dsdb_attribute **_sa)
     193             : {
     194           0 :         WERROR werr;
     195      771277 :         const struct dsdb_attribute *sa = NULL;
     196             : 
     197      771277 :         if (ctx->pfm_remote == NULL) {
     198      180707 :                 DEBUG(7, ("No prefixMap supplied, falling back to local prefixMap.\n"));
     199      180707 :                 goto fail;
     200             :         }
     201             : 
     202      590570 :         werr = dsdb_attribute_drsuapi_remote_to_local(ctx,
     203             :                                                       remote_attid_as_enum,
     204             :                                                       local_attid_as_enum,
     205             :                                                       _sa);
     206      590570 :         if (!W_ERROR_IS_OK(werr)) {
     207           3 :                 DEBUG(3, ("WARNING: Unable to resolve remote attid, falling back to local prefixMap.\n"));
     208           3 :                 goto fail;
     209             :         }
     210             : 
     211      590567 :         return werr;
     212      180710 : fail:
     213             : 
     214      180710 :         sa = dsdb_attribute_by_attributeID_id(schema, remote_attid_as_enum);
     215      180710 :         if (sa == NULL) {
     216           3 :                 return WERR_DS_DRA_SCHEMA_MISMATCH;
     217             :         } else {
     218      180707 :                 if (local_attid_as_enum != NULL) {
     219      180502 :                         *local_attid_as_enum = sa->attributeID_id;
     220             :                 }
     221      180707 :                 if (_sa != NULL) {
     222         205 :                         *_sa = sa;
     223             :                 }
     224      180707 :                 return WERR_OK;
     225             :         }
     226             : }
     227             : 
     228       15577 : static WERROR getncchanges_update_revealed_list(struct ldb_context *sam_ctx,
     229             :                                                 TALLOC_CTX *mem_ctx,
     230             :                                                 struct ldb_message **msg,
     231             :                                                 struct ldb_dn *object_dn,
     232             :                                                 const struct GUID *object_guid,
     233             :                                                 const struct dsdb_attribute *sa,
     234             :                                                 struct replPropertyMetaData1 *meta_data,
     235             :                                                 struct ldb_message *revealed_users)
     236             : {
     237           0 :         enum ndr_err_code ndr_err;
     238           0 :         int ldb_err;
     239       15577 :         char *attr_str = NULL;
     240       15577 :         char *attr_hex = NULL;
     241           0 :         DATA_BLOB attr_blob;
     242       15577 :         struct ldb_message_element *existing = NULL, *el_add = NULL, *el_del = NULL;
     243       15577 :         const char * const * secret_attributes = ldb_get_opaque(sam_ctx, "LDB_SECRET_ATTRIBUTE_LIST");
     244             : 
     245       15577 :         if (!ldb_attr_in_list(secret_attributes,
     246       15577 :                               sa->lDAPDisplayName)) {
     247         237 :                 return WERR_OK;
     248             :         }
     249             : 
     250             : 
     251       15340 :         ndr_err = ndr_push_struct_blob(&attr_blob, mem_ctx, meta_data, (ndr_push_flags_fn_t)ndr_push_replPropertyMetaData1);
     252       15340 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     253           0 :                 return WERR_DS_DRA_INTERNAL_ERROR;
     254             :         }
     255             : 
     256       15340 :         attr_hex = hex_encode_talloc(mem_ctx, attr_blob.data, attr_blob.length);
     257       15340 :         if (attr_hex == NULL) {
     258           0 :                 return WERR_NOT_ENOUGH_MEMORY;
     259             :         }
     260             : 
     261       15340 :         attr_str = talloc_asprintf(mem_ctx, "B:%zd:%s:%s", attr_blob.length*2, attr_hex, ldb_dn_get_linearized(object_dn));
     262       15340 :         if (attr_str == NULL) {
     263           0 :                 return WERR_NOT_ENOUGH_MEMORY;
     264             :         }
     265             : 
     266       15340 :         existing = ldb_msg_find_element(revealed_users, "msDS-RevealedUsers");
     267       15340 :         if (existing != NULL) {
     268             :                 /* Replace the old value (if one exists) with the current one */
     269           0 :                 struct parsed_dn *link_dns;
     270       15050 :                 struct parsed_dn *exact = NULL, *unused = NULL;
     271           0 :                 uint8_t attid[4];
     272           0 :                 DATA_BLOB partial_meta;
     273             : 
     274       15050 :                 ldb_err = get_parsed_dns_trusted(mem_ctx, existing, &link_dns);
     275       15050 :                 if (ldb_err != LDB_SUCCESS) {
     276           0 :                         return WERR_DS_DRA_INTERNAL_ERROR;
     277             :                 }
     278             : 
     279             :                 /* Construct a partial metadata blob to match on in the DB */
     280       15050 :                 SIVAL(attid, 0, sa->attributeID_id);
     281       15050 :                 partial_meta.length = 4;
     282       15050 :                 partial_meta.data = attid;
     283             : 
     284             :                 /* Binary search using GUID and attribute id for uniqueness */
     285       15050 :                 ldb_err = parsed_dn_find(sam_ctx, link_dns, existing->num_values,
     286             :                                          object_guid, object_dn,
     287             :                                          partial_meta, 4,
     288             :                                          &exact, &unused,
     289             :                                          DSDB_SYNTAX_BINARY_DN, true);
     290             : 
     291       15050 :                 if (ldb_err != LDB_SUCCESS) {
     292           0 :                         DEBUG(0,(__location__ ": Failed parsed DN find - %s\n",
     293             :                                  ldb_errstring(sam_ctx)));
     294           0 :                         return WERR_DS_DRA_INTERNAL_ERROR;
     295             :                 }
     296             : 
     297       15050 :                 if (exact != NULL) {
     298             :                         /* Perform some verification of the blob */
     299           0 :                         struct replPropertyMetaData1 existing_meta_data;
     300         450 :                         ndr_err = ndr_pull_struct_blob_all_noalloc(&exact->dsdb_dn->extra_part,
     301             :                                                                    &existing_meta_data,
     302             :                                                                    (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaData1);
     303         450 :                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     304           0 :                                 return WERR_DS_DRA_INTERNAL_ERROR;
     305             :                         }
     306             : 
     307         450 :                         if (existing_meta_data.attid == sa->attributeID_id) {
     308         450 :                                 ldb_err = ldb_msg_add_empty(*msg, "msDS-RevealedUsers", LDB_FLAG_MOD_DELETE, &el_del);
     309         450 :                                 if (ldb_err != LDB_SUCCESS) {
     310           0 :                                         return WERR_DS_DRA_INTERNAL_ERROR;
     311             :                                 }
     312             : 
     313         450 :                                 el_del->values = talloc_array((*msg)->elements, struct ldb_val, 1);
     314         450 :                                 if (el_del->values == NULL) {
     315           0 :                                         return WERR_NOT_ENOUGH_MEMORY;
     316             :                                 }
     317         450 :                                 el_del->values[0] = *exact->v;
     318         450 :                                 el_del->num_values = 1;
     319             :                         } else {
     320           0 :                                 return WERR_DS_DRA_INTERNAL_ERROR;
     321             :                         }
     322             :                 }
     323             :         }
     324             : 
     325       15340 :         ldb_err = ldb_msg_add_empty(*msg, "msDS-RevealedUsers", LDB_FLAG_MOD_ADD, &el_add);
     326       15340 :         if (ldb_err != LDB_SUCCESS) {
     327           0 :                 return WERR_DS_DRA_INTERNAL_ERROR;
     328             :         }
     329             : 
     330       15340 :         el_add->values = talloc_array((*msg)->elements, struct ldb_val, 1);
     331       15340 :         if (el_add->values == NULL) {
     332           0 :                 return WERR_NOT_ENOUGH_MEMORY;
     333             : 
     334             :         }
     335             : 
     336       15340 :         el_add->values[0] = data_blob_string_const(attr_str);
     337       15340 :         el_add->num_values = 1;
     338             : 
     339       15340 :         return WERR_OK;
     340             : }
     341             : 
     342             : /*
     343             :  * This function filter attributes for build_object based on the
     344             :  * uptodatenessvector and partial attribute set.
     345             :  *
     346             :  * Any secret attributes are forced here for REPL_SECRET, and audited at this
     347             :  * point with msDS-RevealedUsers.
     348             :  */
     349      652557 : static WERROR get_nc_changes_filter_attrs(struct drsuapi_DsReplicaObjectListItemEx *obj,
     350             :                                           struct replPropertyMetaDataBlob md,
     351             :                                           struct ldb_context *sam_ctx,
     352             :                                           const struct ldb_message *msg,
     353             :                                           const struct GUID *guid,
     354             :                                           uint32_t *count,
     355             :                                           uint64_t highest_usn,
     356             :                                           const struct dsdb_attribute *rdn_sa,
     357             :                                           struct dsdb_schema *schema,
     358             :                                           struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector,
     359             :                                           struct drsuapi_DsPartialAttributeSet *partial_attribute_set,
     360             :                                           uint32_t *local_pas,
     361             :                                           uint32_t *attids,
     362             :                                           bool exop_secret,
     363             :                                           struct ldb_message **revealed_list_msg,
     364             :                                           struct ldb_message *existing_revealed_list_msg)
     365             : {
     366           0 :         uint32_t i, n;
     367           0 :         WERROR werr;
     368    10242200 :         for (n=i=0; i<md.ctr.ctr1.count; i++) {
     369           0 :                 const struct dsdb_attribute *sa;
     370     9589643 :                 bool force_attribute = false;
     371             : 
     372             :                 /* if the attribute has not changed, and it is not the
     373             :                    instanceType then don't include it */
     374     9589643 :                 if (md.ctr.ctr1.array[i].local_usn < highest_usn &&
     375      130855 :                     !exop_secret &&
     376      130855 :                     md.ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) continue;
     377             : 
     378             :                 /* don't include the rDN */
     379     9477749 :                 if (md.ctr.ctr1.array[i].attid == rdn_sa->attributeID_id) continue;
     380             : 
     381     8850659 :                 sa = dsdb_attribute_by_attributeID_id(schema, md.ctr.ctr1.array[i].attid);
     382     8850659 :                 if (!sa) {
     383           0 :                         DEBUG(0,(__location__ ": Failed to find attribute in schema for attrid %u mentioned in replPropertyMetaData of %s\n",
     384             :                                  (unsigned int)md.ctr.ctr1.array[i].attid,
     385             :                                  ldb_dn_get_linearized(msg->dn)));
     386           0 :                         return WERR_DS_DRA_INTERNAL_ERROR;
     387             :                 }
     388             : 
     389     8850659 :                 if (sa->linkID) {
     390           0 :                         struct ldb_message_element *el;
     391         118 :                         el = ldb_msg_find_element(msg, sa->lDAPDisplayName);
     392         118 :                         if (el && el->num_values && dsdb_dn_is_upgraded_link_val(&el->values[0])) {
     393             :                                 /* don't send upgraded links inline */
     394           0 :                                 continue;
     395             :                         }
     396             :                 }
     397             : 
     398     8850659 :                 if (exop_secret &&
     399       68841 :                     !dsdb_attr_in_rodc_fas(sa)) {
     400       15577 :                         force_attribute = true;
     401       15577 :                         DEBUG(4,("Forcing attribute %s in %s\n",
     402             :                                  sa->lDAPDisplayName, ldb_dn_get_linearized(msg->dn)));
     403       15577 :                         werr = getncchanges_update_revealed_list(sam_ctx, obj,
     404             :                                                                  revealed_list_msg,
     405       15577 :                                                                  msg->dn, guid, sa,
     406       15577 :                                                                  &md.ctr.ctr1.array[i],
     407             :                                                                  existing_revealed_list_msg);
     408       15577 :                         if (!W_ERROR_IS_OK(werr)) {
     409           0 :                                 return werr;
     410             :                         }
     411             :                 }
     412             : 
     413             :                 /* filter by uptodateness_vector */
     414     8850659 :                 if (md.ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType &&
     415    16380627 :                     !force_attribute &&
     416     8182525 :                     udv_filter(uptodateness_vector,
     417     8182525 :                                &md.ctr.ctr1.array[i].originating_invocation_id,
     418     8182525 :                                md.ctr.ctr1.array[i].originating_usn)) {
     419      908618 :                         continue;
     420             :                 }
     421             : 
     422             :                 /* filter by partial_attribute_set */
     423     7942041 :                 if (partial_attribute_set && !force_attribute) {
     424      427359 :                         uint32_t *result = NULL;
     425     3742704 :                         BINARY_ARRAY_SEARCH_V(local_pas, partial_attribute_set->num_attids, sa->attributeID_id,
     426             :                                               uint32_t_cmp, result);
     427      427359 :                         if (result == NULL) {
     428       53116 :                                 continue;
     429             :                         }
     430             :                 }
     431             : 
     432     7888925 :                 obj->meta_data_ctr->meta_data[n].originating_change_time = md.ctr.ctr1.array[i].originating_change_time;
     433     7888925 :                 obj->meta_data_ctr->meta_data[n].version = md.ctr.ctr1.array[i].version;
     434     7888925 :                 obj->meta_data_ctr->meta_data[n].originating_invocation_id = md.ctr.ctr1.array[i].originating_invocation_id;
     435     7888925 :                 obj->meta_data_ctr->meta_data[n].originating_usn = md.ctr.ctr1.array[i].originating_usn;
     436     7888925 :                 attids[n] = md.ctr.ctr1.array[i].attid;
     437             : 
     438     7888925 :                 n++;
     439             :         }
     440             : 
     441      652557 :         *count = n;
     442             : 
     443      652557 :         return WERR_OK;
     444             : }
     445             : 
     446             : /* 
     447             :   drsuapi_DsGetNCChanges for one object
     448             : */
     449      653070 : static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItemEx *obj,
     450             :                                           const struct ldb_message *msg,
     451             :                                           struct ldb_context *sam_ctx,
     452             :                                           struct drsuapi_getncchanges_state *getnc_state,
     453             :                                           struct dsdb_schema *schema,
     454             :                                           DATA_BLOB *session_key,
     455             :                                           struct drsuapi_DsGetNCChangesRequest10 *req10,
     456             :                                           bool force_object_return,
     457             :                                           uint32_t *local_pas,
     458             :                                           struct ldb_dn *machine_dn,
     459             :                                           const struct GUID *guid)
     460             : {
     461           0 :         const struct ldb_val *md_value;
     462           0 :         uint32_t i, n;
     463           0 :         struct replPropertyMetaDataBlob md;
     464      653070 :         uint32_t rid = 0;
     465           0 :         int ldb_err;
     466           0 :         enum ndr_err_code ndr_err;
     467           0 :         uint32_t *attids;
     468           0 :         const char *rdn;
     469           0 :         const struct dsdb_attribute *rdn_sa;
     470           0 :         uint64_t uSNChanged;
     471           0 :         unsigned int instanceType;
     472           0 :         struct dsdb_syntax_ctx syntax_ctx;
     473      653070 :         struct ldb_result *res = NULL;
     474           0 :         WERROR werr;
     475           0 :         int ret;
     476      653070 :         uint32_t replica_flags = req10->replica_flags;
     477      653070 :         struct drsuapi_DsPartialAttributeSet *partial_attribute_set =
     478             :                         req10->partial_attribute_set;
     479      653070 :         struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector =
     480             :                         req10->uptodateness_vector;
     481      653070 :         enum drsuapi_DsExtendedOperation extended_op = req10->extended_op;
     482      653070 :         bool is_schema_nc = getnc_state->is_schema_nc;
     483      653070 :         uint64_t highest_usn = getnc_state->min_usn;
     484             : 
     485             :         /* make dsdb syntax context for conversions */
     486      653070 :         dsdb_syntax_ctx_init(&syntax_ctx, sam_ctx, schema);
     487      653070 :         syntax_ctx.is_schema_nc = is_schema_nc;
     488             : 
     489      653070 :         uSNChanged = ldb_msg_find_attr_as_uint64(msg, "uSNChanged", 0);
     490      653070 :         instanceType = ldb_msg_find_attr_as_uint(msg, "instanceType", 0);
     491      653070 :         if (instanceType & INSTANCE_TYPE_IS_NC_HEAD) {
     492        1455 :                 obj->is_nc_prefix = true;
     493        1455 :                 obj->parent_object_guid = NULL;
     494             :         } else {
     495      651615 :                 obj->is_nc_prefix = false;
     496      651615 :                 obj->parent_object_guid = talloc(obj, struct GUID);
     497      651615 :                 if (obj->parent_object_guid == NULL) {
     498           0 :                         return WERR_DS_DRA_INTERNAL_ERROR;
     499             :                 }
     500      651615 :                 *obj->parent_object_guid = samdb_result_guid(msg, "parentGUID");
     501      651615 :                 if (GUID_all_zero(obj->parent_object_guid)) {
     502           0 :                         DEBUG(0,(__location__ ": missing parentGUID for %s\n",
     503             :                                  ldb_dn_get_linearized(msg->dn)));
     504           0 :                         return WERR_DS_DRA_INTERNAL_ERROR;
     505             :                 }
     506             :         }
     507      653070 :         obj->next_object = NULL;
     508             : 
     509      653070 :         md_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
     510      653070 :         if (!md_value) {
     511             :                 /* nothing to send */
     512           0 :                 return WERR_OK;
     513             :         }
     514             : 
     515      653070 :         if (instanceType & INSTANCE_TYPE_UNINSTANT) {
     516             :                 /* don't send uninstantiated objects */
     517           0 :                 return WERR_OK;
     518             :         }
     519             : 
     520      653070 :         if (uSNChanged <= highest_usn) {
     521             :                 /* nothing to send */
     522         513 :                 return WERR_OK;
     523             :         }
     524             : 
     525      652557 :         ndr_err = ndr_pull_struct_blob(md_value, obj, &md,
     526             :                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
     527      652557 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     528           0 :                 return WERR_DS_DRA_INTERNAL_ERROR;
     529             :         }
     530             : 
     531      652557 :         if (md.version != 1) {
     532           0 :                 return WERR_DS_DRA_INTERNAL_ERROR;
     533             :         }
     534             : 
     535      652557 :         rdn = ldb_dn_get_rdn_name(msg->dn);
     536      652557 :         if (rdn == NULL) {
     537           0 :                 DEBUG(0,(__location__ ": No rDN for %s\n", ldb_dn_get_linearized(msg->dn)));
     538           0 :                 return WERR_DS_DRA_INTERNAL_ERROR;
     539             :         }
     540             : 
     541      652557 :         rdn_sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn);
     542      652557 :         if (rdn_sa == NULL) {
     543           0 :                 DEBUG(0,(__location__ ": Can't find dsds_attribute for rDN %s in %s\n",
     544             :                          rdn, ldb_dn_get_linearized(msg->dn)));
     545           0 :                 return WERR_DS_DRA_INTERNAL_ERROR;
     546             :         }
     547             : 
     548      652557 :         obj->meta_data_ctr = talloc(obj, struct drsuapi_DsReplicaMetaDataCtr);
     549      652557 :         attids = talloc_array(obj, uint32_t, md.ctr.ctr1.count);
     550             : 
     551      652557 :         obj->object.identifier = get_object_identifier(obj, msg);
     552      652557 :         if (obj->object.identifier == NULL) {
     553           0 :                 return WERR_NOT_ENOUGH_MEMORY;
     554             :         }
     555      652557 :         dom_sid_split_rid(NULL, &obj->object.identifier->sid, NULL, &rid);
     556             : 
     557      652557 :         obj->meta_data_ctr->meta_data = talloc_array(obj, struct drsuapi_DsReplicaMetaData, md.ctr.ctr1.count);
     558             : 
     559      652557 :         if (extended_op == DRSUAPI_EXOP_REPL_SECRET) {
     560             :                 /* Get the existing revealed users for the destination */
     561        3068 :                 struct ldb_message *revealed_list_msg = NULL;
     562        3068 :                 struct ldb_message *existing_revealed_list_msg = NULL;
     563        3068 :                 const char *machine_attrs[] = {
     564             :                         "msDS-RevealedUsers",
     565             :                         NULL
     566             :                 };
     567             : 
     568        3068 :                 revealed_list_msg = ldb_msg_new(sam_ctx);
     569        3068 :                 if (revealed_list_msg == NULL) {
     570           0 :                         return WERR_NOT_ENOUGH_MEMORY;
     571             :                 }
     572        3068 :                 revealed_list_msg->dn = machine_dn;
     573             : 
     574        3068 :                 ret = ldb_transaction_start(sam_ctx);
     575        3068 :                 if (ret != LDB_SUCCESS) {
     576           0 :                         DEBUG(0,(__location__ ": Failed transaction start - %s\n",
     577             :                                  ldb_errstring(sam_ctx)));
     578           0 :                         return WERR_DS_DRA_INTERNAL_ERROR;
     579             :                 }
     580             : 
     581        3068 :                 ldb_err = dsdb_search_dn(sam_ctx, obj, &res, machine_dn, machine_attrs, DSDB_SEARCH_SHOW_EXTENDED_DN);
     582        3068 :                 if (ldb_err != LDB_SUCCESS || res->count != 1) {
     583           0 :                         ldb_transaction_cancel(sam_ctx);
     584           0 :                         return WERR_DS_DRA_INTERNAL_ERROR;
     585             :                 }
     586             : 
     587        3068 :                 existing_revealed_list_msg = res->msgs[0];
     588             : 
     589        3068 :                 werr = get_nc_changes_filter_attrs(obj, md, sam_ctx, msg,
     590             :                                                    guid, &n, highest_usn,
     591             :                                                    rdn_sa, schema,
     592             :                                                    uptodateness_vector,
     593             :                                                    partial_attribute_set, local_pas,
     594             :                                                    attids,
     595             :                                                    true,
     596             :                                                    &revealed_list_msg,
     597             :                                                    existing_revealed_list_msg);
     598        3068 :                 if (!W_ERROR_IS_OK(werr)) {
     599           0 :                         ldb_transaction_cancel(sam_ctx);
     600           0 :                         return werr;
     601             :                 }
     602             : 
     603        3068 :                 if (revealed_list_msg != NULL) {
     604        3068 :                         ret = ldb_modify(sam_ctx, revealed_list_msg);
     605        3068 :                         if (ret != LDB_SUCCESS) {
     606           0 :                                 DEBUG(0,(__location__ ": Failed to alter revealed links - %s\n",
     607             :                                          ldb_errstring(sam_ctx)));
     608           0 :                                 ldb_transaction_cancel(sam_ctx);
     609           0 :                                 return WERR_DS_DRA_INTERNAL_ERROR;
     610             :                         }
     611             :                 }
     612             : 
     613        3068 :                 ret = ldb_transaction_commit(sam_ctx);
     614        3068 :                 if (ret != LDB_SUCCESS) {
     615           0 :                         DEBUG(0,(__location__ ": Failed transaction commit - %s\n",
     616             :                                  ldb_errstring(sam_ctx)));
     617           0 :                         return WERR_DS_DRA_INTERNAL_ERROR;
     618             :                 }
     619             :         } else {
     620      649489 :                 werr = get_nc_changes_filter_attrs(obj, md, sam_ctx, msg, guid,
     621             :                                                    &n, highest_usn, rdn_sa,
     622             :                                                    schema, uptodateness_vector,
     623             :                                                    partial_attribute_set, local_pas,
     624             :                                                    attids,
     625             :                                                    false,
     626             :                                                    NULL,
     627             :                                                    NULL);
     628      649489 :                 if (!W_ERROR_IS_OK(werr)) {
     629           0 :                         return werr;
     630             :                 }
     631             :         }
     632             : 
     633             :         /* ignore it if its an empty change. Note that renames always
     634             :          * change the 'name' attribute, so they won't be ignored by
     635             :          * this
     636             : 
     637             :          * the force_object_return check is used to force an empty
     638             :          * object return when we timeout in the getncchanges loop.
     639             :          * This allows us to return an empty object, which keeps the
     640             :          * client happy while preventing timeouts
     641             :          */
     642      652557 :         if (n == 0 ||
     643      652557 :             (n == 1 &&
     644       76069 :              attids[0] == DRSUAPI_ATTID_instanceType &&
     645       76046 :              !force_object_return)) {
     646       76046 :                 talloc_free(obj->meta_data_ctr);
     647       76046 :                 obj->meta_data_ctr = NULL;
     648       76046 :                 return WERR_OK;
     649             :         }
     650             : 
     651      576511 :         obj->meta_data_ctr->count = n;
     652             : 
     653      576511 :         obj->object.flags = DRSUAPI_DS_REPLICA_OBJECT_FROM_MASTER;
     654      576511 :         obj->object.attribute_ctr.num_attributes = obj->meta_data_ctr->count;
     655      576511 :         obj->object.attribute_ctr.attributes = talloc_array(obj, struct drsuapi_DsReplicaAttribute,
     656             :                                                             obj->object.attribute_ctr.num_attributes);
     657      576511 :         if (obj->object.attribute_ctr.attributes == NULL) {
     658           0 :                 return WERR_NOT_ENOUGH_MEMORY;
     659             :         }
     660             : 
     661             :         /*
     662             :          * Note that the meta_data array and the attributes array must
     663             :          * be the same size and in the same order
     664             :          */
     665     8389390 :         for (i=0; i<obj->object.attribute_ctr.num_attributes; i++) {
     666           0 :                 struct ldb_message_element *el;
     667           0 :                 const struct dsdb_attribute *sa;
     668             : 
     669     7812879 :                 sa = dsdb_attribute_by_attributeID_id(schema, attids[i]);
     670     7812879 :                 if (!sa) {
     671           0 :                         DEBUG(0,("Unable to find attributeID %u in schema\n", attids[i]));
     672           0 :                         return WERR_DS_DRA_INTERNAL_ERROR;
     673             :                 }
     674             : 
     675     7812879 :                 el = ldb_msg_find_element(msg, sa->lDAPDisplayName);
     676     7812879 :                 if (el == NULL) {
     677             :                         /* this happens for attributes that have been removed */
     678      836013 :                         DEBUG(5,("No element '%s' for attributeID %u in message\n",
     679             :                                  sa->lDAPDisplayName, attids[i]));
     680      836013 :                         ZERO_STRUCT(obj->object.attribute_ctr.attributes[i]);
     681      836013 :                         obj->object.attribute_ctr.attributes[i].attid =
     682      836013 :                                         dsdb_attribute_get_attid(sa, syntax_ctx.is_schema_nc);
     683             :                 } else {
     684     6976866 :                         werr = sa->syntax->ldb_to_drsuapi(&syntax_ctx, sa, el, obj,
     685     6976866 :                                                           &obj->object.attribute_ctr.attributes[i]);
     686     6976866 :                         if (!W_ERROR_IS_OK(werr)) {
     687           0 :                                 DEBUG(0,("Unable to convert %s on %s to DRS object - %s\n",
     688             :                                          sa->lDAPDisplayName, ldb_dn_get_linearized(msg->dn),
     689             :                                          win_errstr(werr)));
     690           0 :                                 return werr;
     691             :                         }
     692             :                         /* if DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING is set
     693             :                          * check if attribute is secret and send a null value
     694             :                          */
     695     6976866 :                         if (replica_flags & DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING) {
     696     1191402 :                                 drsuapi_process_secret_attribute(&obj->object.attribute_ctr.attributes[i],
     697     1191402 :                                                                  &obj->meta_data_ctr->meta_data[i]);
     698             :                         }
     699             :                         /* some attributes needs to be encrypted
     700             :                            before being sent */
     701     6976866 :                         werr = drsuapi_encrypt_attribute(obj, session_key, rid, 
     702     6976866 :                                                          &obj->object.attribute_ctr.attributes[i]);
     703     6976866 :                         if (!W_ERROR_IS_OK(werr)) {
     704           0 :                                 DEBUG(0,("Unable to encrypt %s on %s in DRS object - %s\n",
     705             :                                          sa->lDAPDisplayName, ldb_dn_get_linearized(msg->dn),
     706             :                                          win_errstr(werr)));
     707           0 :                                 return werr;
     708             :                         }
     709             :                 }
     710     7812879 :                 if (attids[i] != obj->object.attribute_ctr.attributes[i].attid) {
     711           0 :                         DEBUG(0, ("Unable to replicate attribute %s on %s via DRS, incorrect attributeID:  "
     712             :                                   "0x%08x vs 0x%08x "
     713             :                                   "Run dbcheck!\n",
     714             :                                   sa->lDAPDisplayName,
     715             :                                   ldb_dn_get_linearized(msg->dn),
     716             :                                   attids[i],
     717             :                                   obj->object.attribute_ctr.attributes[i].attid));
     718           0 :                         return WERR_DS_DATABASE_ERROR;
     719             :                 }
     720             :         }
     721             : 
     722      576511 :         return WERR_OK;
     723             : }
     724             : 
     725             : /*
     726             :   add one linked attribute from an object to the list of linked
     727             :   attributes in a getncchanges request
     728             :  */
     729       22326 : static WERROR get_nc_changes_add_la(TALLOC_CTX *mem_ctx,
     730             :                                     struct ldb_context *sam_ctx,
     731             :                                     const struct dsdb_schema *schema,
     732             :                                     const struct dsdb_attribute *sa,
     733             :                                     const struct ldb_message *msg,
     734             :                                     struct dsdb_dn *dsdb_dn,
     735             :                                     struct drsuapi_DsReplicaLinkedAttribute **la_list,
     736             :                                     uint32_t *la_count,
     737             :                                     bool is_schema_nc)
     738             : {
     739           0 :         struct drsuapi_DsReplicaLinkedAttribute *la;
     740           0 :         bool active;
     741           0 :         NTSTATUS status;
     742           0 :         WERROR werr;
     743             : 
     744       22326 :         (*la_list) = talloc_realloc(mem_ctx, *la_list, struct drsuapi_DsReplicaLinkedAttribute, (*la_count)+1);
     745       22326 :         W_ERROR_HAVE_NO_MEMORY(*la_list);
     746             : 
     747       22326 :         la = &(*la_list)[*la_count];
     748             : 
     749       22326 :         la->identifier = get_object_identifier(*la_list, msg);
     750       22326 :         W_ERROR_HAVE_NO_MEMORY(la->identifier);
     751             : 
     752       22326 :         active = (dsdb_dn_rmd_flags(dsdb_dn->dn) & DSDB_RMD_FLAG_DELETED) == 0;
     753             : 
     754       22326 :         if (!active) {
     755             :                 /* We have to check that the inactive link still point to an existing object */
     756           0 :                 struct GUID guid;
     757           0 :                 struct ldb_dn *tdn;
     758           0 :                 int ret;
     759           0 :                 const char *v;
     760             : 
     761         406 :                 v = ldb_msg_find_attr_as_string(msg, "isDeleted", "FALSE");
     762         406 :                 if (strncmp(v, "TRUE", 4) == 0) {
     763             :                         /*
     764             :                           * Note: we skip the transmission of the deleted link even if the other part used to
     765             :                           * know about it because when we transmit the deletion of the object, the link will
     766             :                           * be deleted too due to deletion of object where link points and Windows do so.
     767             :                           */
     768           0 :                         if (dsdb_functional_level(sam_ctx) >= DS_DOMAIN_FUNCTION_2008_R2) {
     769           0 :                                 v = ldb_msg_find_attr_as_string(msg, "isRecycled", "FALSE");
     770             :                                 /*
     771             :                                  * On Windows 2008R2 isRecycled is always present even if FL or DL are < FL 2K8R2
     772             :                                  * if it join an existing domain with deleted objects, it firsts impose to have a
     773             :                                  * schema with the is-Recycled object and for all deleted objects it adds the isRecycled
     774             :                                  * either during initial replication or after the getNCChanges.
     775             :                                  * Behavior of samba has been changed to always have this attribute if it's present in the schema.
     776             :                                  *
     777             :                                  * So if FL <2K8R2 isRecycled might be here or not but we don't care, it's meaning less.
     778             :                                  * If FL >=2K8R2 we are sure that this attribute will be here.
     779             :                                  * For this kind of forest level we do not return the link if the object is recycled
     780             :                                  * (isRecycled = true).
     781             :                                  */
     782           0 :                                 if (strncmp(v, "TRUE", 4) == 0) {
     783           0 :                                         DEBUG(2, (" object %s is recycled, not returning linked attribute !\n",
     784             :                                                                 ldb_dn_get_linearized(msg->dn)));
     785           0 :                                         return WERR_OK;
     786             :                                 }
     787             :                         } else {
     788           0 :                                 return WERR_OK;
     789             :                         }
     790             :                 }
     791         406 :                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
     792         406 :                 if (!NT_STATUS_IS_OK(status)) {
     793           0 :                         DEBUG(0,(__location__ " Unable to extract GUID in linked attribute '%s' in '%s'\n",
     794             :                                 sa->lDAPDisplayName, ldb_dn_get_linearized(msg->dn)));
     795           0 :                         return ntstatus_to_werror(status);
     796             :                 }
     797         406 :                 ret = dsdb_find_dn_by_guid(sam_ctx, mem_ctx, &guid, 0, &tdn);
     798         406 :                 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
     799          66 :                         DEBUG(2, (" Search of guid %s returned 0 objects, skipping it !\n",
     800             :                                                 GUID_string(mem_ctx, &guid)));
     801          66 :                         return WERR_OK;
     802         340 :                 } else if (ret != LDB_SUCCESS) {
     803           0 :                         DEBUG(0, (__location__ " Search of guid %s failed with error code %d\n",
     804             :                                                 GUID_string(mem_ctx, &guid),
     805             :                                                 ret));
     806           0 :                         return WERR_OK;
     807             :                 }
     808             :         }
     809       22260 :         la->attid = dsdb_attribute_get_attid(sa, is_schema_nc);
     810       22260 :         la->flags = active?DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE:0;
     811             : 
     812       22260 :         status = dsdb_get_extended_dn_uint32(dsdb_dn->dn, &la->meta_data.version, "RMD_VERSION");
     813       22260 :         if (!NT_STATUS_IS_OK(status)) {
     814           0 :                 DEBUG(0,(__location__ " No RMD_VERSION in linked attribute '%s' in '%s'\n",
     815             :                          sa->lDAPDisplayName, ldb_dn_get_linearized(msg->dn)));
     816           0 :                 return ntstatus_to_werror(status);
     817             :         }
     818       22260 :         status = dsdb_get_extended_dn_nttime(dsdb_dn->dn, &la->meta_data.originating_change_time, "RMD_CHANGETIME");
     819       22260 :         if (!NT_STATUS_IS_OK(status)) {
     820           0 :                 DEBUG(0,(__location__ " No RMD_CHANGETIME in linked attribute '%s' in '%s'\n",
     821             :                          sa->lDAPDisplayName, ldb_dn_get_linearized(msg->dn)));
     822           0 :                 return ntstatus_to_werror(status);
     823             :         }
     824       22260 :         status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &la->meta_data.originating_invocation_id, "RMD_INVOCID");
     825       22260 :         if (!NT_STATUS_IS_OK(status)) {
     826           0 :                 DEBUG(0,(__location__ " No RMD_INVOCID in linked attribute '%s' in '%s'\n",
     827             :                          sa->lDAPDisplayName, ldb_dn_get_linearized(msg->dn)));
     828           0 :                 return ntstatus_to_werror(status);
     829             :         }
     830       22260 :         status = dsdb_get_extended_dn_uint64(dsdb_dn->dn, &la->meta_data.originating_usn, "RMD_ORIGINATING_USN");
     831       22260 :         if (!NT_STATUS_IS_OK(status)) {
     832           0 :                 DEBUG(0,(__location__ " No RMD_ORIGINATING_USN in linked attribute '%s' in '%s'\n",
     833             :                          sa->lDAPDisplayName, ldb_dn_get_linearized(msg->dn)));
     834           0 :                 return ntstatus_to_werror(status);
     835             :         }
     836             : 
     837       22260 :         status = dsdb_get_extended_dn_nttime(dsdb_dn->dn, &la->originating_add_time, "RMD_ADDTIME");
     838       22260 :         if (!NT_STATUS_IS_OK(status)) {
     839             :                 /* this is possible for upgraded links */
     840           0 :                 la->originating_add_time = la->meta_data.originating_change_time;
     841             :         }
     842             : 
     843       22260 :         werr = dsdb_dn_la_to_blob(sam_ctx, sa, schema, *la_list, dsdb_dn, &la->value.blob);
     844       22260 :         W_ERROR_NOT_OK_RETURN(werr);
     845             : 
     846       22260 :         (*la_count)++;
     847       22260 :         return WERR_OK;
     848             : }
     849             : 
     850             : 
     851             : /*
     852             :   add linked attributes from an object to the list of linked
     853             :   attributes in a getncchanges request
     854             :  */
     855      651504 : static WERROR get_nc_changes_add_links(struct ldb_context *sam_ctx,
     856             :                                        TALLOC_CTX *mem_ctx,
     857             :                                        bool is_schema_nc,
     858             :                                        struct dsdb_schema *schema,
     859             :                                        uint64_t highest_usn,
     860             :                                        uint32_t replica_flags,
     861             :                                        const struct ldb_message *msg,
     862             :                                        struct drsuapi_DsReplicaLinkedAttribute **la_list,
     863             :                                        uint32_t *la_count,
     864             :                                        struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector)
     865             : {
     866           0 :         unsigned int i;
     867      651504 :         TALLOC_CTX *tmp_ctx = NULL;
     868      651504 :         uint64_t uSNChanged = ldb_msg_find_attr_as_uint64(msg, "uSNChanged", 0);
     869      651504 :         bool is_critical = ldb_msg_find_attr_as_bool(msg, "isCriticalSystemObject", false);
     870             : 
     871      651504 :         if (replica_flags & DRSUAPI_DRS_CRITICAL_ONLY) {
     872        7496 :                 if (!is_critical) {
     873           3 :                         return WERR_OK;
     874             :                 }
     875             :         }
     876             : 
     877      651501 :         if (uSNChanged <= highest_usn) {
     878           0 :                 return WERR_OK;
     879             :         }
     880             : 
     881      651501 :         tmp_ctx = talloc_new(mem_ctx);
     882      651501 :         if (tmp_ctx == NULL) {
     883           0 :                 return WERR_NOT_ENOUGH_MEMORY;
     884             :         }
     885             : 
     886    13829574 :         for (i=0; i<msg->num_elements; i++) {
     887    13178073 :                 struct ldb_message_element *el = &msg->elements[i];
     888           0 :                 const struct dsdb_attribute *sa;
     889           0 :                 unsigned int j;
     890             : 
     891    13178073 :                 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
     892             : 
     893    13178073 :                 if (!sa || sa->linkID == 0 || (sa->linkID & 1)) {
     894             :                         /* we only want forward links */
     895    13166196 :                         continue;
     896             :                 }
     897             : 
     898       11877 :                 if (el->num_values && !dsdb_dn_is_upgraded_link_val(&el->values[0])) {
     899             :                         /* its an old style link, it will have been
     900             :                          * sent in the main replication data */
     901         123 :                         continue;
     902             :                 }
     903             : 
     904       45907 :                 for (j=0; j<el->num_values; j++) {
     905           0 :                         struct dsdb_dn *dsdb_dn;
     906           0 :                         uint64_t local_usn;
     907           0 :                         uint64_t originating_usn;
     908           0 :                         NTSTATUS status, status2;
     909           0 :                         WERROR werr;
     910           0 :                         struct GUID originating_invocation_id;
     911             : 
     912       34153 :                         dsdb_dn = dsdb_dn_parse(tmp_ctx, sam_ctx, &el->values[j], sa->syntax->ldap_oid);
     913       34153 :                         if (dsdb_dn == NULL) {
     914           0 :                                 DEBUG(1,(__location__ ": Failed to parse DN for %s in %s\n",
     915             :                                          el->name, ldb_dn_get_linearized(msg->dn)));
     916           0 :                                 talloc_free(tmp_ctx);
     917           0 :                                 return WERR_DS_DRA_INTERNAL_ERROR;
     918             :                         }
     919             : 
     920       34153 :                         status = dsdb_get_extended_dn_uint64(dsdb_dn->dn, &local_usn, "RMD_LOCAL_USN");
     921       34153 :                         if (!NT_STATUS_IS_OK(status)) {
     922             :                                 /* this can happen for attributes
     923             :                                    given to us with old style meta
     924             :                                    data */
     925       11827 :                                 continue;
     926             :                         }
     927             : 
     928       34153 :                         if (local_usn > uSNChanged) {
     929           0 :                                 DEBUG(1,(__location__ ": uSNChanged less than RMD_LOCAL_USN for %s on %s\n",
     930             :                                          el->name, ldb_dn_get_linearized(msg->dn)));
     931           0 :                                 talloc_free(tmp_ctx);
     932           0 :                                 return WERR_DS_DRA_INTERNAL_ERROR;
     933             :                         }
     934             : 
     935       34153 :                         if (local_usn <= highest_usn) {
     936       11002 :                                 continue;
     937             :                         }
     938             : 
     939       23151 :                         status = dsdb_get_extended_dn_guid(dsdb_dn->dn,
     940             :                                                            &originating_invocation_id,
     941             :                                                            "RMD_INVOCID");
     942       23151 :                         status2 = dsdb_get_extended_dn_uint64(dsdb_dn->dn,
     943             :                                                               &originating_usn,
     944             :                                                               "RMD_ORIGINATING_USN");
     945             : 
     946       23151 :                         if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(status2)) {
     947       23151 :                                 if (udv_filter(uptodateness_vector,
     948             :                                                &originating_invocation_id,
     949             :                                                originating_usn)) {
     950         825 :                                         continue;
     951             :                                 }
     952             :                         }
     953             : 
     954       22326 :                         werr = get_nc_changes_add_la(mem_ctx, sam_ctx, schema,
     955             :                                                      sa, msg, dsdb_dn, la_list,
     956             :                                                      la_count, is_schema_nc);
     957       22326 :                         if (!W_ERROR_IS_OK(werr)) {
     958           0 :                                 talloc_free(tmp_ctx);
     959           0 :                                 return werr;
     960             :                         }
     961             :                 }
     962             :         }
     963             : 
     964      651501 :         talloc_free(tmp_ctx);
     965      651501 :         return WERR_OK;
     966             : }
     967             : 
     968             : /*
     969             :   fill in the cursors return based on the replUpToDateVector for the ncRoot_dn
     970             :  */
     971        6038 : static WERROR get_nc_changes_udv(struct ldb_context *sam_ctx,
     972             :                                  struct ldb_dn *ncRoot_dn,
     973             :                                  struct drsuapi_DsReplicaCursor2CtrEx *udv)
     974             : {
     975           0 :         int ret;
     976             : 
     977        6038 :         udv->version = 2;
     978        6038 :         udv->reserved1 = 0;
     979        6038 :         udv->reserved2 = 0;
     980             : 
     981        6038 :         ret = dsdb_load_udv_v2(sam_ctx, ncRoot_dn, udv, &udv->cursors, &udv->count);
     982        6038 :         if (ret != LDB_SUCCESS) {
     983           0 :                 DEBUG(0,(__location__ ": Failed to load UDV for %s - %s\n",
     984             :                          ldb_dn_get_linearized(ncRoot_dn), ldb_errstring(sam_ctx)));
     985           0 :                 return WERR_DS_DRA_INTERNAL_ERROR;
     986             :         }
     987             : 
     988        6038 :         return WERR_OK;
     989             : }
     990             : 
     991             : 
     992             : /* comparison function for linked attributes - see CompareLinks() in
     993             :  * MS-DRSR section 4.1.10.5.17 */
     994       71984 : static int linked_attribute_compare(const struct la_for_sorting *la1,
     995             :                                     const struct la_for_sorting *la2)
     996             : {
     997           0 :         int c;
     998       71984 :         c = memcmp(la1->source_guid,
     999       71984 :                    la2->source_guid, sizeof(la2->source_guid));
    1000       71984 :         if (c != 0) {
    1001       40363 :                 return c;
    1002             :         }
    1003             : 
    1004       31621 :         if (la1->link->attid != la2->link->attid) {
    1005        4071 :                 return la1->link->attid < la2->link->attid? -1:1;
    1006             :         }
    1007             : 
    1008       27550 :         if ((la1->link->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) !=
    1009       27550 :             (la2->link->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)) {
    1010         225 :                 return (la1->link->flags &
    1011         225 :                         DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)? 1:-1;
    1012             :         }
    1013             : 
    1014       27325 :         return memcmp(la1->target_guid,
    1015       27325 :                       la2->target_guid, sizeof(la2->target_guid));
    1016             : }
    1017             : 
    1018             : struct drsuapi_changed_objects {
    1019             :         struct ldb_dn *dn;
    1020             :         struct GUID guid;
    1021             :         uint64_t usn;
    1022             : };
    1023             : 
    1024             : 
    1025             : /*
    1026             :   sort the objects we send by tree order (Samba 4.5 emulation)
    1027             :  */
    1028       37892 : static int site_res_cmp_anc_order(struct drsuapi_changed_objects *m1,
    1029             :                                   struct drsuapi_changed_objects *m2)
    1030             : {
    1031       37892 :         return ldb_dn_compare(m2->dn, m1->dn);
    1032             : }
    1033             : 
    1034             : /*
    1035             :   sort the objects we send first by uSNChanged
    1036             :  */
    1037     6409315 : static int site_res_cmp_usn_order(struct drsuapi_changed_objects *m1,
    1038             :                                   struct drsuapi_changed_objects *m2)
    1039             : {
    1040     6409315 :         if (m1->usn == m2->usn) {
    1041           0 :                 return ldb_dn_compare(m2->dn, m1->dn);
    1042             :         }
    1043             : 
    1044     6409315 :         if (m1->usn < m2->usn) {
    1045     3158980 :                 return -1;
    1046             :         }
    1047             : 
    1048     3250335 :         return 1;
    1049             : }
    1050             : 
    1051             : 
    1052             : /*
    1053             :   handle a DRSUAPI_EXOP_FSMO_RID_ALLOC call
    1054             :  */
    1055          41 : static WERROR getncchanges_rid_alloc(struct drsuapi_bind_state *b_state,
    1056             :                                      TALLOC_CTX *mem_ctx,
    1057             :                                      struct drsuapi_DsGetNCChangesRequest10 *req10,
    1058             :                                      struct drsuapi_DsGetNCChangesCtr6 *ctr6,
    1059             :                                      struct ldb_dn **rid_manager_dn)
    1060             : {
    1061          41 :         struct ldb_dn *req_dn, *ntds_dn = NULL;
    1062           0 :         int ret;
    1063          41 :         struct ldb_context *ldb = b_state->sam_ctx;
    1064           0 :         struct ldb_result *ext_res;
    1065           0 :         struct dsdb_fsmo_extended_op *exop;
    1066           0 :         bool is_us;
    1067             : 
    1068             :         /*
    1069             :           steps:
    1070             :             - verify that the DN being asked for is the RID Manager DN
    1071             :             - verify that we are the RID Manager
    1072             :          */
    1073             : 
    1074             :         /* work out who is the RID Manager, also return to caller */
    1075          41 :         ret = samdb_rid_manager_dn(ldb, mem_ctx, rid_manager_dn);
    1076          41 :         if (ret != LDB_SUCCESS) {
    1077           0 :                 DEBUG(0, (__location__ ": Failed to find RID Manager object - %s\n", ldb_errstring(ldb)));
    1078           0 :                 return WERR_DS_DRA_INTERNAL_ERROR;
    1079             :         }
    1080             : 
    1081          41 :         ret = drs_ObjectIdentifier_to_dn_and_nc_root(mem_ctx,
    1082             :                                                      ldb,
    1083             :                                                      req10->naming_context,
    1084             :                                                      &req_dn,
    1085             :                                                      NULL);
    1086          41 :         if (ret != LDB_SUCCESS) {
    1087           0 :                 DBG_ERR("RID Alloc request for invalid DN %s: %s\n",
    1088             :                         drs_ObjectIdentifier_to_debug_string(mem_ctx, req10->naming_context),
    1089             :                         ldb_strerror(ret));
    1090           0 :                 ctr6->extended_ret = DRSUAPI_EXOP_ERR_MISMATCH;
    1091           0 :                 return WERR_OK;
    1092             :         }
    1093             : 
    1094          41 :         if (ldb_dn_compare(req_dn, *rid_manager_dn) != 0) {
    1095             :                 /* that isn't the RID Manager DN */
    1096           0 :                 DBG_ERR("RID Alloc request for wrong DN %s\n",
    1097             :                         drs_ObjectIdentifier_to_debug_string(mem_ctx,
    1098             :                                                              req10->naming_context));
    1099           0 :                 ctr6->extended_ret = DRSUAPI_EXOP_ERR_MISMATCH;
    1100           0 :                 return WERR_OK;
    1101             :         }
    1102             : 
    1103             :         /* TODO: make sure ntds_dn is a valid nTDSDSA object */
    1104          41 :         ret = dsdb_find_dn_by_guid(ldb, mem_ctx, &req10->destination_dsa_guid, 0, &ntds_dn);
    1105          41 :         if (ret != LDB_SUCCESS) {
    1106           0 :                 DEBUG(0, (__location__ ": Unable to find NTDS object for guid %s - %s\n",
    1107             :                           GUID_string(mem_ctx, &req10->destination_dsa_guid), ldb_errstring(ldb)));
    1108           0 :                 ctr6->extended_ret = DRSUAPI_EXOP_ERR_UNKNOWN_CALLER;
    1109           0 :                 return WERR_OK;
    1110             :         }
    1111             : 
    1112             :         /* find the DN of the RID Manager */
    1113          41 :         ret = samdb_reference_dn_is_our_ntdsa(ldb, *rid_manager_dn, "fSMORoleOwner", &is_us);
    1114          41 :         if (ret != LDB_SUCCESS) {
    1115           0 :                 DEBUG(0,("Failed to find fSMORoleOwner in RID Manager object\n"));
    1116           0 :                 ctr6->extended_ret = DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER;
    1117           0 :                 return WERR_DS_DRA_INTERNAL_ERROR;
    1118             :         }
    1119             : 
    1120          41 :         if (!is_us) {
    1121             :                 /* we're not the RID Manager - go away */
    1122           4 :                 DEBUG(0,(__location__ ": RID Alloc request when not RID Manager\n"));
    1123           4 :                 ctr6->extended_ret = DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER;
    1124           4 :                 return WERR_OK;
    1125             :         }
    1126             : 
    1127          37 :         exop = talloc(mem_ctx, struct dsdb_fsmo_extended_op);
    1128          37 :         W_ERROR_HAVE_NO_MEMORY(exop);
    1129             : 
    1130          37 :         exop->fsmo_info = req10->fsmo_info;
    1131          37 :         exop->destination_dsa_guid = req10->destination_dsa_guid;
    1132             : 
    1133          37 :         ret = ldb_transaction_start(ldb);
    1134          37 :         if (ret != LDB_SUCCESS) {
    1135           0 :                 DEBUG(0,(__location__ ": Failed transaction start - %s\n",
    1136             :                          ldb_errstring(ldb)));
    1137           0 :                 return WERR_DS_DRA_INTERNAL_ERROR;
    1138             :         }
    1139             : 
    1140          37 :         ret = ldb_extended(ldb, DSDB_EXTENDED_ALLOCATE_RID_POOL, exop, &ext_res);
    1141          37 :         if (ret != LDB_SUCCESS) {
    1142           0 :                 DEBUG(0,(__location__ ": Failed extended allocation RID pool operation - %s\n",
    1143             :                          ldb_errstring(ldb)));
    1144           0 :                 ldb_transaction_cancel(ldb);
    1145           0 :                 return WERR_DS_DRA_INTERNAL_ERROR;
    1146             :         }
    1147             : 
    1148          37 :         ret = ldb_transaction_commit(ldb);
    1149          37 :         if (ret != LDB_SUCCESS) {
    1150           0 :                 DEBUG(0,(__location__ ": Failed transaction commit - %s\n",
    1151             :                          ldb_errstring(ldb)));
    1152           0 :                 return WERR_DS_DRA_INTERNAL_ERROR;
    1153             :         }
    1154             : 
    1155          37 :         talloc_free(ext_res);
    1156             : 
    1157          37 :         DEBUG(2,("Allocated RID pool for server %s\n",
    1158             :                  GUID_string(mem_ctx, &req10->destination_dsa_guid)));
    1159             : 
    1160          37 :         ctr6->extended_ret = DRSUAPI_EXOP_ERR_SUCCESS;
    1161             : 
    1162          37 :         return WERR_OK;
    1163             : }
    1164             : 
    1165             : /*
    1166             :   handle a DRSUAPI_EXOP_REPL_SECRET call
    1167             :  */
    1168        4403 : static WERROR getncchanges_repl_secret(struct drsuapi_bind_state *b_state,
    1169             :                                        TALLOC_CTX *mem_ctx,
    1170             :                                        struct drsuapi_DsGetNCChangesRequest10 *req10,
    1171             :                                        struct dom_sid *user_sid,
    1172             :                                        struct drsuapi_DsGetNCChangesCtr6 *ctr6,
    1173             :                                        bool has_get_all_changes,
    1174             :                                        struct ldb_dn **machine_dn)
    1175             : {
    1176        4403 :         struct drsuapi_DsReplicaObjectIdentifier *ncRoot = req10->naming_context;
    1177        4403 :         struct ldb_dn *obj_dn = NULL;
    1178        4403 :         struct ldb_message *ntds_msg = NULL;
    1179        4403 :         struct ldb_dn *ntds_dn = NULL, *server_dn = NULL;
    1180           0 :         struct ldb_dn *rodc_dn, *krbtgt_link_dn;
    1181           0 :         int ret;
    1182        4403 :         const char *ntds_attrs[] = { NULL };
    1183        4403 :         const char *rodc_attrs[] = { "msDS-KrbTgtLink",
    1184             :                                      "msDS-NeverRevealGroup",
    1185             :                                      "msDS-RevealOnDemandGroup",
    1186             :                                      "userAccountControl",
    1187             :                                      NULL };
    1188        4403 :         const char *obj_attrs[] = { "tokenGroups", "objectSid", "UserAccountControl", "msDS-KrbTgtLinkBL", NULL };
    1189        4403 :         struct ldb_result *rodc_res = NULL, *obj_res = NULL;
    1190           0 :         WERROR werr;
    1191           0 :         struct GUID_txt_buf guid_buf;
    1192             : 
    1193        4403 :         DEBUG(3,(__location__ ": DRSUAPI_EXOP_REPL_SECRET extended op on %s\n",
    1194             :                  drs_ObjectIdentifier_to_debug_string(mem_ctx, ncRoot)));
    1195             : 
    1196             :         /*
    1197             :          * we need to work out if we will allow this DC to
    1198             :          * replicate the secrets for this object
    1199             :          *
    1200             :          * see 4.1.10.5.14 GetRevealSecretsPolicyForUser for details
    1201             :          * of this function
    1202             :          */
    1203             : 
    1204        4403 :         if (b_state->sam_ctx_system == NULL) {
    1205             :                 /* this operation needs system level access */
    1206          12 :                 ctr6->extended_ret = DRSUAPI_EXOP_ERR_ACCESS_DENIED;
    1207          12 :                 return WERR_DS_DRA_ACCESS_DENIED;
    1208             :         }
    1209             : 
    1210             :         /*
    1211             :          * Before we accept or deny, fetch the machine DN for the destination
    1212             :          * DSA GUID.
    1213             :          *
    1214             :          * If we are the RODC, we will check that this matches the SID.
    1215             :          */
    1216        4391 :         ret = samdb_get_ntds_obj_by_guid(mem_ctx,
    1217             :                                          b_state->sam_ctx_system,
    1218        4391 :                                          &req10->destination_dsa_guid,
    1219             :                                          ntds_attrs,
    1220             :                                          &ntds_msg);
    1221        4391 :         if (ret != LDB_SUCCESS) {
    1222           9 :                 goto dest_dsa_error;
    1223             :         }
    1224             : 
    1225        4382 :         ntds_dn = ntds_msg->dn;
    1226             : 
    1227        4382 :         server_dn = ldb_dn_get_parent(mem_ctx, ntds_dn);
    1228        4382 :         if (server_dn == NULL) {
    1229           0 :                 goto failed;
    1230             :         }
    1231             : 
    1232        4382 :         ret = samdb_reference_dn(b_state->sam_ctx_system, mem_ctx, server_dn,
    1233             :                                  "serverReference", machine_dn);
    1234             : 
    1235        4382 :         if (ret != LDB_SUCCESS) {
    1236           0 :                 goto dest_dsa_error;
    1237             :         }
    1238             : 
    1239             :         /*
    1240             :          * In MS-DRSR.pdf 5.99 IsGetNCChangesPermissionGranted
    1241             :          *
    1242             :          * The pseudo code indicate
    1243             :          * revealsecrets = true
    1244             :          * if IsRevealSecretRequest(msgIn) then
    1245             :          *   if AccessCheckCAR(ncRoot, Ds-Replication-Get-Changes-All) = false
    1246             :          *   then
    1247             :          *     if (msgIn.ulExtendedOp = EXOP_REPL_SECRETS) then
    1248             :          *     <... check if this account is ok to be replicated on this DC ...>
    1249             :          *     <... and if not reveal secrets = no ...>
    1250             :          *     else
    1251             :          *       reveal secrets = false
    1252             :          *     endif
    1253             :          *   endif
    1254             :          * endif
    1255             :          *
    1256             :          * Which basically means that if you have GET_ALL_CHANGES rights (~== RWDC)
    1257             :          * then you can do EXOP_REPL_SECRETS
    1258             :          */
    1259        4382 :         ret = drs_ObjectIdentifier_to_dn_and_nc_root(mem_ctx,
    1260             :                                                         b_state->sam_ctx_system,
    1261             :                                                         ncRoot,
    1262             :                                                         &obj_dn,
    1263             :                                                         NULL);
    1264        4382 :         if (ret != LDB_SUCCESS) {
    1265           0 :                 DBG_ERR("RevealSecretRequest for invalid DN %s\n",
    1266             :                          drs_ObjectIdentifier_to_debug_string(mem_ctx, ncRoot));
    1267           0 :                 goto failed;
    1268             :         }
    1269             : 
    1270        4382 :         if (!ldb_dn_validate(obj_dn)) goto failed;
    1271             : 
    1272        4382 :         if (has_get_all_changes) {
    1273        3043 :                 goto allowed;
    1274             :         }
    1275             : 
    1276        1339 :         rodc_dn = ldb_dn_new_fmt(mem_ctx, b_state->sam_ctx_system, "<SID=%s>",
    1277             :                                  dom_sid_string(mem_ctx, user_sid));
    1278        1339 :         if (!ldb_dn_validate(rodc_dn)) goto failed;
    1279             : 
    1280             :         /*
    1281             :          * do the two searches we need
    1282             :          * We need DSDB_SEARCH_SHOW_EXTENDED_DN as we get a SID lists
    1283             :          * out of the extended DNs
    1284             :          */
    1285        1339 :         ret = dsdb_search_dn(b_state->sam_ctx_system, mem_ctx, &rodc_res, rodc_dn, rodc_attrs,
    1286             :                              DSDB_SEARCH_SHOW_EXTENDED_DN);
    1287        1339 :         if (ret != LDB_SUCCESS || rodc_res->count != 1) goto failed;
    1288             : 
    1289        1339 :         ret = dsdb_search_dn(b_state->sam_ctx_system, mem_ctx, &obj_res, obj_dn, obj_attrs, 0);
    1290        1339 :         if (ret != LDB_SUCCESS || obj_res->count != 1) goto failed;
    1291             : 
    1292             :         /*
    1293             :          * Must be an RODC account at this point, verify machine DN matches the
    1294             :          * SID account
    1295             :          */
    1296        1339 :         if (ldb_dn_compare(rodc_res->msgs[0]->dn, *machine_dn) != 0) {
    1297           2 :                 goto denied;
    1298             :         }
    1299             : 
    1300             :         /* an RODC is allowed to get its own krbtgt account secrets */
    1301        1337 :         krbtgt_link_dn = samdb_result_dn(b_state->sam_ctx_system, mem_ctx,
    1302        1337 :                                          rodc_res->msgs[0], "msDS-KrbTgtLink", NULL);
    1303        2674 :         if (krbtgt_link_dn != NULL &&
    1304        1337 :             ldb_dn_compare(obj_dn, krbtgt_link_dn) == 0) {
    1305           5 :                 goto allowed;
    1306             :         }
    1307             : 
    1308        1332 :         werr = samdb_confirm_rodc_allowed_to_repl_to(b_state->sam_ctx_system,
    1309             :                                                      user_sid,
    1310        1332 :                                                      rodc_res->msgs[0],
    1311        1332 :                                                      obj_res->msgs[0]);
    1312             : 
    1313        1332 :         if (W_ERROR_IS_OK(werr)) {
    1314          20 :                 goto allowed;
    1315             :         }
    1316             : 
    1317             :         /* default deny */
    1318        1312 : denied:
    1319        1314 :         DEBUG(2,(__location__ ": Denied single object with secret replication for %s by RODC %s\n",
    1320             :                  ldb_dn_get_linearized(obj_dn), ldb_dn_get_linearized(rodc_res->msgs[0]->dn)));
    1321        1314 :         ctr6->extended_ret = DRSUAPI_EXOP_ERR_NONE;
    1322        1314 :         return WERR_DS_DRA_SECRETS_DENIED;
    1323             : 
    1324        3068 : allowed:
    1325        3068 :         DEBUG(2,(__location__ ": Allowed single object with secret replication for %s by %s %s\n",
    1326             :                  ldb_dn_get_linearized(obj_dn), has_get_all_changes?"RWDC":"RODC",
    1327             :                  ldb_dn_get_linearized(*machine_dn)));
    1328        3068 :         ctr6->extended_ret = DRSUAPI_EXOP_ERR_SUCCESS;
    1329        3068 :         req10->highwatermark.highest_usn = 0;
    1330        3068 :         return WERR_OK;
    1331             : 
    1332           0 : failed:
    1333           0 :         DEBUG(2,(__location__ ": Failed single secret replication for %s by RODC %s\n",
    1334             :                  ldb_dn_get_linearized(obj_dn), dom_sid_string(mem_ctx, user_sid)));
    1335           0 :         ctr6->extended_ret = DRSUAPI_EXOP_ERR_NONE;
    1336           0 :         return WERR_DS_DRA_BAD_DN;
    1337             : 
    1338           9 : dest_dsa_error:
    1339           9 :         DBG_WARNING("Failed secret replication for %s by RODC %s as dest_dsa_guid %s is invalid\n",
    1340             :                     ldb_dn_get_linearized(obj_dn),
    1341             :                     dom_sid_string(mem_ctx, user_sid),
    1342             :                     GUID_buf_string(&req10->destination_dsa_guid,
    1343             :                                     &guid_buf));
    1344           9 :         ctr6->extended_ret = DRSUAPI_EXOP_ERR_NONE;
    1345           9 :         return WERR_DS_DRA_DB_ERROR;
    1346             : }
    1347             : 
    1348             : /*
    1349             :   handle a DRSUAPI_EXOP_REPL_OBJ call
    1350             :  */
    1351         167 : static WERROR getncchanges_repl_obj(struct drsuapi_bind_state *b_state,
    1352             :                                     TALLOC_CTX *mem_ctx,
    1353             :                                     struct drsuapi_DsGetNCChangesRequest10 *req10,
    1354             :                                     struct dom_sid *user_sid,
    1355             :                                     struct drsuapi_DsGetNCChangesCtr6 *ctr6)
    1356             : {
    1357         167 :         struct drsuapi_DsReplicaObjectIdentifier *ncRoot = req10->naming_context;
    1358             : 
    1359         167 :         DEBUG(3,(__location__ ": DRSUAPI_EXOP_REPL_OBJ extended op on %s\n",
    1360             :                  drs_ObjectIdentifier_to_debug_string(mem_ctx, ncRoot)));
    1361             : 
    1362         167 :         ctr6->extended_ret = DRSUAPI_EXOP_ERR_SUCCESS;
    1363         167 :         return WERR_OK;
    1364             : }
    1365             : 
    1366             : 
    1367             : /*
    1368             :   handle DRSUAPI_EXOP_FSMO_REQ_ROLE,
    1369             :   DRSUAPI_EXOP_FSMO_RID_REQ_ROLE,
    1370             :   and DRSUAPI_EXOP_FSMO_REQ_PDC calls
    1371             :  */
    1372          25 : static WERROR getncchanges_change_master(struct drsuapi_bind_state *b_state,
    1373             :                                          TALLOC_CTX *mem_ctx,
    1374             :                                          struct drsuapi_DsGetNCChangesRequest10 *req10,
    1375             :                                          struct drsuapi_DsGetNCChangesCtr6 *ctr6)
    1376             : {
    1377           0 :         struct ldb_dn *req_dn, *ntds_dn;
    1378           0 :         int ret;
    1379           0 :         unsigned int i;
    1380          25 :         struct ldb_context *ldb = b_state->sam_ctx;
    1381           0 :         struct ldb_message *msg;
    1382           0 :         bool is_us;
    1383             : 
    1384             :         /*
    1385             :           steps:
    1386             :             - verify that the client dn exists
    1387             :             - verify that we are the current master
    1388             :          */
    1389             : 
    1390          25 :         ret = drs_ObjectIdentifier_to_dn_and_nc_root(mem_ctx, ldb, req10->naming_context,
    1391             :                                                      &req_dn, NULL);
    1392          25 :         if (ret != LDB_SUCCESS) {
    1393             :                 /* that is not a valid dn */
    1394           0 :                 DBG_ERR("FSMO role transfer request for invalid DN %s: %s\n",
    1395             :                         drs_ObjectIdentifier_to_debug_string(mem_ctx, req10->naming_context),
    1396             :                         ldb_strerror(ret));
    1397           0 :                 ctr6->extended_ret = DRSUAPI_EXOP_ERR_MISMATCH;
    1398           0 :                 return WERR_OK;
    1399             :         }
    1400             : 
    1401             :         /* find the DN of the current role owner */
    1402          25 :         ret = samdb_reference_dn_is_our_ntdsa(ldb, req_dn, "fSMORoleOwner", &is_us);
    1403          25 :         if (ret != LDB_SUCCESS) {
    1404           0 :                 DEBUG(0,("Failed to find fSMORoleOwner in RID Manager object\n"));
    1405           0 :                 ctr6->extended_ret = DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER;
    1406           0 :                 return WERR_DS_DRA_INTERNAL_ERROR;
    1407             :         }
    1408             : 
    1409          25 :         if (!is_us) {
    1410             :                 /* we're not the RID Manager or role owner - go away */
    1411           2 :                 DEBUG(0,(__location__ ": FSMO role or RID manager transfer owner request when not role owner\n"));
    1412           2 :                 ctr6->extended_ret = DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER;
    1413           2 :                 return WERR_OK;
    1414             :         }
    1415             : 
    1416             :         /* change the current master */
    1417          23 :         msg = ldb_msg_new(ldb);
    1418          23 :         W_ERROR_HAVE_NO_MEMORY(msg);
    1419          23 :         ret = drs_ObjectIdentifier_to_dn_and_nc_root(msg, ldb, req10->naming_context,
    1420             :                                                      &msg->dn, NULL);
    1421          23 :         if (ret != LDB_SUCCESS) {
    1422             :                 /* that is not a valid dn */
    1423           0 :                 DBG_ERR("FSMO role transfer request for invalid DN %s: %s\n",
    1424             :                         drs_ObjectIdentifier_to_debug_string(mem_ctx, req10->naming_context),
    1425             :                         ldb_strerror(ret));
    1426           0 :                 ctr6->extended_ret = DRSUAPI_EXOP_ERR_MISMATCH;
    1427           0 :                 return WERR_OK;
    1428             :         }
    1429             : 
    1430             :         /* TODO: make sure ntds_dn is a valid nTDSDSA object */
    1431          23 :         ret = dsdb_find_dn_by_guid(ldb, msg, &req10->destination_dsa_guid, 0, &ntds_dn);
    1432          23 :         if (ret != LDB_SUCCESS) {
    1433           0 :                 DEBUG(0, (__location__ ": Unable to find NTDS object for guid %s - %s\n",
    1434             :                           GUID_string(mem_ctx, &req10->destination_dsa_guid), ldb_errstring(ldb)));
    1435           0 :                 talloc_free(msg);
    1436           0 :                 ctr6->extended_ret = DRSUAPI_EXOP_ERR_UNKNOWN_CALLER;
    1437           0 :                 return WERR_OK;
    1438             :         }
    1439             : 
    1440          23 :         ret = ldb_msg_add_string(msg, "fSMORoleOwner", ldb_dn_get_linearized(ntds_dn));
    1441          23 :         if (ret != 0) {
    1442           0 :                 talloc_free(msg);
    1443           0 :                 return WERR_DS_DRA_INTERNAL_ERROR;
    1444             :         }
    1445             : 
    1446          46 :         for (i=0;i<msg->num_elements;i++) {
    1447          23 :                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
    1448             :         }
    1449             : 
    1450          23 :         ret = ldb_transaction_start(ldb);
    1451          23 :         if (ret != LDB_SUCCESS) {
    1452           0 :                 DEBUG(0,(__location__ ": Failed transaction start - %s\n",
    1453             :                          ldb_errstring(ldb)));
    1454           0 :                 return WERR_DS_DRA_INTERNAL_ERROR;
    1455             :         }
    1456             : 
    1457          23 :         ret = ldb_modify(ldb, msg);
    1458          23 :         if (ret != LDB_SUCCESS) {
    1459           0 :                 DEBUG(0,(__location__ ": Failed to change current owner - %s\n",
    1460             :                          ldb_errstring(ldb)));
    1461           0 :                 ldb_transaction_cancel(ldb);
    1462           0 :                 return WERR_DS_DRA_INTERNAL_ERROR;
    1463             :         }
    1464             : 
    1465          23 :         ret = ldb_transaction_commit(ldb);
    1466          23 :         if (ret != LDB_SUCCESS) {
    1467           0 :                 DEBUG(0,(__location__ ": Failed transaction commit - %s\n",
    1468             :                          ldb_errstring(ldb)));
    1469           0 :                 return WERR_DS_DRA_INTERNAL_ERROR;
    1470             :         }
    1471             : 
    1472          23 :         ctr6->extended_ret = DRSUAPI_EXOP_ERR_SUCCESS;
    1473             : 
    1474          23 :         return WERR_OK;
    1475             : }
    1476             : 
    1477             : /*
    1478             :   see if this getncchanges request includes a request to reveal secret information
    1479             :  */
    1480        9537 : static WERROR dcesrv_drsuapi_is_reveal_secrets_request(struct drsuapi_bind_state *b_state,
    1481             :                                                        struct drsuapi_DsGetNCChangesRequest10 *req10,
    1482             :                                                        struct dsdb_schema_prefixmap *pfm_remote,
    1483             :                                                        bool *is_secret_request)
    1484             : {
    1485           0 :         enum drsuapi_DsExtendedOperation exop;
    1486           0 :         uint32_t i;
    1487           0 :         struct dsdb_schema *schema;
    1488           0 :         struct dsdb_syntax_ctx syntax_ctx;
    1489             : 
    1490        9537 :         *is_secret_request = true;
    1491             : 
    1492        9537 :         exop = req10->extended_op;
    1493             : 
    1494        9537 :         switch (exop) {
    1495          66 :         case DRSUAPI_EXOP_FSMO_REQ_ROLE:
    1496             :         case DRSUAPI_EXOP_FSMO_RID_ALLOC:
    1497             :         case DRSUAPI_EXOP_FSMO_RID_REQ_ROLE:
    1498             :         case DRSUAPI_EXOP_FSMO_REQ_PDC:
    1499             :         case DRSUAPI_EXOP_FSMO_ABANDON_ROLE:
    1500             :                 /* FSMO exops can reveal secrets */
    1501          66 :                 *is_secret_request = true;
    1502          66 :                 return WERR_OK;
    1503        9471 :         case DRSUAPI_EXOP_REPL_SECRET:
    1504             :         case DRSUAPI_EXOP_REPL_OBJ:
    1505             :         case DRSUAPI_EXOP_NONE:
    1506        9471 :                 break;
    1507             :         }
    1508             : 
    1509        9471 :         if (req10->replica_flags & DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING) {
    1510         865 :                 *is_secret_request = false;
    1511         865 :                 return WERR_OK;
    1512             :         }
    1513             : 
    1514        8606 :         if (exop == DRSUAPI_EXOP_REPL_SECRET ||
    1515        4199 :             req10->partial_attribute_set == NULL) {
    1516             :                 /* they want secrets */
    1517        8589 :                 *is_secret_request = true;
    1518        8589 :                 return WERR_OK;
    1519             :         }
    1520             : 
    1521          17 :         schema = dsdb_get_schema(b_state->sam_ctx, NULL);
    1522          17 :         dsdb_syntax_ctx_init(&syntax_ctx, b_state->sam_ctx, schema);
    1523          17 :         syntax_ctx.pfm_remote = pfm_remote;
    1524             : 
    1525             :         /* check the attributes they asked for */
    1526          28 :         for (i=0; i<req10->partial_attribute_set->num_attids; i++) {
    1527           0 :                 const struct dsdb_attribute *sa;
    1528          17 :                 WERROR werr = getncchanges_attid_remote_to_local(schema,
    1529             :                                                                  &syntax_ctx,
    1530          17 :                                                                  req10->partial_attribute_set->attids[i],
    1531             :                                                                  NULL,
    1532             :                                                                  &sa);
    1533             : 
    1534          17 :                 if (!W_ERROR_IS_OK(werr)) {
    1535           0 :                         DEBUG(0,(__location__": attid 0x%08X not found: %s\n",
    1536             :                                  req10->partial_attribute_set->attids[i], win_errstr(werr)));
    1537           6 :                         return werr;
    1538             :                 }
    1539             : 
    1540          17 :                 if (!dsdb_attr_in_rodc_fas(sa)) {
    1541           6 :                         *is_secret_request = true;
    1542           6 :                         return WERR_OK;
    1543             :                 }
    1544             :         }
    1545             : 
    1546          11 :         if (req10->partial_attribute_set_ex) {
    1547             :                 /* check the extended attributes they asked for */
    1548           3 :                 for (i=0; i<req10->partial_attribute_set_ex->num_attids; i++) {
    1549           0 :                         const struct dsdb_attribute *sa;
    1550           3 :                         WERROR werr = getncchanges_attid_remote_to_local(schema,
    1551             :                                                                          &syntax_ctx,
    1552           3 :                                                                          req10->partial_attribute_set_ex->attids[i],
    1553             :                                                                          NULL,
    1554             :                                                                          &sa);
    1555             : 
    1556           3 :                         if (!W_ERROR_IS_OK(werr)) {
    1557           0 :                                 DEBUG(0,(__location__": attid 0x%08X not found: %s\n",
    1558             :                                          req10->partial_attribute_set_ex->attids[i], win_errstr(werr)));
    1559           3 :                                 return werr;
    1560             :                         }
    1561             : 
    1562           3 :                         if (!dsdb_attr_in_rodc_fas(sa)) {
    1563           3 :                                 *is_secret_request = true;
    1564           3 :                                 return WERR_OK;
    1565             :                         }
    1566             :                 }
    1567             :         }
    1568             : 
    1569           8 :         *is_secret_request = false;
    1570           8 :         return WERR_OK;
    1571             : }
    1572             : 
    1573             : /*
    1574             :   see if this getncchanges request is only for attributes in the GC
    1575             :   partial attribute set
    1576             :  */
    1577        9549 : static WERROR dcesrv_drsuapi_is_gc_pas_request(struct drsuapi_bind_state *b_state,
    1578             :                                                struct drsuapi_DsGetNCChangesRequest10 *req10,
    1579             :                                                struct dsdb_schema_prefixmap *pfm_remote,
    1580             :                                                bool *is_gc_pas_request)
    1581             : {
    1582           0 :         enum drsuapi_DsExtendedOperation exop;
    1583           0 :         uint32_t i;
    1584           0 :         struct dsdb_schema *schema;
    1585           0 :         struct dsdb_syntax_ctx syntax_ctx;
    1586             : 
    1587        9549 :         exop = req10->extended_op;
    1588             : 
    1589        9549 :         switch (exop) {
    1590        4473 :         case DRSUAPI_EXOP_FSMO_REQ_ROLE:
    1591             :         case DRSUAPI_EXOP_FSMO_RID_ALLOC:
    1592             :         case DRSUAPI_EXOP_FSMO_RID_REQ_ROLE:
    1593             :         case DRSUAPI_EXOP_FSMO_REQ_PDC:
    1594             :         case DRSUAPI_EXOP_FSMO_ABANDON_ROLE:
    1595             :         case DRSUAPI_EXOP_REPL_SECRET:
    1596        4473 :                 *is_gc_pas_request = false;
    1597        4473 :                 return WERR_OK;
    1598        5076 :         case DRSUAPI_EXOP_REPL_OBJ:
    1599             :         case DRSUAPI_EXOP_NONE:
    1600        5076 :                 break;
    1601             :         }
    1602             : 
    1603        5076 :         if (req10->partial_attribute_set == NULL) {
    1604             :                 /* they want it all */
    1605        4458 :                 *is_gc_pas_request = false;
    1606        4458 :                 return WERR_OK;
    1607             :         }
    1608             : 
    1609         618 :         schema = dsdb_get_schema(b_state->sam_ctx, NULL);
    1610         618 :         dsdb_syntax_ctx_init(&syntax_ctx, b_state->sam_ctx, schema);
    1611         618 :         syntax_ctx.pfm_remote = pfm_remote;
    1612             : 
    1613             :         /* check the attributes they asked for */
    1614        1227 :         for (i=0; i<req10->partial_attribute_set->num_attids; i++) {
    1615           0 :                 const struct dsdb_attribute *sa;
    1616        1207 :                 WERROR werr = getncchanges_attid_remote_to_local(schema,
    1617             :                                                                  &syntax_ctx,
    1618        1207 :                                                                  req10->partial_attribute_set->attids[i],
    1619             :                                                                  NULL,
    1620             :                                                                  &sa);
    1621             : 
    1622        1207 :                 if (!W_ERROR_IS_OK(werr)) {
    1623           3 :                         DEBUG(0,(__location__": attid 0x%08X not found: %s\n",
    1624             :                                  req10->partial_attribute_set->attids[i], win_errstr(werr)));
    1625         598 :                         return werr;
    1626             :                 }
    1627             : 
    1628        1204 :                 if (!sa->isMemberOfPartialAttributeSet) {
    1629         595 :                         *is_gc_pas_request = false;
    1630         595 :                         return WERR_OK;
    1631             :                 }
    1632             :         }
    1633             : 
    1634          20 :         if (req10->partial_attribute_set_ex) {
    1635             :                 /* check the extended attributes they asked for */
    1636           3 :                 for (i=0; i<req10->partial_attribute_set_ex->num_attids; i++) {
    1637           0 :                         const struct dsdb_attribute *sa;
    1638           3 :                         WERROR werr = getncchanges_attid_remote_to_local(schema,
    1639             :                                                                          &syntax_ctx,
    1640           3 :                                                                          req10->partial_attribute_set_ex->attids[i],
    1641             :                                                                          NULL,
    1642             :                                                                          &sa);
    1643             : 
    1644           3 :                         if (!W_ERROR_IS_OK(werr)) {
    1645           0 :                                 DEBUG(0,(__location__": attid 0x%08X not found: %s\n",
    1646             :                                          req10->partial_attribute_set_ex->attids[i], win_errstr(werr)));
    1647           3 :                                 return werr;
    1648             :                         }
    1649             : 
    1650           3 :                         if (!sa->isMemberOfPartialAttributeSet) {
    1651           3 :                                 *is_gc_pas_request = false;
    1652           3 :                                 return WERR_OK;
    1653             :                         }
    1654             :                 }
    1655             :         }
    1656             : 
    1657          17 :         *is_gc_pas_request = true;
    1658          17 :         return WERR_OK;
    1659             : }
    1660             : 
    1661             : 
    1662             : /*
    1663             :   map from req8 to req10
    1664             :  */
    1665             : static struct drsuapi_DsGetNCChangesRequest10 *
    1666        3483 : getncchanges_map_req8(TALLOC_CTX *mem_ctx,
    1667             :                       struct drsuapi_DsGetNCChangesRequest8 *req8)
    1668             : {
    1669        3483 :         struct drsuapi_DsGetNCChangesRequest10 *req10 = talloc_zero(mem_ctx,
    1670             :                                                                     struct drsuapi_DsGetNCChangesRequest10);
    1671        3483 :         if (req10 == NULL) {
    1672           0 :                 return NULL;
    1673             :         }
    1674             : 
    1675        3483 :         req10->destination_dsa_guid = req8->destination_dsa_guid;
    1676        3483 :         req10->source_dsa_invocation_id = req8->source_dsa_invocation_id;
    1677        3483 :         req10->naming_context = req8->naming_context;
    1678        3483 :         req10->highwatermark = req8->highwatermark;
    1679        3483 :         req10->uptodateness_vector = req8->uptodateness_vector;
    1680        3483 :         req10->replica_flags = req8->replica_flags;
    1681        3483 :         req10->max_object_count = req8->max_object_count;
    1682        3483 :         req10->max_ndr_size = req8->max_ndr_size;
    1683        3483 :         req10->extended_op = req8->extended_op;
    1684        3483 :         req10->fsmo_info = req8->fsmo_info;
    1685        3483 :         req10->partial_attribute_set = req8->partial_attribute_set;
    1686        3483 :         req10->partial_attribute_set_ex = req8->partial_attribute_set_ex;
    1687        3483 :         req10->mapping_ctr = req8->mapping_ctr;
    1688             : 
    1689        3483 :         return req10;
    1690             : }
    1691             : 
    1692             : static const char *collect_objects_attrs[] = { "uSNChanged",
    1693             :                                                "objectGUID" ,
    1694             :                                                NULL };
    1695             : 
    1696             : /**
    1697             :  * Collects object for normal replication cycle.
    1698             :  */
    1699        6001 : static WERROR getncchanges_collect_objects(struct drsuapi_bind_state *b_state,
    1700             :                                            TALLOC_CTX *mem_ctx,
    1701             :                                            struct drsuapi_getncchanges_state *getnc_state,
    1702             :                                            struct drsuapi_DsGetNCChangesRequest10 *req10,
    1703             :                                            struct ldb_dn *search_dn,
    1704             :                                            const char *extra_filter,
    1705             :                                            struct ldb_result **search_res)
    1706             : {
    1707           0 :         int ret;
    1708           0 :         char* search_filter;
    1709        6001 :         enum ldb_scope scope = LDB_SCOPE_SUBTREE;
    1710        6001 :         bool critical_only = false;
    1711             : 
    1712        6001 :         if (req10->replica_flags & DRSUAPI_DRS_CRITICAL_ONLY) {
    1713         135 :                 critical_only = true;
    1714             :         }
    1715             : 
    1716        6001 :         if (req10->extended_op == DRSUAPI_EXOP_REPL_OBJ ||
    1717        5834 :             req10->extended_op == DRSUAPI_EXOP_REPL_SECRET) {
    1718        3235 :                 scope = LDB_SCOPE_BASE;
    1719        3235 :                 critical_only = false;
    1720             :         }
    1721             : 
    1722             :         /* Construct response. */
    1723        6001 :         search_filter = talloc_asprintf(mem_ctx,
    1724             :                                         "(uSNChanged>=%llu)",
    1725        6001 :                                         (unsigned long long)(getnc_state->min_usn+1));
    1726             : 
    1727        6001 :         if (extra_filter) {
    1728           0 :                 search_filter = talloc_asprintf(mem_ctx, "(&%s(%s))", search_filter, extra_filter);
    1729             :         }
    1730             : 
    1731        6001 :         if (critical_only) {
    1732         132 :                 search_filter = talloc_asprintf(mem_ctx,
    1733             :                                                 "(&%s(isCriticalSystemObject=TRUE))",
    1734             :                                                 search_filter);
    1735             :         }
    1736             : 
    1737        6001 :         if (req10->replica_flags & DRSUAPI_DRS_ASYNC_REP) {
    1738           0 :                 scope = LDB_SCOPE_BASE;
    1739             :         }
    1740             : 
    1741        6001 :         if (!search_dn) {
    1742        6001 :                 search_dn = getnc_state->ncRoot_dn;
    1743             :         }
    1744             : 
    1745        6001 :         DEBUG(2,(__location__ ": getncchanges on %s using filter %s\n",
    1746             :                  ldb_dn_get_linearized(getnc_state->ncRoot_dn), search_filter));
    1747        6001 :         ret = drsuapi_search_with_extended_dn(b_state->sam_ctx, getnc_state, search_res,
    1748             :                                               search_dn, scope,
    1749             :                                               collect_objects_attrs,
    1750             :                                               search_filter);
    1751        6001 :         if (ret != LDB_SUCCESS) {
    1752           0 :                 return WERR_DS_DRA_INTERNAL_ERROR;
    1753             :         }
    1754             : 
    1755        6001 :         return WERR_OK;
    1756             : }
    1757             : 
    1758             : /**
    1759             :  * Collects object for normal replication cycle.
    1760             :  */
    1761        3295 : static WERROR getncchanges_collect_objects_exop(struct drsuapi_bind_state *b_state,
    1762             :                                                 TALLOC_CTX *mem_ctx,
    1763             :                                                 struct drsuapi_getncchanges_state *getnc_state,
    1764             :                                                 struct drsuapi_DsGetNCChangesRequest10 *req10,
    1765             :                                                 struct drsuapi_DsGetNCChangesCtr6 *ctr6,
    1766             :                                                 struct ldb_dn *search_dn,
    1767             :                                                 const char *extra_filter,
    1768             :                                                 struct ldb_result **search_res)
    1769             : {
    1770             :         /* we have nothing to do in case of ex-op failure */
    1771        3295 :         if (ctr6->extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
    1772           0 :                 return WERR_OK;
    1773             :         }
    1774             : 
    1775        3295 :         switch (req10->extended_op) {
    1776          37 :         case DRSUAPI_EXOP_FSMO_RID_ALLOC:
    1777             :         {
    1778           0 :                 int ret;
    1779          37 :                 struct ldb_dn *ntds_dn = NULL;
    1780          37 :                 struct ldb_dn *server_dn = NULL;
    1781          37 :                 struct ldb_dn *machine_dn = NULL;
    1782          37 :                 struct ldb_dn *rid_set_dn = NULL;
    1783          37 :                 struct ldb_result *search_res2 = NULL;
    1784          37 :                 struct ldb_result *search_res3 = NULL;
    1785          37 :                 TALLOC_CTX *frame = talloc_stackframe();
    1786             :                 /* get RID manager, RID set and server DN (in that order) */
    1787             : 
    1788             :                 /* This first search will get the RID Manager */
    1789          37 :                 ret = drsuapi_search_with_extended_dn(b_state->sam_ctx, frame,
    1790             :                                                       search_res,
    1791             :                                                       search_dn, LDB_SCOPE_BASE,
    1792             :                                                       collect_objects_attrs,
    1793             :                                                       NULL);
    1794          37 :                 if (ret != LDB_SUCCESS) {
    1795           0 :                         DEBUG(1, ("DRSUAPI_EXOP_FSMO_RID_ALLOC: Failed to get RID Manager object %s - %s\n",
    1796             :                                   ldb_dn_get_linearized(search_dn),
    1797             :                                   ldb_errstring(b_state->sam_ctx)));
    1798           0 :                         TALLOC_FREE(frame);
    1799           0 :                         return WERR_DS_DRA_INTERNAL_ERROR;
    1800             :                 }
    1801             : 
    1802          37 :                 if ((*search_res)->count != 1) {
    1803           0 :                         DEBUG(1, ("DRSUAPI_EXOP_FSMO_RID_ALLOC: Failed to get RID Manager object %s - %u objects returned\n",
    1804             :                                   ldb_dn_get_linearized(search_dn),
    1805             :                                   (*search_res)->count));
    1806           0 :                         TALLOC_FREE(frame);
    1807           0 :                         return WERR_DS_DRA_INTERNAL_ERROR;
    1808             :                 }
    1809             : 
    1810             :                 /* Now extend it to the RID set */
    1811             : 
    1812             :                 /* Find the computer account DN for the destination
    1813             :                  * dsa GUID specified */
    1814             : 
    1815          37 :                 ret = dsdb_find_dn_by_guid(b_state->sam_ctx, frame,
    1816          37 :                                            &req10->destination_dsa_guid, 0,
    1817             :                                            &ntds_dn);
    1818          37 :                 if (ret != LDB_SUCCESS) {
    1819           0 :                         DEBUG(1, ("DRSUAPI_EXOP_FSMO_RID_ALLOC: Unable to find NTDS object for guid %s - %s\n",
    1820             :                                   GUID_string(frame,
    1821             :                                               &req10->destination_dsa_guid),
    1822             :                                   ldb_errstring(b_state->sam_ctx)));
    1823           0 :                         TALLOC_FREE(frame);
    1824           0 :                         return WERR_DS_DRA_INTERNAL_ERROR;
    1825             :                 }
    1826             : 
    1827          37 :                 server_dn = ldb_dn_get_parent(frame, ntds_dn);
    1828          37 :                 if (!server_dn) {
    1829           0 :                         TALLOC_FREE(frame);
    1830           0 :                         return WERR_DS_DRA_INTERNAL_ERROR;
    1831             :                 }
    1832             : 
    1833          37 :                 ret = samdb_reference_dn(b_state->sam_ctx, frame, server_dn,
    1834             :                                          "serverReference", &machine_dn);
    1835          37 :                 if (ret != LDB_SUCCESS) {
    1836           0 :                         DEBUG(1, ("DRSUAPI_EXOP_FSMO_RID_ALLOC: Failed to find serverReference in %s - %s\n",
    1837             :                                   ldb_dn_get_linearized(server_dn),
    1838             :                                   ldb_errstring(b_state->sam_ctx)));
    1839           0 :                         TALLOC_FREE(frame);
    1840           0 :                         return WERR_DS_DRA_INTERNAL_ERROR;
    1841             :                 }
    1842             : 
    1843          37 :                 ret = samdb_reference_dn(b_state->sam_ctx, frame, machine_dn,
    1844             :                                          "rIDSetReferences", &rid_set_dn);
    1845          37 :                 if (ret != LDB_SUCCESS) {
    1846           0 :                         DEBUG(1, ("DRSUAPI_EXOP_FSMO_RID_ALLOC: Failed to find rIDSetReferences in %s - %s\n",
    1847             :                                   ldb_dn_get_linearized(server_dn),
    1848             :                                   ldb_errstring(b_state->sam_ctx)));
    1849           0 :                         TALLOC_FREE(frame);
    1850           0 :                         return WERR_DS_DRA_INTERNAL_ERROR;
    1851             :                 }
    1852             : 
    1853             : 
    1854             :                 /* This first search will get the RID Manager, now get the RID set */
    1855          37 :                 ret = drsuapi_search_with_extended_dn(b_state->sam_ctx, frame,
    1856             :                                                       &search_res2,
    1857             :                                                       rid_set_dn, LDB_SCOPE_BASE,
    1858             :                                                       collect_objects_attrs,
    1859             :                                                       NULL);
    1860          37 :                 if (ret != LDB_SUCCESS) {
    1861           0 :                         DEBUG(1, ("DRSUAPI_EXOP_FSMO_RID_ALLOC: Failed to get RID Set object %s - %s\n",
    1862             :                                   ldb_dn_get_linearized(rid_set_dn),
    1863             :                                   ldb_errstring(b_state->sam_ctx)));
    1864           0 :                         TALLOC_FREE(frame);
    1865           0 :                         return WERR_DS_DRA_INTERNAL_ERROR;
    1866             :                 }
    1867             : 
    1868          37 :                 if (search_res2->count != 1) {
    1869           0 :                         DEBUG(1, ("DRSUAPI_EXOP_FSMO_RID_ALLOC: Failed to get RID Set object %s - %u objects returned\n",
    1870             :                                   ldb_dn_get_linearized(rid_set_dn),
    1871             :                                   search_res2->count));
    1872           0 :                         TALLOC_FREE(frame);
    1873           0 :                         return WERR_DS_DRA_INTERNAL_ERROR;
    1874             :                 }
    1875             : 
    1876             :                 /* Finally get the server DN */
    1877          37 :                 ret = drsuapi_search_with_extended_dn(b_state->sam_ctx, frame,
    1878             :                                                       &search_res3,
    1879             :                                                       machine_dn, LDB_SCOPE_BASE,
    1880             :                                                       collect_objects_attrs,
    1881             :                                                       NULL);
    1882          37 :                 if (ret != LDB_SUCCESS) {
    1883           0 :                         DEBUG(1, ("DRSUAPI_EXOP_FSMO_RID_ALLOC: Failed to get server object %s - %s\n",
    1884             :                                   ldb_dn_get_linearized(server_dn),
    1885             :                                   ldb_errstring(b_state->sam_ctx)));
    1886           0 :                         TALLOC_FREE(frame);
    1887           0 :                         return WERR_DS_DRA_INTERNAL_ERROR;
    1888             :                 }
    1889             : 
    1890          37 :                 if (search_res3->count != 1) {
    1891           0 :                         DEBUG(1, ("DRSUAPI_EXOP_FSMO_RID_ALLOC: Failed to get server object %s - %u objects returned\n",
    1892             :                                   ldb_dn_get_linearized(server_dn),
    1893             :                                   search_res3->count));
    1894           0 :                         TALLOC_FREE(frame);
    1895           0 :                         return WERR_DS_DRA_INTERNAL_ERROR;
    1896             :                 }
    1897             : 
    1898             :                 /* Now extend the original search_res with these answers */
    1899          37 :                 (*search_res)->count = 3;
    1900             : 
    1901          37 :                 (*search_res)->msgs = talloc_realloc(frame, (*search_res)->msgs,
    1902             :                                                      struct ldb_message *,
    1903             :                                                      (*search_res)->count);
    1904          37 :                 if ((*search_res)->msgs == NULL) {
    1905           0 :                         TALLOC_FREE(frame);
    1906           0 :                         return WERR_NOT_ENOUGH_MEMORY;
    1907             :                 }
    1908             : 
    1909             : 
    1910          37 :                 talloc_steal(mem_ctx, *search_res);
    1911          37 :                 (*search_res)->msgs[1] =
    1912          37 :                         talloc_steal((*search_res)->msgs, search_res2->msgs[0]);
    1913          37 :                 (*search_res)->msgs[2] =
    1914          37 :                         talloc_steal((*search_res)->msgs, search_res3->msgs[0]);
    1915             : 
    1916          37 :                 TALLOC_FREE(frame);
    1917          37 :                 return WERR_OK;
    1918             :         }
    1919        3258 :         default:
    1920             :                 /* TODO: implement extended op specific collection
    1921             :                  * of objects. Right now we just normal procedure
    1922             :                  * for collecting objects */
    1923        3258 :                 return getncchanges_collect_objects(b_state,
    1924             :                                                     mem_ctx,
    1925             :                                                     getnc_state,
    1926             :                                                     req10,
    1927             :                                                     search_dn,
    1928             :                                                     extra_filter,
    1929             :                                                     search_res);
    1930             :         }
    1931             : }
    1932             : 
    1933      651504 : static void dcesrv_drsuapi_update_highwatermark(const struct ldb_message *msg,
    1934             :                                                 uint64_t max_usn,
    1935             :                                                 struct drsuapi_DsReplicaHighWaterMark *hwm)
    1936             : {
    1937      651504 :         uint64_t uSN = ldb_msg_find_attr_as_uint64(msg, "uSNChanged", 0);
    1938             : 
    1939      651504 :         if (uSN > max_usn) {
    1940             :                 /*
    1941             :                  * Only report the max_usn we had at the start
    1942             :                  * of the replication cycle.
    1943             :                  *
    1944             :                  * If this object has changed lately we better
    1945             :                  * let the destination dsa refetch the change.
    1946             :                  * This is better than the risk of losing some
    1947             :                  * objects or linked attributes.
    1948             :                  */
    1949        3962 :                 return;
    1950             :         }
    1951             : 
    1952      647542 :         if (uSN <= hwm->tmp_highest_usn) {
    1953       59877 :                 return;
    1954             :         }
    1955             : 
    1956      587665 :         hwm->tmp_highest_usn = uSN;
    1957      587665 :         hwm->reserved_usn = 0;
    1958             : }
    1959             : 
    1960             : /**
    1961             :  * Adds an object's GUID to the cache of objects already sent.
    1962             :  * This avoids us sending the same object multiple times when
    1963             :  * the GetNCChanges request uses a flag like GET_ANC.
    1964             :  */
    1965      456971 : static WERROR dcesrv_drsuapi_obj_cache_add(struct db_context *obj_cache,
    1966             :                                            const struct GUID *guid)
    1967             : {
    1968           0 :         enum ndr_err_code ndr_err;
    1969      456971 :         uint8_t guid_buf[DRS_GUID_SIZE] = { 0, };
    1970      456971 :         DATA_BLOB b = {
    1971             :                 .data = guid_buf,
    1972             :                 .length = sizeof(guid_buf),
    1973             :         };
    1974      456971 :         TDB_DATA key = {
    1975      456971 :                 .dptr = b.data,
    1976      456971 :                 .dsize = b.length,
    1977             :         };
    1978      456971 :         TDB_DATA val = {
    1979             :                 .dptr = NULL,
    1980             :                 .dsize = 0,
    1981             :         };
    1982           0 :         NTSTATUS status;
    1983             : 
    1984      456971 :         ndr_err = ndr_push_struct_into_fixed_blob(&b, guid,
    1985             :                         (ndr_push_flags_fn_t)ndr_push_GUID);
    1986      456971 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    1987           0 :                 return WERR_DS_DRA_INTERNAL_ERROR;
    1988             :         }
    1989             : 
    1990      456971 :         status = dbwrap_store(obj_cache, key, val, TDB_REPLACE);
    1991      456971 :         if (!NT_STATUS_IS_OK(status)) {
    1992           0 :                 return WERR_DS_DRA_INTERNAL_ERROR;
    1993             :         }
    1994             : 
    1995      456971 :         return WERR_OK;
    1996             : }
    1997             : 
    1998             : /**
    1999             :  * Checks if the object with the GUID specified already exists in the
    2000             :  * object cache, i.e. it's already been sent in a GetNCChanges response.
    2001             :  */
    2002      910647 : static WERROR dcesrv_drsuapi_obj_cache_exists(struct db_context *obj_cache,
    2003             :                                               const struct GUID *guid)
    2004             : {
    2005           0 :         enum ndr_err_code ndr_err;
    2006      910647 :         uint8_t guid_buf[DRS_GUID_SIZE] = { 0, };
    2007      910647 :         DATA_BLOB b = {
    2008             :                 .data = guid_buf,
    2009             :                 .length = sizeof(guid_buf),
    2010             :         };
    2011      910647 :         TDB_DATA key = {
    2012      910647 :                 .dptr = b.data,
    2013      910647 :                 .dsize = b.length,
    2014             :         };
    2015           0 :         bool exists;
    2016             : 
    2017      910647 :         ndr_err = ndr_push_struct_into_fixed_blob(&b, guid,
    2018             :                         (ndr_push_flags_fn_t)ndr_push_GUID);
    2019      910647 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    2020           0 :                 return WERR_DS_DRA_INTERNAL_ERROR;
    2021             :         }
    2022             : 
    2023      910647 :         exists = dbwrap_exists(obj_cache, key);
    2024      910647 :         if (!exists) {
    2025      458227 :                 return WERR_OBJECT_NOT_FOUND;
    2026             :         }
    2027             : 
    2028      452420 :         return WERR_OBJECT_NAME_EXISTS;
    2029             : }
    2030             : 
    2031             : /**
    2032             :  * Copies the la_list specified into a sorted array, ready to be sent in a
    2033             :  * GetNCChanges response.
    2034             :  */
    2035        2225 : static WERROR getncchanges_get_sorted_array(const struct drsuapi_DsReplicaLinkedAttribute *la_list,
    2036             :                                             const uint32_t link_count,
    2037             :                                             struct ldb_context *sam_ctx,
    2038             :                                             TALLOC_CTX *mem_ctx,
    2039             :                                             const struct dsdb_schema *schema,
    2040             :                                             struct la_for_sorting **ret_array)
    2041             : {
    2042           0 :         int j;
    2043           0 :         struct la_for_sorting *guid_array;
    2044        2225 :         WERROR werr = WERR_OK;
    2045             : 
    2046        2225 :         *ret_array = NULL;
    2047        2225 :         guid_array = talloc_array(mem_ctx, struct la_for_sorting, link_count);
    2048        2225 :         if (guid_array == NULL) {
    2049           0 :                 DEBUG(0, ("Out of memory allocating %u linked attributes for sorting\n", link_count));
    2050           0 :                 return WERR_NOT_ENOUGH_MEMORY;
    2051             :         }
    2052             : 
    2053       23841 :         for (j = 0; j < link_count; j++) {
    2054             : 
    2055             :                 /* we need to get the target GUIDs to compare */
    2056           0 :                 struct dsdb_dn *dn;
    2057       21616 :                 const struct drsuapi_DsReplicaLinkedAttribute *la = &la_list[j];
    2058           0 :                 const struct dsdb_attribute *schema_attrib;
    2059           0 :                 const struct ldb_val *target_guid;
    2060           0 :                 DATA_BLOB source_guid;
    2061       21616 :                 TALLOC_CTX *frame = talloc_stackframe();
    2062           0 :                 NTSTATUS status;
    2063             : 
    2064       21616 :                 schema_attrib = dsdb_attribute_by_attributeID_id(schema, la->attid);
    2065             : 
    2066       21616 :                 werr = dsdb_dn_la_from_blob(sam_ctx, schema_attrib, schema, frame, la->value.blob, &dn);
    2067       21616 :                 if (!W_ERROR_IS_OK(werr)) {
    2068           0 :                         DEBUG(0,(__location__ ": Bad la blob in sort\n"));
    2069           0 :                         TALLOC_FREE(frame);
    2070           0 :                         return werr;
    2071             :                 }
    2072             : 
    2073             :                 /* Extract the target GUID in NDR form */
    2074       21616 :                 target_guid = ldb_dn_get_extended_component(dn->dn, "GUID");
    2075       21616 :                 if (target_guid == NULL
    2076       21616 :                                 || target_guid->length != sizeof(guid_array[0].target_guid)) {
    2077           0 :                         status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
    2078             :                 } else {
    2079             :                         /* Repack the source GUID as NDR for sorting */
    2080       21616 :                         status = GUID_to_ndr_blob(&la->identifier->guid,
    2081             :                                                   frame,
    2082             :                                                   &source_guid);
    2083             :                 }
    2084             : 
    2085       21616 :                 if (!NT_STATUS_IS_OK(status)
    2086       21616 :                                 || source_guid.length != sizeof(guid_array[0].source_guid)) {
    2087           0 :                         DEBUG(0,(__location__ ": Bad la guid in sort\n"));
    2088           0 :                         TALLOC_FREE(frame);
    2089           0 :                         return ntstatus_to_werror(status);
    2090             :                 }
    2091             : 
    2092       21616 :                 guid_array[j].link = &la_list[j];
    2093       21616 :                 memcpy(guid_array[j].target_guid, target_guid->data,
    2094             :                        sizeof(guid_array[j].target_guid));
    2095       21616 :                 memcpy(guid_array[j].source_guid, source_guid.data,
    2096             :                        sizeof(guid_array[j].source_guid));
    2097       21616 :                 TALLOC_FREE(frame);
    2098             :         }
    2099             : 
    2100        2225 :         TYPESAFE_QSORT(guid_array, link_count, linked_attribute_compare);
    2101             : 
    2102        2225 :         *ret_array = guid_array;
    2103             : 
    2104        2225 :         return werr;
    2105             : }
    2106             : 
    2107             : 
    2108             : /**
    2109             :  * Adds any ancestor/parent objects of the child_obj specified.
    2110             :  * This is needed when the GET_ANC flag is specified in the request.
    2111             :  * @param new_objs if parents are added, this gets updated to point to a chain
    2112             :  * of parent objects (with the parents first and the child last)
    2113             :  */
    2114      448661 : static WERROR getncchanges_add_ancestors(const struct GUID *parent_object_guid,
    2115             :                                          struct ldb_dn *child_dn,
    2116             :                                          TALLOC_CTX *mem_ctx,
    2117             :                                          struct ldb_context *sam_ctx,
    2118             :                                          struct drsuapi_getncchanges_state *getnc_state,
    2119             :                                          struct dsdb_schema *schema,
    2120             :                                          DATA_BLOB *session_key,
    2121             :                                          struct drsuapi_DsGetNCChangesRequest10 *req10,
    2122             :                                          uint32_t *local_pas,
    2123             :                                          struct ldb_dn *machine_dn,
    2124             :                                          struct drsuapi_DsReplicaObjectListItemEx **new_objs)
    2125             : {
    2126           0 :         int ret;
    2127      448661 :         const struct GUID *next_anc_guid = NULL;
    2128      448661 :         WERROR werr = WERR_OK;
    2129           0 :         static const char * const msg_attrs[] = {
    2130             :                                             "*",
    2131             :                                             "nTSecurityDescriptor",
    2132             :                                             "parentGUID",
    2133             :                                             "replPropertyMetaData",
    2134             :                                             DSDB_SECRET_ATTRIBUTES,
    2135             :                                             NULL };
    2136             : 
    2137      448661 :         next_anc_guid = parent_object_guid;
    2138             : 
    2139      451577 :         while (next_anc_guid != NULL) {
    2140      450132 :                 struct drsuapi_DsReplicaObjectListItemEx *anc_obj = NULL;
    2141      450132 :                 struct ldb_message *anc_msg = NULL;
    2142      450132 :                 struct ldb_result *anc_res = NULL;
    2143      450132 :                 struct ldb_dn *anc_dn = NULL;
    2144             : 
    2145             :                 /*
    2146             :                  * For the GET_ANC case (but not the 'send NC root
    2147             :                  * first' case), don't send an object twice.
    2148             :                  *
    2149             :                  * (If we've sent the object, then we've also sent all
    2150             :                  * its parents as well)
    2151             :                  */
    2152      450132 :                 if (getnc_state->obj_cache) {
    2153      449341 :                         werr = dcesrv_drsuapi_obj_cache_exists(getnc_state->obj_cache,
    2154             :                                                                next_anc_guid);
    2155      449341 :                         if (W_ERROR_EQUAL(werr, WERR_OBJECT_NAME_EXISTS)) {
    2156      447216 :                                 return WERR_OK;
    2157             :                         }
    2158        2125 :                         if (W_ERROR_IS_OK(werr)) {
    2159           0 :                                 return WERR_INTERNAL_ERROR;
    2160             :                         }
    2161        2125 :                         if (!W_ERROR_EQUAL(werr, WERR_OBJECT_NOT_FOUND)) {
    2162           0 :                                 return werr;
    2163             :                         }
    2164             :                 }
    2165             : 
    2166        2916 :                 anc_obj = talloc_zero(mem_ctx,
    2167             :                                       struct drsuapi_DsReplicaObjectListItemEx);
    2168        2916 :                 if (anc_obj == NULL) {
    2169           0 :                         return WERR_NOT_ENOUGH_MEMORY;
    2170             :                 }
    2171             : 
    2172        2916 :                 anc_dn = ldb_dn_new_fmt(anc_obj, sam_ctx, "<GUID=%s>",
    2173             :                                         GUID_string(anc_obj, next_anc_guid));
    2174        2916 :                 if (anc_dn == NULL) {
    2175           0 :                         return WERR_NOT_ENOUGH_MEMORY;
    2176             :                 }
    2177             : 
    2178        2916 :                 ret = drsuapi_search_with_extended_dn(sam_ctx, anc_obj,
    2179             :                                                       &anc_res, anc_dn,
    2180             :                                                       LDB_SCOPE_BASE,
    2181             :                                                       msg_attrs, NULL);
    2182        2916 :                 if (ret != LDB_SUCCESS) {
    2183           0 :                         const char *anc_str = NULL;
    2184           0 :                         const char *obj_str = NULL;
    2185             : 
    2186           0 :                         anc_str = ldb_dn_get_extended_linearized(anc_obj,
    2187             :                                                                  anc_dn,
    2188             :                                                                  1);
    2189           0 :                         obj_str = ldb_dn_get_extended_linearized(anc_obj,
    2190             :                                                                  child_dn,
    2191             :                                                                  1);
    2192             : 
    2193           0 :                         DBG_ERR("getncchanges: failed to fetch ANC "
    2194             :                                 "DN %s for DN %s - %s\n",
    2195             :                                 anc_str, obj_str, ldb_errstring(sam_ctx));
    2196           0 :                         return WERR_DS_DRA_INCONSISTENT_DIT;
    2197             :                 }
    2198             : 
    2199        2916 :                 anc_msg = anc_res->msgs[0];
    2200             : 
    2201        2916 :                 werr = get_nc_changes_build_object(anc_obj, anc_msg,
    2202             :                                                    sam_ctx,
    2203             :                                                    getnc_state,
    2204             :                                                    schema, session_key,
    2205             :                                                    req10,
    2206             :                                                    false, /* force_object_return */
    2207             :                                                    local_pas,
    2208             :                                                    machine_dn,
    2209             :                                                    next_anc_guid);
    2210        2916 :                 if (!W_ERROR_IS_OK(werr)) {
    2211           0 :                         return werr;
    2212             :                 }
    2213             : 
    2214             :                 /*
    2215             :                  * Regardless of whether we actually use it or not,
    2216             :                  * we add it to the cache so we don't look at it again
    2217             :                  *
    2218             :                  * The only time we are here without
    2219             :                  * getnc_state->obj_cache is for the forced addition
    2220             :                  * of the NC root to the start of the reply, this we
    2221             :                  * want to add each and every call..
    2222             :                  */
    2223        2916 :                 if (getnc_state->obj_cache) {
    2224        2125 :                         werr = dcesrv_drsuapi_obj_cache_add(getnc_state->obj_cache,
    2225             :                                                             next_anc_guid);
    2226        2125 :                         if (!W_ERROR_IS_OK(werr)) {
    2227           0 :                                 return werr;
    2228             :                         }
    2229             :                 }
    2230             : 
    2231             :                 /*
    2232             :                  * Any ancestors which are below the highwatermark
    2233             :                  * or uptodateness_vector shouldn't be added,
    2234             :                  * but we still look further up the
    2235             :                  * tree for ones which have been changed recently.
    2236             :                  */
    2237        2916 :                 if (anc_obj->meta_data_ctr != NULL) {
    2238             : 
    2239             :                         /*
    2240             :                          * prepend the parent to the list so that the client-side
    2241             :                          * adds the parent object before it adds the children
    2242             :                          */
    2243        2461 :                         anc_obj->next_object = *new_objs;
    2244        2461 :                         *new_objs = anc_obj;
    2245             :                 }
    2246             : 
    2247        2916 :                 anc_msg = NULL;
    2248        2916 :                 TALLOC_FREE(anc_res);
    2249        2916 :                 TALLOC_FREE(anc_dn);
    2250             : 
    2251             :                 /*
    2252             :                  * We may need to resolve more parents...
    2253             :                  */
    2254        2916 :                 next_anc_guid = anc_obj->parent_object_guid;
    2255             :         }
    2256        1445 :         return werr;
    2257             : }
    2258             : 
    2259             : /**
    2260             :  * Adds a list of new objects into the current chunk of replication data to send
    2261             :  */
    2262      576070 : static void getncchanges_chunk_add_objects(struct getncchanges_repl_chunk *repl_chunk,
    2263             :                                            struct drsuapi_DsReplicaObjectListItemEx *obj_list)
    2264             : {
    2265           0 :         struct drsuapi_DsReplicaObjectListItemEx *obj;
    2266             : 
    2267             :         /*
    2268             :          * We track the last object added to the replication chunk, so just add
    2269             :          * the new object-list onto the end
    2270             :          */
    2271      576070 :         if (repl_chunk->object_list == NULL) {
    2272        8099 :                 repl_chunk->object_list = obj_list;
    2273             :         } else {
    2274      567971 :                 repl_chunk->last_object->next_object = obj_list;
    2275             :         }
    2276             : 
    2277     1152581 :         for (obj = obj_list; obj != NULL; obj = obj->next_object) {
    2278      576511 :                 repl_chunk->object_count += 1;
    2279             : 
    2280             :                 /*
    2281             :                  * Remember the last object in the response - we'll use this to
    2282             :                  * link the next object(s) processed onto the existing list
    2283             :                  */
    2284      576511 :                 if (obj->next_object == NULL) {
    2285      575286 :                         repl_chunk->last_object = obj;
    2286             :                 }
    2287             :         }
    2288      576070 : }
    2289             : 
    2290             : /**
    2291             :  * Gets the object to send, packed into an RPC struct ready to send. This also
    2292             :  * adds the object to the object cache, and adds any ancestors (if needed).
    2293             :  * @param msg - DB search result for the object to add
    2294             :  * @param guid - GUID of the object to add
    2295             :  * @param ret_obj_list - returns the object ready to be sent (in a list, along
    2296             :  * with any ancestors that might be needed). NULL if nothing to send.
    2297             :  */
    2298      650154 : static WERROR getncchanges_get_obj_to_send(const struct ldb_message *msg,
    2299             :                                            TALLOC_CTX *mem_ctx,
    2300             :                                            struct ldb_context *sam_ctx,
    2301             :                                            struct drsuapi_getncchanges_state *getnc_state,
    2302             :                                            struct dsdb_schema *schema,
    2303             :                                            DATA_BLOB *session_key,
    2304             :                                            struct drsuapi_DsGetNCChangesRequest10 *req10,
    2305             :                                            bool force_object_return,
    2306             :                                            uint32_t *local_pas,
    2307             :                                            struct ldb_dn *machine_dn,
    2308             :                                            const struct GUID *guid,
    2309             :                                            struct drsuapi_DsReplicaObjectListItemEx **ret_obj_list)
    2310             : {
    2311           0 :         struct drsuapi_DsReplicaObjectListItemEx *obj;
    2312           0 :         WERROR werr;
    2313             : 
    2314      650154 :         *ret_obj_list = NULL;
    2315             : 
    2316      650154 :         obj = talloc_zero(mem_ctx, struct drsuapi_DsReplicaObjectListItemEx);
    2317      650154 :         W_ERROR_HAVE_NO_MEMORY(obj);
    2318             : 
    2319      650154 :         werr = get_nc_changes_build_object(obj, msg, sam_ctx, getnc_state,
    2320             :                                            schema, session_key, req10,
    2321             :                                            force_object_return,
    2322             :                                            local_pas, machine_dn, guid);
    2323      650154 :         if (!W_ERROR_IS_OK(werr)) {
    2324           0 :                 return werr;
    2325             :         }
    2326             : 
    2327             :         /*
    2328             :          * The object may get filtered out by the UTDV's USN and not actually
    2329             :          * sent, in which case there's nothing more to do here
    2330             :          */
    2331      650154 :         if (obj->meta_data_ctr == NULL) {
    2332       76104 :                 TALLOC_FREE(obj);
    2333       76104 :                 return WERR_OK;
    2334             :         }
    2335             : 
    2336      574050 :         if (getnc_state->obj_cache != NULL) {
    2337      454846 :                 werr = dcesrv_drsuapi_obj_cache_add(getnc_state->obj_cache,
    2338             :                                                     guid);
    2339      454846 :                 if (!W_ERROR_IS_OK(werr)) {
    2340           0 :                         return werr;
    2341             :                 }
    2342             :         }
    2343             : 
    2344      574050 :         *ret_obj_list = obj;
    2345             : 
    2346             :         /*
    2347             :          * If required, also add any ancestors that the client may need to know
    2348             :          * about before it can resolve this object. These get prepended to the
    2349             :          * ret_obj_list so the client adds them first.
    2350             :          *
    2351             :          * We allow this to be disabled to permit testing of a
    2352             :          * client-side fallback for the broken behaviour in Samba 4.5
    2353             :          * and earlier.
    2354             :          */
    2355      574050 :         if (getnc_state->is_get_anc
    2356      450815 :             && !getnc_state->broken_samba_4_5_get_anc_emulation) {
    2357      446641 :                 werr = getncchanges_add_ancestors(obj->parent_object_guid,
    2358      446641 :                                                   msg->dn, mem_ctx,
    2359             :                                                   sam_ctx, getnc_state,
    2360             :                                                   schema, session_key,
    2361             :                                                   req10, local_pas,
    2362             :                                                   machine_dn, ret_obj_list);
    2363             :         }
    2364             : 
    2365      574050 :         return werr;
    2366             : }
    2367             : 
    2368             : /**
    2369             :  * Returns the number of links that are waiting to be sent
    2370             :  */
    2371      221907 : static uint32_t getncchanges_chunk_links_pending(struct getncchanges_repl_chunk *repl_chunk,
    2372             :                                                  struct drsuapi_getncchanges_state *getnc_state)
    2373             : {
    2374      221907 :         uint32_t links_to_send = 0;
    2375             : 
    2376      221907 :         if (getnc_state->is_get_tgt) {
    2377             : 
    2378             :                 /*
    2379             :                  * when the GET_TGT flag is set, only include the linked
    2380             :                  * attributes whose target object has already been checked
    2381             :                  * (i.e. they're ready to send).
    2382             :                  */
    2383      115446 :                 if (repl_chunk->tgt_la_count > getnc_state->la_idx) {
    2384       23165 :                         links_to_send = (repl_chunk->tgt_la_count -
    2385       23165 :                                          getnc_state->la_idx);
    2386             :                 }
    2387             :         } else {
    2388      106461 :                 links_to_send = getnc_state->la_count - getnc_state->la_idx;
    2389             :         }
    2390             : 
    2391      221907 :         return links_to_send;
    2392             : }
    2393             : 
    2394             : /**
    2395             :  * Returns the max number of links that will fit in the current replication chunk
    2396             :  */
    2397      332684 : static uint32_t getncchanges_chunk_max_links(struct getncchanges_repl_chunk *repl_chunk)
    2398             : {
    2399      332684 :         uint32_t max_links = 0;
    2400             : 
    2401      332684 :         if (repl_chunk->max_links != DEFAULT_MAX_LINKS ||
    2402      204028 :             repl_chunk->max_objects != DEFAULT_MAX_OBJECTS) {
    2403             : 
    2404             :                 /*
    2405             :                  * We're using non-default settings, so don't try to adjust
    2406             :                  * them, just trust the user has configured decent values
    2407             :                  */
    2408      329419 :                 max_links = repl_chunk->max_links;
    2409             : 
    2410        3265 :         } else if (repl_chunk->max_links > repl_chunk->object_count) {
    2411             : 
    2412             :                 /*
    2413             :                  * This is just an approximate guess to avoid overfilling the
    2414             :                  * replication chunk. It's the logic we've used historically.
    2415             :                  * E.g. if we've already sent 1000 objects, then send 1000 fewer
    2416             :                  * links. For comparison, the max that Windows seems to send is
    2417             :                  * ~2700 links and ~250 objects (although this may vary based
    2418             :                  * on timeouts)
    2419             :                  */
    2420        3265 :                 max_links = repl_chunk->max_links - repl_chunk->object_count;
    2421             :         }
    2422             : 
    2423      332684 :         return max_links;
    2424             : }
    2425             : 
    2426             : /**
    2427             :  * Returns true if the current GetNCChanges() call has taken longer than its
    2428             :  * allotted time. This prevents the client from timing out.
    2429             :  */
    2430     1231271 : static bool getncchanges_chunk_timed_out(struct getncchanges_repl_chunk *repl_chunk)
    2431             : {
    2432     1231271 :         return (time(NULL) - repl_chunk->start > repl_chunk->max_wait);
    2433             : }
    2434             : 
    2435             : /**
    2436             :  * Returns true if the current chunk of replication data has reached the
    2437             :  * max_objects and/or max_links thresholds.
    2438             :  */
    2439      658392 : static bool getncchanges_chunk_is_full(struct getncchanges_repl_chunk *repl_chunk,
    2440             :                                        struct drsuapi_getncchanges_state *getnc_state)
    2441             : {
    2442      658392 :         bool chunk_full = false;
    2443           0 :         uint32_t links_to_send;
    2444           0 :         uint32_t chunk_limit;
    2445             : 
    2446             :         /* check if the current chunk is already full with objects */
    2447      658392 :         if (repl_chunk->object_count >= repl_chunk->max_objects) {
    2448        1948 :                 chunk_full = true;
    2449             : 
    2450     1239525 :         } else if (repl_chunk->object_count > 0 &&
    2451      583081 :                    getncchanges_chunk_timed_out(repl_chunk)) {
    2452             : 
    2453             :                 /*
    2454             :                  * We've exceeded our allotted time building this chunk,
    2455             :                  * and we have at least one object to send back to the client
    2456             :                  */
    2457           0 :                 chunk_full = true;
    2458             : 
    2459      656444 :         } else if (repl_chunk->immediate_link_sync) {
    2460             : 
    2461             :                 /* check if the chunk is already full with links */
    2462      214911 :                 links_to_send = getncchanges_chunk_links_pending(repl_chunk,
    2463             :                                                                  getnc_state);
    2464             : 
    2465      214911 :                 chunk_limit = getncchanges_chunk_max_links(repl_chunk);
    2466             : 
    2467             :                 /*
    2468             :                  * The chunk is full if we've got more links to send than will
    2469             :                  * fit in one chunk
    2470             :                  */
    2471      214911 :                 if (links_to_send > 0 && chunk_limit <= links_to_send) {
    2472          16 :                         chunk_full = true;
    2473             :                 }
    2474             :         }
    2475             : 
    2476      658392 :         return chunk_full;
    2477             : }
    2478             : 
    2479             : /**
    2480             :  * Goes through any new linked attributes and checks that the target object
    2481             :  * will be known to the client, i.e. we've already sent it in an replication
    2482             :  * chunk. If not, then it adds the target object to the current replication
    2483             :  * chunk. This is only done when the client specifies DRS_GET_TGT.
    2484             :  */
    2485      110509 : static WERROR getncchanges_chunk_add_la_targets(struct getncchanges_repl_chunk *repl_chunk,
    2486             :                                                 struct drsuapi_getncchanges_state *getnc_state,
    2487             :                                                 uint32_t start_la_index,
    2488             :                                                 TALLOC_CTX *mem_ctx,
    2489             :                                                 struct ldb_context *sam_ctx,
    2490             :                                                 struct dsdb_schema *schema,
    2491             :                                                 DATA_BLOB *session_key,
    2492             :                                                 struct drsuapi_DsGetNCChangesRequest10 *req10,
    2493             :                                                 uint32_t *local_pas,
    2494             :                                                 struct ldb_dn *machine_dn)
    2495             : {
    2496           0 :         int ret;
    2497           0 :         uint32_t i;
    2498           0 :         uint32_t max_la_index;
    2499           0 :         uint32_t max_links;
    2500      110509 :         uint32_t target_count = 0;
    2501      110509 :         WERROR werr = WERR_OK;
    2502           0 :         static const char * const msg_attrs[] = {
    2503             :                                             "*",
    2504             :                                             "nTSecurityDescriptor",
    2505             :                                             "parentGUID",
    2506             :                                             "replPropertyMetaData",
    2507             :                                             DSDB_SECRET_ATTRIBUTES,
    2508             :                                             NULL };
    2509             : 
    2510             :         /*
    2511             :          * A object can potentially link to thousands of targets. Only bother
    2512             :          * checking as many targets as will fit into the current response
    2513             :          */
    2514      110509 :         max_links = getncchanges_chunk_max_links(repl_chunk);
    2515      110509 :         max_la_index = MIN(getnc_state->la_count,
    2516             :                            start_la_index + max_links);
    2517             : 
    2518             :         /* loop through any linked attributes to check */
    2519      110509 :         for (i = start_la_index;
    2520      115433 :              (i < max_la_index &&
    2521        4932 :               !getncchanges_chunk_is_full(repl_chunk, getnc_state));
    2522        4924 :              i++) {
    2523             : 
    2524           0 :                 struct GUID target_guid;
    2525        4924 :                 struct drsuapi_DsReplicaObjectListItemEx *new_objs = NULL;
    2526           0 :                 const struct drsuapi_DsReplicaLinkedAttribute *la;
    2527           0 :                 struct ldb_result *msg_res;
    2528           0 :                 struct ldb_dn *search_dn;
    2529           0 :                 TALLOC_CTX *tmp_ctx;
    2530           0 :                 struct dsdb_dn *dn;
    2531           0 :                 const struct dsdb_attribute *schema_attrib;
    2532           0 :                 NTSTATUS status;
    2533           0 :                 bool same_nc;
    2534             : 
    2535        4924 :                 la = &getnc_state->la_list[i];
    2536        4924 :                 tmp_ctx = talloc_new(mem_ctx);
    2537             : 
    2538             :                 /*
    2539             :                  * Track what linked attribute targets we've checked. We might
    2540             :                  * not have time to check them all, so we should only send back
    2541             :                  * the ones we've actually checked.
    2542             :                  */
    2543        4924 :                 repl_chunk->tgt_la_count = i + 1;
    2544             : 
    2545             :                 /* get the GUID of the linked attribute's target object */
    2546        4924 :                 schema_attrib = dsdb_attribute_by_attributeID_id(schema,
    2547        4924 :                                                                  la->attid);
    2548             : 
    2549        4924 :                 werr = dsdb_dn_la_from_blob(sam_ctx, schema_attrib, schema,
    2550        4924 :                                             tmp_ctx, la->value.blob, &dn);
    2551             : 
    2552        4924 :                 if (!W_ERROR_IS_OK(werr)) {
    2553           0 :                         DEBUG(0,(__location__ ": Bad la blob\n"));
    2554           0 :                         return werr;
    2555             :                 }
    2556             : 
    2557        4924 :                 status = dsdb_get_extended_dn_guid(dn->dn, &target_guid, "GUID");
    2558             : 
    2559        4924 :                 if (!NT_STATUS_IS_OK(status)) {
    2560           0 :                         return ntstatus_to_werror(status);
    2561             :                 }
    2562             : 
    2563             :                 /*
    2564             :                  * if the target isn't in the cache, then the client
    2565             :                  * might not know about it, so send the target now
    2566             :                  */
    2567        4924 :                 werr = dcesrv_drsuapi_obj_cache_exists(getnc_state->obj_cache,
    2568             :                                                        &target_guid);
    2569             : 
    2570        4924 :                 if (W_ERROR_EQUAL(werr, WERR_OBJECT_NAME_EXISTS)) {
    2571             : 
    2572             :                         /* target already sent, nothing to do */
    2573        2108 :                         TALLOC_FREE(tmp_ctx);
    2574        2108 :                         continue;
    2575             :                 }
    2576             : 
    2577        2816 :                 same_nc = dsdb_objects_have_same_nc(sam_ctx, tmp_ctx, dn->dn,
    2578             :                                                     getnc_state->ncRoot_dn);
    2579             : 
    2580             :                 /* don't try to fetch target objects from another partition */
    2581        2816 :                 if (!same_nc) {
    2582         852 :                         TALLOC_FREE(tmp_ctx);
    2583         852 :                         continue;
    2584             :                 }
    2585             : 
    2586        1964 :                 search_dn = ldb_dn_new_fmt(tmp_ctx, sam_ctx, "<GUID=%s>",
    2587             :                                            GUID_string(tmp_ctx, &target_guid));
    2588        1964 :                 W_ERROR_HAVE_NO_MEMORY(search_dn);
    2589             : 
    2590        1964 :                 ret = drsuapi_search_with_extended_dn(sam_ctx, tmp_ctx,
    2591             :                                                       &msg_res, search_dn,
    2592             :                                                       LDB_SCOPE_BASE,
    2593             :                                                       msg_attrs, NULL);
    2594             : 
    2595             :                 /*
    2596             :                  * Don't fail the replication if we can't find the target.
    2597             :                  * This could happen for a one-way linked attribute, if the
    2598             :                  * target is deleted and then later expunged (thus, the source
    2599             :                  * object can be left with a hanging link). Continue to send
    2600             :                  * the the link (the client-side has already tried once with
    2601             :                  * GET_TGT, so it should just end up ignoring it).
    2602             :                  */
    2603        1964 :                 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
    2604           0 :                         DBG_WARNING("Encountered unknown link target DN %s\n",
    2605             :                                     ldb_dn_get_extended_linearized(tmp_ctx, dn->dn, 1));
    2606           0 :                         TALLOC_FREE(tmp_ctx);
    2607           0 :                         continue;
    2608             : 
    2609        1964 :                 } else if (ret != LDB_SUCCESS) {
    2610           0 :                         DBG_ERR("Failed to fetch link target DN %s - %s\n",
    2611             :                                 ldb_dn_get_extended_linearized(tmp_ctx, dn->dn, 1),
    2612             :                                 ldb_errstring(sam_ctx));
    2613           0 :                         return WERR_DS_DRA_INCONSISTENT_DIT;
    2614             :                 }
    2615             : 
    2616             :                 /*
    2617             :                  * Construct an object, ready to send (this will include
    2618             :                  * the object's ancestors as well, if GET_ANC is set)
    2619             :                  */
    2620        1964 :                 werr = getncchanges_get_obj_to_send(msg_res->msgs[0], mem_ctx,
    2621             :                                                     sam_ctx, getnc_state,
    2622             :                                                     schema, session_key, req10,
    2623             :                                                     false, local_pas,
    2624             :                                                     machine_dn, &target_guid,
    2625             :                                                     &new_objs);
    2626        1964 :                 if (!W_ERROR_IS_OK(werr)) {
    2627           0 :                         return werr;
    2628             :                 }
    2629             : 
    2630        1964 :                 if (new_objs != NULL) {
    2631        1854 :                         target_count++;
    2632        1854 :                         getncchanges_chunk_add_objects(repl_chunk, new_objs);
    2633             :                 }
    2634        1964 :                 TALLOC_FREE(tmp_ctx);
    2635             :         }
    2636             : 
    2637      110509 :         if (target_count > 0) {
    2638        1282 :                 DEBUG(3, ("GET_TGT: checked %u link-attrs, added %u target objs\n",
    2639             :                           i - start_la_index, target_count));
    2640             :         }
    2641             : 
    2642      110509 :         return WERR_OK;
    2643             : }
    2644             : 
    2645             : /**
    2646             :  * Creates a helper struct used for building a chunk of replication data,
    2647             :  * i.e. used over a single call to dcesrv_drsuapi_DsGetNCChanges().
    2648             :  */
    2649       10301 : static struct getncchanges_repl_chunk * getncchanges_chunk_new(TALLOC_CTX *mem_ctx,
    2650             :                                                                struct dcesrv_call_state *dce_call,
    2651             :                                                                struct drsuapi_DsGetNCChangesRequest10 *req10)
    2652             : {
    2653           0 :         struct getncchanges_repl_chunk *repl_chunk;
    2654             : 
    2655       10301 :         repl_chunk = talloc_zero(mem_ctx, struct getncchanges_repl_chunk);
    2656             : 
    2657       10301 :         repl_chunk->start = time(NULL);
    2658             : 
    2659       10301 :         repl_chunk->max_objects = lpcfg_parm_int(dce_call->conn->dce_ctx->lp_ctx, NULL,
    2660             :                                                  "drs", "max object sync",
    2661             :                                                  DEFAULT_MAX_OBJECTS);
    2662             : 
    2663             :         /*
    2664             :          * The client control here only applies in normal replication, not extended
    2665             :          * operations, which return a fixed set, even if the caller
    2666             :          * sets max_object_count == 0
    2667             :          */
    2668       10301 :         if (req10->extended_op == DRSUAPI_EXOP_NONE) {
    2669             : 
    2670             :                 /*
    2671             :                  * use this to force single objects at a time, which is useful
    2672             :                  * for working out what object is giving problems
    2673             :                  */
    2674        5066 :                 if (req10->max_object_count < repl_chunk->max_objects) {
    2675        5066 :                         repl_chunk->max_objects = req10->max_object_count;
    2676             :                 }
    2677             :         }
    2678             : 
    2679       10301 :         repl_chunk->max_links =
    2680       10301 :                         lpcfg_parm_int(dce_call->conn->dce_ctx->lp_ctx, NULL,
    2681             :                                        "drs", "max link sync",
    2682             :                                         DEFAULT_MAX_LINKS);
    2683             : 
    2684       10301 :         repl_chunk->immediate_link_sync =
    2685       10301 :                         lpcfg_parm_bool(dce_call->conn->dce_ctx->lp_ctx, NULL,
    2686             :                                         "drs", "immediate link sync", false);
    2687             : 
    2688             :         /*
    2689             :          * Maximum time that we can spend in a getncchanges
    2690             :          * in order to avoid timeout of the other part.
    2691             :          * 10 seconds by default.
    2692             :          */
    2693       10301 :         repl_chunk->max_wait = lpcfg_parm_int(dce_call->conn->dce_ctx->lp_ctx,
    2694             :                                               NULL, "drs", "max work time", 10);
    2695             : 
    2696       10301 :         return repl_chunk;
    2697             : }
    2698             : 
    2699             : /*
    2700             :   drsuapi_DsGetNCChanges
    2701             : 
    2702             :   see MS-DRSR 4.1.10.5.2 for basic logic of this function
    2703             : */
    2704       10301 : WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
    2705             :                                      struct drsuapi_DsGetNCChanges *r)
    2706             : {
    2707           0 :         struct auth_session_info *session_info =
    2708       10301 :                 dcesrv_call_session_info(dce_call);
    2709           0 :         struct imessaging_context *imsg_ctx =
    2710       10301 :                 dcesrv_imessaging_context(dce_call->conn);
    2711           0 :         struct drsuapi_DsReplicaObjectIdentifier *untrusted_ncRoot;
    2712           0 :         int ret;
    2713           0 :         uint32_t i, k;
    2714           0 :         struct dsdb_schema *schema;
    2715           0 :         struct drsuapi_DsReplicaOIDMapping_Ctr *ctr;
    2716           0 :         struct getncchanges_repl_chunk *repl_chunk;
    2717           0 :         NTSTATUS status;
    2718           0 :         DATA_BLOB session_key;
    2719           0 :         WERROR werr;
    2720           0 :         struct dcesrv_handle *h;
    2721           0 :         struct drsuapi_bind_state *b_state;
    2722       10301 :         struct drsuapi_getncchanges_state *getnc_state = NULL;
    2723           0 :         struct drsuapi_DsGetNCChangesRequest10 *req10;
    2724           0 :         uint32_t options;
    2725       10301 :         uint32_t link_count = 0;
    2726       10301 :         struct ldb_dn *search_dn = NULL;
    2727           0 :         bool am_rodc;
    2728           0 :         enum security_user_level security_level;
    2729           0 :         struct ldb_context *sam_ctx;
    2730           0 :         struct dom_sid *user_sid;
    2731           0 :         bool is_secret_request;
    2732           0 :         bool is_gc_pas_request;
    2733           0 :         struct drsuapi_changed_objects *changes;
    2734       10301 :         bool has_get_all_changes = false;
    2735           0 :         struct GUID invocation_id;
    2736           0 :         static const struct drsuapi_DsReplicaLinkedAttribute no_linked_attr;
    2737       10301 :         struct dsdb_schema_prefixmap *pfm_remote = NULL;
    2738       10301 :         bool full = true;
    2739       10301 :         uint32_t *local_pas = NULL;
    2740       10301 :         struct ldb_dn *machine_dn = NULL; /* Only used for REPL SECRET EXOP */
    2741             : 
    2742       10301 :         DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
    2743       10301 :         b_state = h->data;
    2744             : 
    2745             :         /* sam_ctx_system is not present for non-administrator users */
    2746       10301 :         sam_ctx = b_state->sam_ctx_system?b_state->sam_ctx_system:b_state->sam_ctx;
    2747             : 
    2748       10301 :         invocation_id = *(samdb_ntds_invocation_id(sam_ctx));
    2749             : 
    2750       10301 :         *r->out.level_out = 6;
    2751             : 
    2752       10301 :         r->out.ctr->ctr6.linked_attributes_count = 0;
    2753       10301 :         r->out.ctr->ctr6.linked_attributes = discard_const_p(struct drsuapi_DsReplicaLinkedAttribute, &no_linked_attr);
    2754             : 
    2755       10301 :         r->out.ctr->ctr6.object_count = 0;
    2756       10301 :         r->out.ctr->ctr6.nc_object_count = 0;
    2757       10301 :         r->out.ctr->ctr6.more_data = false;
    2758       10301 :         r->out.ctr->ctr6.uptodateness_vector = NULL;
    2759       10301 :         r->out.ctr->ctr6.source_dsa_guid = *(samdb_ntds_objectGUID(sam_ctx));
    2760       10301 :         r->out.ctr->ctr6.source_dsa_invocation_id = *(samdb_ntds_invocation_id(sam_ctx));
    2761       10301 :         r->out.ctr->ctr6.first_object = NULL;
    2762             : 
    2763             :         /* Check request revision. 
    2764             :          */
    2765       10301 :         switch (r->in.level) {
    2766        3483 :         case 8:
    2767        3483 :                 req10 = getncchanges_map_req8(mem_ctx, &r->in.req->req8);
    2768        3483 :                 if (req10 == NULL) {
    2769           0 :                         return WERR_NOT_ENOUGH_MEMORY;
    2770             :                 }
    2771        3483 :                 break;
    2772        6818 :         case 10:
    2773        6818 :                 req10 = &r->in.req->req10;
    2774        6818 :                 break;
    2775           0 :         default:
    2776           0 :                 DEBUG(0,(__location__ ": Request for DsGetNCChanges with unsupported level %u\n",
    2777             :                          r->in.level));
    2778           0 :                 return WERR_REVISION_MISMATCH;
    2779             :         }
    2780             : 
    2781       10301 :         repl_chunk = getncchanges_chunk_new(mem_ctx, dce_call, req10);
    2782             : 
    2783       10301 :         if (repl_chunk == NULL) {
    2784           0 :                 return WERR_NOT_ENOUGH_MEMORY;
    2785             :         }
    2786             : 
    2787             :         /* a RODC doesn't allow for any replication */
    2788       10301 :         ret = samdb_rodc(sam_ctx, &am_rodc);
    2789       10301 :         if (ret == LDB_SUCCESS && am_rodc) {
    2790           0 :                 DEBUG(0,(__location__ ": DsGetNCChanges attempt on RODC\n"));
    2791           0 :                 return WERR_DS_DRA_SOURCE_DISABLED;
    2792             :         }
    2793             : 
    2794             :         /*
    2795             :          * Help our tests pass by pre-checking the
    2796             :          * destination_dsa_guid before the NC permissions.  Info on
    2797             :          * valid DSA GUIDs is not sensitive so this isn't a leak
    2798             :          */
    2799       10301 :         switch (req10->extended_op) {
    2800          79 :         case DRSUAPI_EXOP_FSMO_REQ_ROLE:
    2801             :         case DRSUAPI_EXOP_FSMO_RID_ALLOC:
    2802             :         case DRSUAPI_EXOP_FSMO_RID_REQ_ROLE:
    2803             :         case DRSUAPI_EXOP_FSMO_REQ_PDC:
    2804             :         case DRSUAPI_EXOP_FSMO_ABANDON_ROLE:
    2805             :         {
    2806          79 :                 const char *attrs[] = { NULL };
    2807             : 
    2808          79 :                 ret = samdb_get_ntds_obj_by_guid(mem_ctx,
    2809             :                                                  sam_ctx,
    2810          79 :                                                  &req10->destination_dsa_guid,
    2811             :                                                  attrs,
    2812             :                                                  NULL);
    2813          79 :                 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
    2814             :                         /*
    2815             :                          * Error out with an EXOP error but success at
    2816             :                          * the top level return value
    2817             :                          */
    2818          13 :                         r->out.ctr->ctr6.extended_ret = DRSUAPI_EXOP_ERR_UNKNOWN_CALLER;
    2819          13 :                         return WERR_OK;
    2820          66 :                 } else if (ret != LDB_SUCCESS) {
    2821           0 :                         return WERR_DS_DRA_INTERNAL_ERROR;
    2822             :                 }
    2823             : 
    2824          66 :                 break;
    2825             :         }
    2826       10222 :         case DRSUAPI_EXOP_REPL_SECRET:
    2827             :         case DRSUAPI_EXOP_REPL_OBJ:
    2828             :         case DRSUAPI_EXOP_NONE:
    2829       10222 :                 break;
    2830             :         }
    2831             : 
    2832             :         /* Perform access checks. */
    2833       10288 :         untrusted_ncRoot = req10->naming_context;
    2834       10288 :         if (untrusted_ncRoot == NULL) {
    2835           0 :                 DEBUG(0,(__location__ ": Request for DsGetNCChanges with no NC\n"));
    2836           0 :                 return WERR_DS_DRA_INVALID_PARAMETER;
    2837             :         }
    2838             : 
    2839       10288 :         if (samdb_ntds_options(sam_ctx, &options) != LDB_SUCCESS) {
    2840           0 :                 return WERR_DS_DRA_INTERNAL_ERROR;
    2841             :         }
    2842             : 
    2843       10288 :         if ((options & DS_NTDSDSA_OPT_DISABLE_OUTBOUND_REPL) &&
    2844        1268 :             !(req10->replica_flags & DRSUAPI_DRS_SYNC_FORCED)) {
    2845         687 :                 return WERR_DS_DRA_SOURCE_DISABLED;
    2846             :         }
    2847             : 
    2848        9601 :         user_sid = &session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
    2849             : 
    2850             :         /*
    2851             :          * all clients must have GUID_DRS_GET_CHANGES.  This finds the
    2852             :          * actual NC root of the given value and checks that, allowing
    2853             :          * REPL_OBJ to work safely
    2854             :          */
    2855        9601 :         werr = drs_security_access_check_nc_root(sam_ctx,
    2856             :                                                  mem_ctx,
    2857             :                                                  session_info->security_token,
    2858             :                                                  req10->naming_context,
    2859             :                                                  GUID_DRS_GET_CHANGES);
    2860             : 
    2861        9601 :         if (W_ERROR_EQUAL(werr, WERR_DS_DRA_BAD_NC)) {
    2862             :                 /*
    2863             :                  * These extended operations need a different error if
    2864             :                  * the supplied DN can't be found
    2865             :                  */
    2866           8 :                 switch (req10->extended_op) {
    2867           6 :                 case DRSUAPI_EXOP_REPL_OBJ:
    2868             :                 case DRSUAPI_EXOP_REPL_SECRET:
    2869           6 :                         return WERR_DS_DRA_BAD_DN;
    2870           2 :                 default:
    2871           2 :                         return werr;
    2872             :                 }
    2873             :         }
    2874        9593 :         if (!W_ERROR_IS_OK(werr)) {
    2875          44 :                 return werr;
    2876             :         }
    2877             : 
    2878        9549 :         if (dsdb_functional_level(sam_ctx) >= DS_DOMAIN_FUNCTION_2008) {
    2879       13773 :                 full = req10->partial_attribute_set == NULL &&
    2880        4421 :                        req10->partial_attribute_set_ex == NULL;
    2881             :         } else {
    2882         197 :                 full = (options & DRSUAPI_DRS_WRIT_REP) != 0;
    2883             :         }
    2884             : 
    2885        9549 :         werr = dsdb_schema_pfm_from_drsuapi_pfm(&req10->mapping_ctr, true,
    2886             :                                                 mem_ctx, &pfm_remote, NULL);
    2887             : 
    2888             :         /* We were supplied a partial attribute set, without the prefix map! */
    2889        9549 :         if (!full && !W_ERROR_IS_OK(werr)) {
    2890        3303 :                 if (req10->mapping_ctr.num_mappings == 0) {
    2891             :                         /*
    2892             :                          * Despite the fact MS-DRSR specifies that this shouldn't
    2893             :                          * happen, Windows RODCs will in fact not provide a prefixMap.
    2894             :                          */
    2895        3303 :                         DEBUG(5,(__location__ ": Failed to provide a remote prefixMap,"
    2896             :                                  " falling back to local prefixMap\n"));
    2897             :                 } else {
    2898           0 :                         DEBUG(0,(__location__ ": Failed to decode remote prefixMap: %s\n",
    2899             :                                  win_errstr(werr)));
    2900           0 :                         return werr;
    2901             :                 }
    2902             :         }
    2903             : 
    2904             :         /* allowed if the GC PAS and client has
    2905             :            GUID_DRS_GET_FILTERED_ATTRIBUTES */
    2906        9549 :         werr = dcesrv_drsuapi_is_gc_pas_request(b_state, req10, pfm_remote, &is_gc_pas_request);
    2907        9549 :         if (!W_ERROR_IS_OK(werr)) {
    2908           3 :                 return werr;
    2909             :         }
    2910        9546 :         if (is_gc_pas_request) {
    2911          17 :                 werr = drs_security_access_check_nc_root(sam_ctx,
    2912             :                                                          mem_ctx,
    2913             :                                                          session_info->security_token,
    2914             :                                                          req10->naming_context,
    2915             :                                                          GUID_DRS_GET_FILTERED_ATTRIBUTES);
    2916          17 :                 if (W_ERROR_IS_OK(werr)) {
    2917           9 :                         goto allowed;
    2918             :                 }
    2919             :         }
    2920             : 
    2921        9537 :         werr = dcesrv_drsuapi_is_reveal_secrets_request(b_state, req10,
    2922             :                                                         pfm_remote,
    2923             :                                                         &is_secret_request);
    2924        9537 :         if (!W_ERROR_IS_OK(werr)) {
    2925           0 :                 return werr;
    2926             :         }
    2927        9537 :         if (is_secret_request) {
    2928        8664 :                 werr = drs_security_access_check_nc_root(sam_ctx,
    2929             :                                                          mem_ctx,
    2930             :                                                          session_info->security_token,
    2931             :                                                          req10->naming_context,
    2932             :                                                          GUID_DRS_GET_ALL_CHANGES);
    2933        8664 :                 if (!W_ERROR_IS_OK(werr)) {
    2934             :                         /* Only bail if this is not a EXOP_REPL_SECRET */
    2935        1363 :                         if (req10->extended_op != DRSUAPI_EXOP_REPL_SECRET) {
    2936          10 :                                 return werr;
    2937             :                         }
    2938             :                 } else {
    2939        7301 :                         has_get_all_changes = true;
    2940             :                 }
    2941             :         }
    2942             : 
    2943         873 : allowed:
    2944             :         /* for non-administrator replications, check that they have
    2945             :            given the correct source_dsa_invocation_id */
    2946        9536 :         security_level = security_session_user_level(session_info,
    2947             :                                                      samdb_domain_sid(sam_ctx));
    2948        9536 :         if (security_level == SECURITY_RO_DOMAIN_CONTROLLER) {
    2949        1954 :                 if (req10->replica_flags & DRSUAPI_DRS_WRIT_REP) {
    2950             :                         /* we rely on this flag being unset for RODC requests */
    2951           0 :                         req10->replica_flags &= ~DRSUAPI_DRS_WRIT_REP;
    2952             :                 }
    2953             :         }
    2954             : 
    2955        9536 :         if (req10->replica_flags & DRSUAPI_DRS_FULL_SYNC_PACKET) {
    2956             :                 /* Ignore the _in_ uptodateness vector*/
    2957           0 :                 req10->uptodateness_vector = NULL;
    2958             :         }
    2959             : 
    2960        9536 :         if (GUID_all_zero(&req10->source_dsa_invocation_id)) {
    2961        4395 :                 req10->source_dsa_invocation_id = invocation_id;
    2962             :         }
    2963             : 
    2964        9536 :         if (!GUID_equal(&req10->source_dsa_invocation_id, &invocation_id)) {
    2965             :                 /*
    2966             :                  * The given highwatermark is only valid relative to the
    2967             :                  * specified source_dsa_invocation_id.
    2968             :                  */
    2969           2 :                 ZERO_STRUCT(req10->highwatermark);
    2970             :         }
    2971             : 
    2972             :         /*
    2973             :          * An extended operation is "special single-response cycle"
    2974             :          * per MS-DRSR 4.1.10.1.1 "Start and Finish" so we don't need
    2975             :          * to guess if this is a continuation of any long-term
    2976             :          * state.
    2977             :          *
    2978             :          * Otherwise, maintain (including marking as stale, which is
    2979             :          * what the below is for) the replication state.
    2980             :          *
    2981             :          * Note that point 5 "The server implementation MAY declare
    2982             :          * the supplied values ... as too stale to use."  would allow
    2983             :          * resetting the state at almost any point, Microsoft Azure AD
    2984             :          * Connect will switch back and forth between a REPL_OBJ and a
    2985             :          * full replication, so we must not reset the statue during
    2986             :          * extended operations.
    2987             :          */
    2988        9536 :         if (req10->extended_op == DRSUAPI_EXOP_NONE &&
    2989        4894 :             b_state->getncchanges_full_repl_state != NULL) {
    2990             :                 /*
    2991             :                  * Knowing that this is not an extended operation, we
    2992             :                  * can access (and validate) the full replication
    2993             :                  * state
    2994             :                  */
    2995        2174 :                 getnc_state = b_state->getncchanges_full_repl_state;
    2996             :         }
    2997             : 
    2998             :         /* see if a previous replication has been abandoned */
    2999        9536 :         if (getnc_state != NULL) {
    3000           0 :                 struct ldb_dn *new_dn;
    3001        2174 :                 ret = drs_ObjectIdentifier_to_dn_and_nc_root(getnc_state,
    3002             :                                                              sam_ctx,
    3003             :                                                              untrusted_ncRoot,
    3004             :                                                              &new_dn,
    3005             :                                                              NULL);
    3006        2174 :                 if (ret != LDB_SUCCESS) {
    3007             :                         /*
    3008             :                          * This can't fail as we have done this above
    3009             :                          * implicitly but not got the DN out, but
    3010             :                          * print a good error message regardless just
    3011             :                          * in case.
    3012             :                          */
    3013           0 :                         DBG_ERR("Bad DN '%s' as Naming Context for GetNCChanges: %s\n",
    3014             :                                 drs_ObjectIdentifier_to_debug_string(mem_ctx, untrusted_ncRoot),
    3015             :                                 ldb_strerror(ret));
    3016           0 :                         return WERR_DS_DRA_INVALID_PARAMETER;
    3017             :                 }
    3018        2174 :                 if (ldb_dn_compare(new_dn, getnc_state->ncRoot_dn) != 0) {
    3019           9 :                         DEBUG(0,(__location__ ": DsGetNCChanges 2nd replication on different DN %s %s (last_dn %s)\n",
    3020             :                                  ldb_dn_get_linearized(new_dn),
    3021             :                                  ldb_dn_get_linearized(getnc_state->ncRoot_dn),
    3022             :                                  ldb_dn_get_linearized(getnc_state->last_dn)));
    3023           9 :                         TALLOC_FREE(getnc_state);
    3024           9 :                         b_state->getncchanges_full_repl_state = NULL;
    3025             :                 }
    3026             :         }
    3027             : 
    3028        9536 :         if (getnc_state != NULL) {
    3029        2165 :                 ret = drsuapi_DsReplicaHighWaterMark_cmp(&getnc_state->last_hwm,
    3030        2165 :                                                          &req10->highwatermark);
    3031        2165 :                 if (ret != 0) {
    3032          21 :                         DEBUG(0,(__location__ ": DsGetNCChanges 2nd replication "
    3033             :                                  "on DN %s %s highwatermark (last_dn %s)\n",
    3034             :                                  ldb_dn_get_linearized(getnc_state->ncRoot_dn),
    3035             :                                  (ret > 0) ? "older" : "newer",
    3036             :                                  ldb_dn_get_linearized(getnc_state->last_dn)));
    3037          21 :                         TALLOC_FREE(getnc_state);
    3038          21 :                         b_state->getncchanges_full_repl_state = NULL;
    3039             :                 }
    3040             :         }
    3041             : 
    3042             :          /*
    3043             :           * This is either a new replication cycle, or an extended
    3044             :           * operation.  A new cycle is triggered above by the
    3045             :           * TALLOC_FREE() which sets getnc_state to NULL.
    3046             :           */
    3047        9536 :         if (getnc_state == NULL) {
    3048        7392 :                 struct ldb_result *res = NULL;
    3049        7392 :                 const char *attrs[] = {
    3050             :                         "instanceType",
    3051             :                         "objectGuID",
    3052             :                         NULL
    3053             :                 };
    3054           0 :                 uint32_t nc_instanceType;
    3055           0 :                 struct ldb_dn *ncRoot_dn;
    3056             : 
    3057        7392 :                 ret = drs_ObjectIdentifier_to_dn_and_nc_root(mem_ctx,
    3058             :                                                              sam_ctx,
    3059             :                                                              untrusted_ncRoot,
    3060             :                                                              &ncRoot_dn,
    3061             :                                                              NULL);
    3062        7392 :                 if (ret != LDB_SUCCESS) {
    3063           8 :                         DBG_ERR("Bad DN '%s' as Naming Context or EXOP DN for GetNCChanges: %s\n",
    3064             :                                 drs_ObjectIdentifier_to_debug_string(mem_ctx, untrusted_ncRoot),
    3065             :                                 ldb_strerror(ret));
    3066           8 :                         return WERR_DS_DRA_BAD_DN;
    3067             :                 }
    3068             : 
    3069        7384 :                 ret = dsdb_search_dn(sam_ctx, mem_ctx, &res,
    3070             :                                      ncRoot_dn, attrs,
    3071             :                                      DSDB_SEARCH_SHOW_DELETED |
    3072             :                                      DSDB_SEARCH_SHOW_RECYCLED);
    3073        7384 :                 if (ret != LDB_SUCCESS) {
    3074           0 :                         DBG_WARNING("Failed to find ncRoot_dn %s\n",
    3075             :                                     ldb_dn_get_linearized(ncRoot_dn));
    3076           0 :                         return WERR_DS_DRA_BAD_DN;
    3077             :                 }
    3078        7384 :                 nc_instanceType = ldb_msg_find_attr_as_int(res->msgs[0],
    3079             :                                                            "instanceType",
    3080             :                                                            0);
    3081             : 
    3082        7384 :                 if (req10->extended_op != DRSUAPI_EXOP_NONE) {
    3083        4636 :                         r->out.ctr->ctr6.extended_ret = DRSUAPI_EXOP_ERR_SUCCESS;
    3084             :                 }
    3085             : 
    3086             :                 /*
    3087             :                  * This is the first replication cycle and it is
    3088             :                  * a good place to handle extended operations
    3089             :                  *
    3090             :                  * FIXME: we don't fully support extended operations yet
    3091             :                  */
    3092        7384 :                 switch (req10->extended_op) {
    3093        2748 :                 case DRSUAPI_EXOP_NONE:
    3094        2748 :                         if ((nc_instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0) {
    3095           0 :                                 const char *dn_str
    3096           5 :                                         = ldb_dn_get_linearized(ncRoot_dn);
    3097             : 
    3098           5 :                                 DBG_NOTICE("Rejecting full replication on "
    3099             :                                            "not NC %s\n", dn_str);
    3100             : 
    3101           5 :                                 return WERR_DS_CANT_FIND_EXPECTED_NC;
    3102             :                         }
    3103             : 
    3104        6038 :                         break;
    3105          41 :                 case DRSUAPI_EXOP_FSMO_RID_ALLOC:
    3106          41 :                         werr = getncchanges_rid_alloc(b_state, mem_ctx, req10, &r->out.ctr->ctr6, &search_dn);
    3107          41 :                         W_ERROR_NOT_OK_RETURN(werr);
    3108          41 :                         if (r->out.ctr->ctr6.extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
    3109           4 :                                 return WERR_OK;
    3110             :                         }
    3111          37 :                         break;
    3112        4403 :                 case DRSUAPI_EXOP_REPL_SECRET:
    3113        4403 :                         werr = getncchanges_repl_secret(b_state, mem_ctx, req10,
    3114             :                                                         user_sid,
    3115        4403 :                                                         &r->out.ctr->ctr6,
    3116             :                                                         has_get_all_changes,
    3117             :                                                         &machine_dn);
    3118        4403 :                         r->out.result = werr;
    3119        4403 :                         W_ERROR_NOT_OK_RETURN(werr);
    3120        3068 :                         break;
    3121          15 :                 case DRSUAPI_EXOP_FSMO_REQ_ROLE:
    3122          15 :                         werr = getncchanges_change_master(b_state, mem_ctx, req10, &r->out.ctr->ctr6);
    3123          15 :                         W_ERROR_NOT_OK_RETURN(werr);
    3124          15 :                         if (r->out.ctr->ctr6.extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
    3125           2 :                                 return WERR_OK;
    3126             :                         }
    3127          13 :                         break;
    3128           6 :                 case DRSUAPI_EXOP_FSMO_RID_REQ_ROLE:
    3129           6 :                         werr = getncchanges_change_master(b_state, mem_ctx, req10, &r->out.ctr->ctr6);
    3130           6 :                         W_ERROR_NOT_OK_RETURN(werr);
    3131           6 :                         if (r->out.ctr->ctr6.extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
    3132           0 :                                 return WERR_OK;
    3133             :                         }
    3134           6 :                         break;
    3135           4 :                 case DRSUAPI_EXOP_FSMO_REQ_PDC:
    3136           4 :                         werr = getncchanges_change_master(b_state, mem_ctx, req10, &r->out.ctr->ctr6);
    3137           4 :                         W_ERROR_NOT_OK_RETURN(werr);
    3138           4 :                         if (r->out.ctr->ctr6.extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
    3139           0 :                                 return WERR_OK;
    3140             :                         }
    3141           4 :                         break;
    3142         167 :                 case DRSUAPI_EXOP_REPL_OBJ:
    3143         167 :                         werr = getncchanges_repl_obj(b_state, mem_ctx, req10, user_sid, &r->out.ctr->ctr6);
    3144         167 :                         r->out.result = werr;
    3145         167 :                         W_ERROR_NOT_OK_RETURN(werr);
    3146         167 :                         break;
    3147             : 
    3148           0 :                 case DRSUAPI_EXOP_FSMO_ABANDON_ROLE:
    3149             : 
    3150           0 :                         DEBUG(0,(__location__ ": Request for DsGetNCChanges unsupported extended op 0x%x\n",
    3151             :                                  (unsigned)req10->extended_op));
    3152           0 :                         return WERR_DS_DRA_NOT_SUPPORTED;
    3153             :                 }
    3154             : 
    3155             :                 /*
    3156             :                  * Initialize the state, initially for the remainder
    3157             :                  * of this call (EXOPs)
    3158             :                  *
    3159             :                  * An extended operation is a "special single-response
    3160             :                  * cycle" per MS-DRSR 4.1.10.1.1 "Start and Finish"
    3161             :                  *
    3162             :                  */
    3163        6038 :                 getnc_state = talloc_zero(mem_ctx, struct drsuapi_getncchanges_state);
    3164        6038 :                 if (getnc_state == NULL) {
    3165           0 :                         return WERR_NOT_ENOUGH_MEMORY;
    3166             :                 }
    3167             : 
    3168        6038 :                 if (req10->extended_op == DRSUAPI_EXOP_NONE) {
    3169             :                         /*
    3170             :                          * Promote the memory to being a store of
    3171             :                          * long-term state that we will use over the
    3172             :                          * replication cycle for full replication
    3173             :                          * requests
    3174             :                          *
    3175             :                          * Store the state in a clearly named location
    3176             :                          * for pulling back only during full
    3177             :                          * replications
    3178             :                          */
    3179           0 :                         b_state->getncchanges_full_repl_state
    3180        2743 :                                 = talloc_steal(b_state, getnc_state);
    3181             :                 }
    3182             : 
    3183        6038 :                 getnc_state->ncRoot_dn = ncRoot_dn;
    3184        6038 :                 talloc_steal(getnc_state, ncRoot_dn);
    3185             : 
    3186        6038 :                 getnc_state->ncRoot_guid = samdb_result_guid(res->msgs[0],
    3187             :                                                              "objectGUID");
    3188             : 
    3189             :                 /* find out if we are to replicate Schema NC */
    3190        6038 :                 ret = ldb_dn_compare_base(ldb_get_schema_basedn(sam_ctx),
    3191             :                                           ncRoot_dn);
    3192        6038 :                 getnc_state->is_schema_nc = (0 == ret);
    3193             : 
    3194        6038 :                 TALLOC_FREE(res);
    3195             :         }
    3196             : 
    3197             :         /* we need the session key for encrypting password attributes */
    3198        8182 :         status = dcesrv_auth_session_key(dce_call, &session_key);
    3199        8182 :         if (!NT_STATUS_IS_OK(status)) {
    3200           0 :                 DEBUG(0,(__location__ ": Failed to get session key\n"));
    3201           0 :                 return WERR_DS_DRA_INTERNAL_ERROR;
    3202             :         }
    3203             : 
    3204             :         /* 
    3205             :            TODO: MS-DRSR section 4.1.10.1.1
    3206             :            Work out if this is the start of a new cycle */
    3207             : 
    3208        8182 :         if (getnc_state->guids == NULL) {
    3209           0 :                 const char *extra_filter;
    3210        6038 :                 struct ldb_result *search_res = NULL;
    3211           0 :                 static const struct drsuapi_DsReplicaCursorCtrEx empty_udv;
    3212        6038 :                 const struct drsuapi_DsReplicaCursorCtrEx *udv = NULL;
    3213             : 
    3214        6038 :                 extra_filter = lpcfg_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "drs", "object filter");
    3215             : 
    3216        6038 :                 if (req10->extended_op == DRSUAPI_EXOP_NONE) {
    3217        2743 :                         if (req10->uptodateness_vector != NULL) {
    3218        2070 :                                 udv = req10->uptodateness_vector;
    3219             :                         } else {
    3220         673 :                                 udv = &empty_udv;
    3221             :                         }
    3222             : 
    3223        2743 :                         getnc_state->min_usn = req10->highwatermark.highest_usn;
    3224        4072 :                         for (i = 0; i < udv->count; i++) {
    3225           0 :                                 bool match;
    3226        3351 :                                 const struct drsuapi_DsReplicaCursor *cur =
    3227        3351 :                                         &udv->cursors[i];
    3228             : 
    3229        3351 :                                 match = GUID_equal(&invocation_id,
    3230             :                                                    &cur->source_dsa_invocation_id);
    3231        3351 :                                 if (!match) {
    3232        1329 :                                         continue;
    3233             :                                 }
    3234        2022 :                                 if (cur->highest_usn > getnc_state->min_usn) {
    3235         441 :                                         getnc_state->min_usn = cur->highest_usn;
    3236             :                                 }
    3237        2022 :                                 break;
    3238             :                         }
    3239             :                 } else {
    3240             :                         /* We do not want REPL_SECRETS or REPL_SINGLE to return empty-handed */
    3241        3295 :                         udv = &empty_udv;
    3242        3295 :                         getnc_state->min_usn = 0;
    3243             :                 }
    3244             : 
    3245        6038 :                 getnc_state->max_usn = getnc_state->min_usn;
    3246             : 
    3247        6038 :                 getnc_state->final_udv = talloc_zero(getnc_state,
    3248             :                                         struct drsuapi_DsReplicaCursor2CtrEx);
    3249        6038 :                 if (getnc_state->final_udv == NULL) {
    3250           0 :                         return WERR_NOT_ENOUGH_MEMORY;
    3251             :                 }
    3252        6038 :                 werr = get_nc_changes_udv(sam_ctx, getnc_state->ncRoot_dn,
    3253             :                                           getnc_state->final_udv);
    3254        6038 :                 if (!W_ERROR_IS_OK(werr)) {
    3255           0 :                         return werr;
    3256             :                 }
    3257             : 
    3258        6038 :                 if (req10->extended_op == DRSUAPI_EXOP_NONE) {
    3259        2743 :                         werr = getncchanges_collect_objects(b_state, mem_ctx,
    3260             :                                                             getnc_state, req10,
    3261             :                                                             search_dn, extra_filter,
    3262             :                                                             &search_res);
    3263             :                 } else {
    3264        3295 :                         werr = getncchanges_collect_objects_exop(b_state, mem_ctx,
    3265             :                                                                  getnc_state, req10,
    3266        3295 :                                                                  &r->out.ctr->ctr6,
    3267             :                                                                  search_dn, extra_filter,
    3268             :                                                                  &search_res);
    3269             :                 }
    3270        6038 :                 W_ERROR_NOT_OK_RETURN(werr);
    3271             : 
    3272             :                 /* extract out the GUIDs list */
    3273        6038 :                 getnc_state->num_records = search_res ? search_res->count : 0;
    3274        6038 :                 getnc_state->guids = talloc_array(getnc_state, struct GUID, getnc_state->num_records);
    3275        6038 :                 W_ERROR_HAVE_NO_MEMORY(getnc_state->guids);
    3276             : 
    3277        6038 :                 changes = talloc_array(getnc_state,
    3278             :                                        struct drsuapi_changed_objects,
    3279             :                                        getnc_state->num_records);
    3280        6038 :                 W_ERROR_HAVE_NO_MEMORY(changes);
    3281             : 
    3282      696486 :                 for (i=0; i<getnc_state->num_records; i++) {
    3283      690448 :                         changes[i].dn = search_res->msgs[i]->dn;
    3284      690448 :                         changes[i].guid = samdb_result_guid(search_res->msgs[i], "objectGUID");
    3285      690448 :                         changes[i].usn = ldb_msg_find_attr_as_uint64(search_res->msgs[i], "uSNChanged", 0);
    3286             : 
    3287      690448 :                         if (changes[i].usn > getnc_state->max_usn) {
    3288       13299 :                                 getnc_state->max_usn = changes[i].usn;
    3289             :                         }
    3290             : 
    3291     1361786 :                         if (req10->extended_op == DRSUAPI_EXOP_NONE &&
    3292      671338 :                             GUID_equal(&changes[i].guid, &getnc_state->ncRoot_guid))
    3293             :                         {
    3294         727 :                                 getnc_state->send_nc_root_first = true;
    3295             :                         }
    3296             :                 }
    3297             : 
    3298        6038 :                 if (req10->extended_op == DRSUAPI_EXOP_NONE) {
    3299        2743 :                         getnc_state->is_get_anc =
    3300        2743 :                                 ((req10->replica_flags & DRSUAPI_DRS_GET_ANC) != 0);
    3301        2743 :                         if (getnc_state->is_get_anc
    3302         667 :                                 && lpcfg_parm_bool(dce_call->conn->dce_ctx->lp_ctx,
    3303             :                                                     NULL,
    3304             :                                                     "drs",
    3305             :                                                     "broken_samba_4.5_get_anc_emulation",
    3306             :                                                    false)) {
    3307           8 :                                 getnc_state->broken_samba_4_5_get_anc_emulation = true;
    3308             :                         }
    3309        2743 :                         if (lpcfg_parm_bool(dce_call->conn->dce_ctx->lp_ctx,
    3310             :                                              NULL,
    3311             :                                              "drs",
    3312             :                                              "get_tgt_support",
    3313             :                                              true)) {
    3314        2732 :                                 getnc_state->is_get_tgt =
    3315        2732 :                                         ((req10->more_flags & DRSUAPI_DRS_GET_TGT) != 0);
    3316             :                         }
    3317             :                 }
    3318             : 
    3319             :                 /* RID_ALLOC returns 3 objects in a fixed order */
    3320        6038 :                 if (req10->extended_op == DRSUAPI_EXOP_FSMO_RID_ALLOC) {
    3321             :                         /* Do nothing */
    3322        6001 :                 } else if (getnc_state->broken_samba_4_5_get_anc_emulation) {
    3323           8 :                         TYPESAFE_QSORT(changes,
    3324             :                                        getnc_state->num_records,
    3325             :                                        site_res_cmp_anc_order);
    3326             :                 } else {
    3327        5993 :                         TYPESAFE_QSORT(changes,
    3328             :                                        getnc_state->num_records,
    3329             :                                        site_res_cmp_usn_order);
    3330             :                 }
    3331             : 
    3332      696486 :                 for (i=0; i < getnc_state->num_records; i++) {
    3333      690448 :                         getnc_state->guids[i] = changes[i].guid;
    3334      690448 :                         if (GUID_all_zero(&getnc_state->guids[i])) {
    3335           0 :                                 DEBUG(2,("getncchanges: bad objectGUID from %s\n",
    3336             :                                          ldb_dn_get_linearized(search_res->msgs[i]->dn)));
    3337           0 :                                 return WERR_DS_DRA_INTERNAL_ERROR;
    3338             :                         }
    3339             :                 }
    3340             : 
    3341        6038 :                 getnc_state->final_hwm.tmp_highest_usn = getnc_state->max_usn;
    3342        6038 :                 getnc_state->final_hwm.reserved_usn = 0;
    3343        6038 :                 getnc_state->final_hwm.highest_usn = getnc_state->max_usn;
    3344             : 
    3345        6038 :                 talloc_free(search_res);
    3346        6038 :                 talloc_free(changes);
    3347             : 
    3348             :                 /*
    3349             :                  * when using GET_ANC or GET_TGT, cache the objects that have
    3350             :                  * been already sent, to avoid sending them multiple times
    3351             :                  */
    3352        6038 :                 if (getnc_state->is_get_anc || getnc_state->is_get_tgt) {
    3353         699 :                         DEBUG(3,("Using object cache, GET_ANC %u, GET_TGT %u\n",
    3354             :                                  getnc_state->is_get_anc,
    3355             :                                  getnc_state->is_get_tgt));
    3356             : 
    3357         699 :                         getnc_state->obj_cache = db_open_rbt(getnc_state);
    3358         699 :                         if (getnc_state->obj_cache == NULL) {
    3359           0 :                                 return WERR_NOT_ENOUGH_MEMORY;
    3360             :                         }
    3361             :                 }
    3362             :         }
    3363             : 
    3364        8182 :         if (req10->uptodateness_vector) {
    3365             :                 /* make sure its sorted */
    3366        2415 :                 TYPESAFE_QSORT(req10->uptodateness_vector->cursors,
    3367             :                                req10->uptodateness_vector->count,
    3368             :                                drsuapi_DsReplicaCursor_compare);
    3369             :         }
    3370             : 
    3371             :         /* Prefix mapping */
    3372        8182 :         schema = dsdb_get_schema(sam_ctx, mem_ctx);
    3373        8182 :         if (!schema) {
    3374           0 :                 DEBUG(0,("No schema in sam_ctx\n"));
    3375           0 :                 return WERR_DS_DRA_INTERNAL_ERROR;
    3376             :         }
    3377             : 
    3378        8182 :         r->out.ctr->ctr6.naming_context = talloc(mem_ctx, struct drsuapi_DsReplicaObjectIdentifier);
    3379        8182 :         if (r->out.ctr->ctr6.naming_context == NULL) {
    3380           0 :                 return WERR_NOT_ENOUGH_MEMORY;
    3381             :         }
    3382             : 
    3383             :         /*
    3384             :          * Match Windows and echo back the original values from the request, even if
    3385             :          * they say DummyDN for the string NC
    3386             :          */
    3387        8182 :         *r->out.ctr->ctr6.naming_context = *untrusted_ncRoot;
    3388             : 
    3389             :         /* find the SID if there is one */
    3390        8182 :         dsdb_find_sid_by_dn(sam_ctx, getnc_state->ncRoot_dn, &r->out.ctr->ctr6.naming_context->sid);
    3391             : 
    3392             :         /* Set GUID */
    3393        8182 :         r->out.ctr->ctr6.naming_context->guid = getnc_state->ncRoot_guid;
    3394             : 
    3395        8182 :         dsdb_get_oid_mappings_drsuapi(schema, true, mem_ctx, &ctr);
    3396        8182 :         r->out.ctr->ctr6.mapping_ctr = *ctr;
    3397             : 
    3398        8182 :         r->out.ctr->ctr6.source_dsa_guid = *(samdb_ntds_objectGUID(sam_ctx));
    3399        8182 :         r->out.ctr->ctr6.source_dsa_invocation_id = *(samdb_ntds_invocation_id(sam_ctx));
    3400             : 
    3401        8182 :         r->out.ctr->ctr6.old_highwatermark = req10->highwatermark;
    3402        8182 :         r->out.ctr->ctr6.new_highwatermark = req10->highwatermark;
    3403             : 
    3404             :         /*
    3405             :          * If the client has already set GET_TGT then we know they can handle
    3406             :          * receiving the linked attributes interleaved with the source objects
    3407             :          */
    3408        8182 :         if (getnc_state->is_get_tgt) {
    3409         423 :                 repl_chunk->immediate_link_sync = true;
    3410             :         }
    3411             : 
    3412        8182 :         if (req10->partial_attribute_set != NULL) {
    3413           0 :                 struct dsdb_syntax_ctx syntax_ctx;
    3414        3683 :                 uint32_t j = 0;
    3415             : 
    3416        3683 :                 dsdb_syntax_ctx_init(&syntax_ctx, sam_ctx, schema);
    3417        3683 :                 syntax_ctx.pfm_remote = pfm_remote;
    3418             : 
    3419        3683 :                 local_pas = talloc_array(b_state, uint32_t, req10->partial_attribute_set->num_attids);
    3420             : 
    3421      773730 :                 for (j = 0; j < req10->partial_attribute_set->num_attids; j++) {
    3422      770047 :                         getncchanges_attid_remote_to_local(schema,
    3423             :                                                            &syntax_ctx,
    3424      770047 :                                                            req10->partial_attribute_set->attids[j],
    3425      770047 :                                                            (enum drsuapi_DsAttributeId *)&local_pas[j],
    3426             :                                                            NULL);
    3427             :                 }
    3428             : 
    3429        3683 :                 TYPESAFE_QSORT(local_pas,
    3430             :                                req10->partial_attribute_set->num_attids,
    3431             :                                uint32_t_ptr_cmp);
    3432             :         }
    3433             : 
    3434             :         /*
    3435             :          * If we have the NC root in this replication, send it
    3436             :          * first regardless.  However, don't bump the USN now,
    3437             :          * treat it as if it was sent early due to GET_ANC
    3438             :          *
    3439             :          * This is triggered for each call, so every page of responses
    3440             :          * gets the NC root as the first object, up to the point where
    3441             :          * it naturally occurs in the replication.
    3442             :          */
    3443             : 
    3444        8182 :         if (getnc_state->send_nc_root_first) {
    3445        2020 :                 struct drsuapi_DsReplicaObjectListItemEx *new_objs = NULL;
    3446             : 
    3447        2020 :                 werr = getncchanges_add_ancestors(&getnc_state->ncRoot_guid,
    3448             :                                                   NULL, mem_ctx,
    3449             :                                                   sam_ctx, getnc_state,
    3450             :                                                   schema, &session_key,
    3451             :                                                   req10, local_pas,
    3452             :                                                   machine_dn, &new_objs);
    3453             : 
    3454        2020 :                 if (!W_ERROR_IS_OK(werr)) {
    3455           0 :                         return werr;
    3456             :                 }
    3457             : 
    3458        2020 :                 getncchanges_chunk_add_objects(repl_chunk, new_objs);
    3459             : 
    3460        2020 :                 DEBUG(8,(__location__ ": replicating NC root %s\n",
    3461             :                          ldb_dn_get_linearized(getnc_state->ncRoot_dn)));
    3462             :         }
    3463             : 
    3464             :         /*
    3465             :          * Check in case we're still processing the links from an object in the
    3466             :          * previous chunk. We want to send the links (and any targets needed)
    3467             :          * before moving on to the next object.
    3468             :          */
    3469        8182 :         if (getnc_state->is_get_tgt) {
    3470         423 :                 werr = getncchanges_chunk_add_la_targets(repl_chunk,
    3471             :                                                          getnc_state,
    3472             :                                                          getnc_state->la_idx,
    3473             :                                                          mem_ctx, sam_ctx,
    3474             :                                                          schema, &session_key,
    3475             :                                                          req10, local_pas,
    3476             :                                                          machine_dn);
    3477             : 
    3478         423 :                 if (!W_ERROR_IS_OK(werr)) {
    3479           0 :                         return werr;
    3480             :                 }
    3481             :         }
    3482             : 
    3483        8182 :         for (i=getnc_state->num_processed;
    3484      659686 :              i<getnc_state->num_records &&
    3485      653460 :                      !getncchanges_chunk_is_full(repl_chunk, getnc_state);
    3486      651504 :             i++) {
    3487      651504 :                 struct drsuapi_DsReplicaObjectListItemEx *new_objs = NULL;
    3488           0 :                 struct ldb_message *msg;
    3489           0 :                 static const char * const msg_attrs[] = {
    3490             :                                             "*",
    3491             :                                             "nTSecurityDescriptor",
    3492             :                                             "parentGUID",
    3493             :                                             "replPropertyMetaData",
    3494             :                                             DSDB_SECRET_ATTRIBUTES,
    3495             :                                             NULL };
    3496           0 :                 struct ldb_result *msg_res;
    3497           0 :                 struct ldb_dn *msg_dn;
    3498      651504 :                 bool obj_already_sent = false;
    3499      651504 :                 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
    3500           0 :                 uint32_t old_la_index;
    3501             : 
    3502             :                 /*
    3503             :                  * Once we get to the 'natural' place to send the NC
    3504             :                  * root, stop sending it at the front of each reply
    3505             :                  * and make sure to suppress sending it now
    3506             :                  *
    3507             :                  * We don't just 'continue' here as we must send links
    3508             :                  * and unlike Windows we want to update the
    3509             :                  * tmp_highest_usn
    3510             :                  */
    3511             : 
    3512     1087545 :                 if (getnc_state->send_nc_root_first &&
    3513      436041 :                     GUID_equal(&getnc_state->guids[i], &getnc_state->ncRoot_guid))
    3514             :                 {
    3515         711 :                         getnc_state->send_nc_root_first = false;
    3516         711 :                         obj_already_sent = true;
    3517             :                 }
    3518             : 
    3519      651504 :                 msg_dn = ldb_dn_new_fmt(tmp_ctx, sam_ctx, "<GUID=%s>",
    3520      651504 :                                         GUID_string(tmp_ctx, &getnc_state->guids[i]));
    3521      651504 :                 W_ERROR_HAVE_NO_MEMORY(msg_dn);
    3522             : 
    3523             :                 /*
    3524             :                  * by re-searching here we avoid having a lot of full
    3525             :                  * records in memory between calls to getncchanges.
    3526             :                  *
    3527             :                  * We expect that we may get some objects that vanish
    3528             :                  * (tombstone expunge) between the first and second
    3529             :                  * check.
    3530             :                  */
    3531      651504 :                 ret = drsuapi_search_with_extended_dn(sam_ctx, tmp_ctx, &msg_res,
    3532             :                                                       msg_dn,
    3533             :                                                       LDB_SCOPE_BASE, msg_attrs, NULL);
    3534      651504 :                 if (ret != LDB_SUCCESS) {
    3535           0 :                         if (ret != LDB_ERR_NO_SUCH_OBJECT) {
    3536           0 :                                 DEBUG(1,("getncchanges: failed to fetch DN %s - %s\n",
    3537             :                                          ldb_dn_get_extended_linearized(tmp_ctx, msg_dn, 1),
    3538             :                                          ldb_errstring(sam_ctx)));
    3539             :                         }
    3540           0 :                         TALLOC_FREE(tmp_ctx);
    3541           0 :                         continue;
    3542             :                 }
    3543             : 
    3544      651504 :                 if (msg_res->count == 0) {
    3545           0 :                         DEBUG(1,("getncchanges: got LDB_SUCCESS but failed"
    3546             :                                  "to get any results in fetch of DN "
    3547             :                                  "%s (race with tombstone expunge?)\n",
    3548             :                                  ldb_dn_get_extended_linearized(tmp_ctx,
    3549             :                                                                 msg_dn, 1)));
    3550           0 :                         TALLOC_FREE(tmp_ctx);
    3551           0 :                         continue;
    3552             :                 }
    3553             : 
    3554      651504 :                 msg = msg_res->msgs[0];
    3555             : 
    3556             :                 /*
    3557             :                  * Check if we've already sent the object as an ancestor of
    3558             :                  * another object. If so, we don't need to send it again
    3559             :                  */
    3560      651504 :                 if (getnc_state->obj_cache != NULL) {
    3561      456382 :                         werr = dcesrv_drsuapi_obj_cache_exists(getnc_state->obj_cache,
    3562      456382 :                                                                &getnc_state->guids[i]);
    3563      456382 :                         if (W_ERROR_EQUAL(werr, WERR_OBJECT_NAME_EXISTS)) {
    3564        3096 :                                 obj_already_sent = true;
    3565             :                         }
    3566             :                 }
    3567             : 
    3568      651504 :                 if (!obj_already_sent) {
    3569           0 :                         bool max_wait_reached;
    3570             : 
    3571      648190 :                         max_wait_reached = getncchanges_chunk_timed_out(repl_chunk);
    3572             : 
    3573             :                         /*
    3574             :                          * Construct an object, ready to send (this will include
    3575             :                          * the object's ancestors as well, if needed)
    3576             :                          */
    3577      648190 :                         werr = getncchanges_get_obj_to_send(msg, mem_ctx, sam_ctx,
    3578             :                                                             getnc_state, schema,
    3579             :                                                             &session_key, req10,
    3580             :                                                             max_wait_reached,
    3581             :                                                             local_pas, machine_dn,
    3582      648190 :                                                             &getnc_state->guids[i],
    3583             :                                                             &new_objs);
    3584      648190 :                         if (!W_ERROR_IS_OK(werr)) {
    3585           0 :                                 return werr;
    3586             :                         }
    3587             :                 }
    3588             : 
    3589      651504 :                 old_la_index = getnc_state->la_count;
    3590             : 
    3591             :                 /*
    3592             :                  * We've reached the USN where this object naturally occurs.
    3593             :                  * Regardless of whether we've already sent the object (as an
    3594             :                  * ancestor), we add its links and update the HWM at this point
    3595             :                  */
    3596      651504 :                 werr = get_nc_changes_add_links(sam_ctx, getnc_state,
    3597      651504 :                                                 getnc_state->is_schema_nc,
    3598             :                                                 schema, getnc_state->min_usn,
    3599             :                                                 req10->replica_flags,
    3600             :                                                 msg,
    3601             :                                                 &getnc_state->la_list,
    3602             :                                                 &getnc_state->la_count,
    3603             :                                                 req10->uptodateness_vector);
    3604      651504 :                 if (!W_ERROR_IS_OK(werr)) {
    3605           0 :                         return werr;
    3606             :                 }
    3607             : 
    3608      651504 :                 dcesrv_drsuapi_update_highwatermark(msg,
    3609             :                                         getnc_state->max_usn,
    3610      651504 :                                         &r->out.ctr->ctr6.new_highwatermark);
    3611             : 
    3612      651504 :                 if (new_objs != NULL) {
    3613             : 
    3614             :                         /*
    3615             :                          * Add the object (and, if GET_ANC, any parents it may
    3616             :                          * have) into the current chunk of replication data
    3617             :                          */
    3618      572196 :                         getncchanges_chunk_add_objects(repl_chunk, new_objs);
    3619             : 
    3620      572196 :                         talloc_free(getnc_state->last_dn);
    3621             :                         /*
    3622             :                          * talloc_steal() as we still need msg->dn to
    3623             :                          * be a valid pointer for the log on the next
    3624             :                          * line.
    3625             :                          *
    3626             :                          * msg only remains in scope for the next 25
    3627             :                          * lines or so anyway.
    3628             :                          */
    3629      572196 :                         getnc_state->last_dn = talloc_steal(getnc_state, msg->dn);
    3630             :                 }
    3631             : 
    3632      651504 :                 DEBUG(8,(__location__ ": %s object %s new tmp_highest_usn=%" PRIu64 "\n",
    3633             :                          new_objs ? "replicating" : "skipping send of",
    3634             :                          ldb_dn_get_linearized(msg->dn),
    3635             :                          r->out.ctr->ctr6.new_highwatermark.tmp_highest_usn));
    3636             : 
    3637      651504 :                 getnc_state->total_links += (getnc_state->la_count - old_la_index);
    3638             : 
    3639             :                 /*
    3640             :                  * If the GET_TGT flag was set, check any new links added to
    3641             :                  * make sure the client knows about the link target object
    3642             :                  */
    3643      651504 :                 if (getnc_state->is_get_tgt) {
    3644      110086 :                         werr = getncchanges_chunk_add_la_targets(repl_chunk,
    3645             :                                                                  getnc_state,
    3646             :                                                                  old_la_index,
    3647             :                                                                  mem_ctx, sam_ctx,
    3648             :                                                                  schema, &session_key,
    3649             :                                                                  req10, local_pas,
    3650             :                                                                  machine_dn);
    3651             : 
    3652      110086 :                         if (!W_ERROR_IS_OK(werr)) {
    3653           0 :                                 return werr;
    3654             :                         }
    3655             :                 }
    3656             : 
    3657      651504 :                 TALLOC_FREE(tmp_ctx);
    3658             :         }
    3659             : 
    3660             :         /* copy the constructed object list into the response message */
    3661        8182 :         r->out.ctr->ctr6.object_count = repl_chunk->object_count;
    3662        8182 :         r->out.ctr->ctr6.first_object = repl_chunk->object_list;
    3663             : 
    3664        8182 :         getnc_state->num_processed = i;
    3665             : 
    3666        8182 :         if (i < getnc_state->num_records) {
    3667        1956 :                 r->out.ctr->ctr6.more_data = true;
    3668             :         }
    3669             : 
    3670             :         /* the client can us to call UpdateRefs on its behalf to
    3671             :            re-establish monitoring of the NC */
    3672        8182 :         if ((req10->replica_flags & (DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_REF_GCSPN)) &&
    3673        1273 :             !GUID_all_zero(&req10->destination_dsa_guid)) {
    3674           0 :                 struct drsuapi_DsReplicaUpdateRefsRequest1 ureq;
    3675        1273 :                 DEBUG(3,("UpdateRefs on getncchanges for %s\n",
    3676             :                          GUID_string(mem_ctx, &req10->destination_dsa_guid)));
    3677             : 
    3678             :                 /*
    3679             :                  * We pass the pre-validation NC root here as
    3680             :                  * drsuapi_UpdateRefs() has to check its own input
    3681             :                  * values due to being called from
    3682             :                  * dcesrv_drsuapi_DsReplicaUpdateRefs()
    3683             :                  */
    3684             : 
    3685        1273 :                 ureq.naming_context = untrusted_ncRoot;
    3686        2546 :                 ureq.dest_dsa_dns_name = samdb_ntds_msdcs_dns_name(sam_ctx, mem_ctx,
    3687        1273 :                                                                    &req10->destination_dsa_guid);
    3688        1273 :                 if (!ureq.dest_dsa_dns_name) {
    3689           0 :                         return WERR_NOT_ENOUGH_MEMORY;
    3690             :                 }
    3691        1273 :                 ureq.dest_dsa_guid = req10->destination_dsa_guid;
    3692        1273 :                 ureq.options = DRSUAPI_DRS_ADD_REF |
    3693             :                         DRSUAPI_DRS_ASYNC_OP |
    3694             :                         DRSUAPI_DRS_GETCHG_CHECK;
    3695             : 
    3696             :                 /* we also need to pass through the
    3697             :                    DRSUAPI_DRS_REF_GCSPN bit so that repsTo gets flagged
    3698             :                    to send notifies using the GC SPN */
    3699        1273 :                 ureq.options |= (req10->replica_flags & DRSUAPI_DRS_REF_GCSPN);
    3700             : 
    3701        1273 :                 werr = drsuapi_UpdateRefs(imsg_ctx,
    3702             :                                           dce_call->event_ctx,
    3703             :                                           b_state,
    3704             :                                           mem_ctx,
    3705             :                                           &ureq);
    3706        1273 :                 if (!W_ERROR_IS_OK(werr)) {
    3707           0 :                         DEBUG(0,(__location__ ": Failed UpdateRefs on %s for %s in DsGetNCChanges - %s\n",
    3708             :                                  drs_ObjectIdentifier_to_debug_string(mem_ctx, untrusted_ncRoot),
    3709             :                                  ureq.dest_dsa_dns_name,
    3710             :                                  win_errstr(werr)));
    3711             :                 }
    3712             :         }
    3713             : 
    3714             :         /*
    3715             :          * Work out how many links we can send in this chunk. The default is to
    3716             :          * send all the links last, but there is a config option to send them
    3717             :          * immediately, in the same chunk as their source object
    3718             :          */
    3719        8182 :         if (!r->out.ctr->ctr6.more_data || repl_chunk->immediate_link_sync) {
    3720        6996 :                 link_count = getncchanges_chunk_links_pending(repl_chunk,
    3721             :                                                               getnc_state);
    3722        6996 :                 link_count = MIN(link_count,
    3723             :                                  getncchanges_chunk_max_links(repl_chunk));
    3724             :         }
    3725             : 
    3726             :         /* If we've got linked attributes to send, add them now */
    3727        8182 :         if (link_count > 0) {
    3728           0 :                 struct la_for_sorting *la_sorted;
    3729             : 
    3730             :                 /*
    3731             :                  * Grab a chunk of linked attributes off the list and put them
    3732             :                  * in sorted array, ready to send
    3733             :                  */
    3734        2225 :                 werr = getncchanges_get_sorted_array(&getnc_state->la_list[getnc_state->la_idx],
    3735             :                                                      link_count,
    3736             :                                                      sam_ctx, getnc_state,
    3737             :                                                      schema,
    3738             :                                                      &la_sorted);
    3739        2225 :                 if (!W_ERROR_IS_OK(werr)) {
    3740           0 :                         return werr;
    3741             :                 }
    3742             : 
    3743        2225 :                 r->out.ctr->ctr6.linked_attributes_count = link_count;
    3744        2225 :                 r->out.ctr->ctr6.linked_attributes = talloc_array(r->out.ctr, struct drsuapi_DsReplicaLinkedAttribute, link_count);
    3745        2225 :                 if (r->out.ctr->ctr6.linked_attributes == NULL) {
    3746           0 :                         DEBUG(0, ("Out of memory allocating %u linked attributes for output\n", link_count));
    3747           0 :                         return WERR_NOT_ENOUGH_MEMORY;
    3748             :                 }
    3749             : 
    3750       23841 :                 for (k = 0; k < link_count; k++) {
    3751       21616 :                         r->out.ctr->ctr6.linked_attributes[k] = *la_sorted[k].link;
    3752             :                 }
    3753             : 
    3754        2225 :                 getnc_state->la_idx += link_count;
    3755        2225 :                 getnc_state->links_given += link_count;
    3756             : 
    3757        2225 :                 if (getnc_state->la_idx < getnc_state->la_count) {
    3758         252 :                         r->out.ctr->ctr6.more_data = true;
    3759             :                 } else {
    3760             : 
    3761             :                         /*
    3762             :                          * We've now sent all the links seen so far, so we can
    3763             :                          * reset la_list back to an empty list again. Note that
    3764             :                          * the steal means the linked attribute memory gets
    3765             :                          * freed after this RPC message is sent on the wire.
    3766             :                          */
    3767        1973 :                         talloc_steal(mem_ctx, getnc_state->la_list);
    3768        1973 :                         getnc_state->la_list = NULL;
    3769        1973 :                         getnc_state->la_idx = 0;
    3770        1973 :                         getnc_state->la_count = 0;
    3771             :                 }
    3772             : 
    3773        2225 :                 TALLOC_FREE(la_sorted);
    3774             :         }
    3775             : 
    3776        8182 :         if (req10->replica_flags & DRSUAPI_DRS_GET_NC_SIZE) {
    3777             :                 /*
    3778             :                  * TODO: This implementation is wrong
    3779             :                  * we should find out the total number of
    3780             :                  * objects and links in the whole naming context
    3781             :                  * at the start of the cycle and return these
    3782             :                  * values in each message.
    3783             :                  *
    3784             :                  * For now we keep our current strategy and return
    3785             :                  * the number of objects for this cycle and the number
    3786             :                  * of links we found so far during the cycle.
    3787             :                  */
    3788        1530 :                 r->out.ctr->ctr6.nc_object_count = getnc_state->num_records;
    3789        1530 :                 r->out.ctr->ctr6.nc_linked_attributes_count = getnc_state->total_links;
    3790             :         }
    3791             : 
    3792        8182 :         if (req10->extended_op != DRSUAPI_EXOP_NONE) {
    3793        3295 :                 r->out.ctr->ctr6.uptodateness_vector = NULL;
    3794        3295 :                 r->out.ctr->ctr6.nc_object_count = 0;
    3795        3295 :                 ZERO_STRUCT(r->out.ctr->ctr6.new_highwatermark);
    3796        4887 :         } else if (!r->out.ctr->ctr6.more_data) {
    3797             : 
    3798             :                 /* this is the last response in the replication cycle */
    3799        2697 :                 r->out.ctr->ctr6.new_highwatermark = getnc_state->final_hwm;
    3800        2697 :                 r->out.ctr->ctr6.uptodateness_vector = talloc_move(mem_ctx,
    3801             :                                                                    &getnc_state->final_udv);
    3802             : 
    3803             :                 /*
    3804             :                  * Free the state info stored for the replication cycle. Note
    3805             :                  * that the RPC message we're sending contains links stored in
    3806             :                  * getnc_state. mem_ctx is local to this RPC call, so the memory
    3807             :                  * will get freed after the RPC message is sent on the wire.
    3808             :                  *
    3809             :                  * We must not do this for an EXOP, as that should not
    3810             :                  * end the replication state, which is why that is
    3811             :                  * checked first above.
    3812             :                  */
    3813        2697 :                 talloc_steal(mem_ctx, getnc_state);
    3814        2697 :                 b_state->getncchanges_full_repl_state = NULL;
    3815             :         } else {
    3816        2190 :                 ret = drsuapi_DsReplicaHighWaterMark_cmp(&r->out.ctr->ctr6.old_highwatermark,
    3817        2190 :                                                          &r->out.ctr->ctr6.new_highwatermark);
    3818        2190 :                 if (ret == 0) {
    3819             :                         /*
    3820             :                          * We need to make sure that we never return the
    3821             :                          * same highwatermark within the same replication
    3822             :                          * cycle more than once. Otherwise we cannot detect
    3823             :                          * when the client uses an unexpected highwatermark.
    3824             :                          *
    3825             :                          * This is a HACK which is needed because our
    3826             :                          * object ordering is wrong and set tmp_highest_usn
    3827             :                          * to a value that is higher than what we already
    3828             :                          * sent to the client (destination dsa).
    3829             :                          */
    3830         358 :                         r->out.ctr->ctr6.new_highwatermark.reserved_usn += 1;
    3831             :                 }
    3832             : 
    3833        2190 :                 getnc_state->last_hwm = r->out.ctr->ctr6.new_highwatermark;
    3834             :         }
    3835             : 
    3836        8182 :         TALLOC_FREE(repl_chunk);
    3837             : 
    3838        8182 :         DEBUG(r->out.ctr->ctr6.more_data?4:2,
    3839             :               ("DsGetNCChanges with uSNChanged >= %llu flags 0x%08x on %s gave %u objects (done %u/%u) %u links (done %u/%u (as %s))\n",
    3840             :                (unsigned long long)(req10->highwatermark.highest_usn+1),
    3841             :                req10->replica_flags,
    3842             :                drs_ObjectIdentifier_to_debug_string(mem_ctx, untrusted_ncRoot),
    3843             :                r->out.ctr->ctr6.object_count,
    3844             :                i, r->out.ctr->ctr6.more_data?getnc_state->num_records:i,
    3845             :                r->out.ctr->ctr6.linked_attributes_count,
    3846             :                getnc_state->links_given, getnc_state->total_links,
    3847             :                dom_sid_string(mem_ctx, user_sid)));
    3848             : 
    3849             : #if 0
    3850             :         if (!r->out.ctr->ctr6.more_data && req10->extended_op != DRSUAPI_EXOP_NONE) {
    3851             :                 NDR_PRINT_FUNCTION_DEBUG(drsuapi_DsGetNCChanges, NDR_BOTH, r);
    3852             :         }
    3853             : #endif
    3854             : 
    3855        8182 :         return WERR_OK;
    3856             : }
    3857             : 

Generated by: LCOV version 1.14