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

Generated by: LCOV version 1.14