LCOV - code coverage report
Current view: top level - source4/dsdb/repl - replicated_objects.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 367 594 61.8 %
Date: 2024-02-28 12:06:22 Functions: 9 9 100.0 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS Implementation.
       3             :    Helper functions for applying replicated objects
       4             :    
       5             :    Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
       6             :     
       7             :    This program is free software; you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation; either version 3 of the License, or
      10             :    (at your option) any later version.
      11             :    
      12             :    This program is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             :    
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             :    
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include "dsdb/samdb/samdb.h"
      24             : #include <ldb_errors.h>
      25             : #include "../lib/util/dlinklist.h"
      26             : #include "librpc/gen_ndr/ndr_misc.h"
      27             : #include "librpc/gen_ndr/ndr_drsuapi.h"
      28             : #include "librpc/gen_ndr/ndr_drsblobs.h"
      29             : #include "../libcli/drsuapi/drsuapi.h"
      30             : #include "libcli/auth/libcli_auth.h"
      31             : #include "param/param.h"
      32             : 
      33             : #undef DBGC_CLASS
      34             : #define DBGC_CLASS            DBGC_DRS_REPL
      35             : 
      36         132 : static WERROR dsdb_repl_merge_working_schema(struct ldb_context *ldb,
      37             :                                              struct dsdb_schema *dest_schema,
      38             :                                              const struct dsdb_schema *ref_schema)
      39             : {
      40         132 :         const struct dsdb_class *cur_class = NULL;
      41         132 :         const struct dsdb_attribute *cur_attr = NULL;
      42           0 :         int ret;
      43             : 
      44         132 :         for (cur_class = ref_schema->classes;
      45       15264 :              cur_class;
      46       15132 :              cur_class = cur_class->next)
      47             :         {
      48           0 :                 const struct dsdb_class *tmp1;
      49           0 :                 struct dsdb_class *tmp2;
      50             : 
      51       15132 :                 tmp1 = dsdb_class_by_governsID_id(dest_schema,
      52       15132 :                                                   cur_class->governsID_id);
      53       15132 :                 if (tmp1 != NULL) {
      54       14336 :                         continue;
      55             :                 }
      56             : 
      57             :                 /*
      58             :                  * Do a shallow copy so that original next and prev are
      59             :                  * not modified, we don't need to do a deep copy
      60             :                  * as the rest won't be modified and this is for
      61             :                  * a short lived object.
      62             :                  */
      63         796 :                 tmp2 = talloc(dest_schema, struct dsdb_class);
      64         796 :                 if (tmp2 == NULL) {
      65           0 :                         return WERR_NOT_ENOUGH_MEMORY;
      66             :                 }
      67         796 :                 *tmp2 = *cur_class;
      68         796 :                 DLIST_ADD(dest_schema->classes, tmp2);
      69             :         }
      70             : 
      71         132 :         for (cur_attr = ref_schema->attributes;
      72       84184 :              cur_attr;
      73       84052 :              cur_attr = cur_attr->next)
      74             :         {
      75           0 :                 const struct dsdb_attribute *tmp1;
      76           0 :                 struct dsdb_attribute *tmp2;
      77             : 
      78       84052 :                 tmp1 = dsdb_attribute_by_attributeID_id(dest_schema,
      79       84052 :                                                 cur_attr->attributeID_id);
      80       84052 :                 if (tmp1 != NULL) {
      81       82488 :                         continue;
      82             :                 }
      83             : 
      84             :                 /*
      85             :                  * Do a shallow copy so that original next and prev are
      86             :                  * not modified, we don't need to do a deep copy
      87             :                  * as the rest won't be modified and this is for
      88             :                  * a short lived object.
      89             :                  */
      90        1564 :                 tmp2 = talloc(dest_schema, struct dsdb_attribute);
      91        1564 :                 if (tmp2 == NULL) {
      92           0 :                         return WERR_NOT_ENOUGH_MEMORY;
      93             :                 }
      94        1564 :                 *tmp2 = *cur_attr;
      95        1564 :                 DLIST_ADD(dest_schema->attributes, tmp2);
      96             :         }
      97             : 
      98         132 :         ret = dsdb_setup_sorted_accessors(ldb, dest_schema);
      99         132 :         if (LDB_SUCCESS != ret) {
     100           0 :                 DEBUG(0,("Failed to add new attribute to reference schema!\n"));
     101           0 :                 return WERR_INTERNAL_ERROR;
     102             :         }
     103             : 
     104         132 :         return WERR_OK;
     105             : }
     106             : 
     107         135 : WERROR dsdb_repl_resolve_working_schema(struct ldb_context *ldb,
     108             :                                         struct dsdb_schema_prefixmap *pfm_remote,
     109             :                                         uint32_t cycle_before_switching,
     110             :                                         struct dsdb_schema *initial_schema,
     111             :                                         struct dsdb_schema *resulting_schema,
     112             :                                         uint32_t object_count,
     113             :                                         const struct drsuapi_DsReplicaObjectListItemEx *first_object)
     114             : {
     115           0 :         struct schema_list {
     116             :                 struct schema_list *next, *prev;
     117             :                 const struct drsuapi_DsReplicaObjectListItemEx *obj;
     118             :         };
     119         135 :         struct schema_list *schema_list = NULL, *schema_list_item, *schema_list_next_item;
     120           0 :         WERROR werr;
     121           0 :         struct dsdb_schema *working_schema;
     122           0 :         const struct drsuapi_DsReplicaObjectListItemEx *cur;
     123         135 :         DATA_BLOB empty_key = data_blob_null;
     124           0 :         int ret, pass_no;
     125         135 :         uint32_t ignore_attids[] = {
     126             :                         DRSUAPI_ATTID_auxiliaryClass,
     127             :                         DRSUAPI_ATTID_mayContain,
     128             :                         DRSUAPI_ATTID_mustContain,
     129             :                         DRSUAPI_ATTID_possSuperiors,
     130             :                         DRSUAPI_ATTID_systemPossSuperiors,
     131             :                         DRSUAPI_ATTID_INVALID
     132             :         };
     133         135 :         TALLOC_CTX *frame = talloc_stackframe();
     134             : 
     135             :         /* create a list of objects yet to be converted */
     136      131592 :         for (cur = first_object; cur; cur = cur->next_object) {
     137      131457 :                 schema_list_item = talloc(frame, struct schema_list);
     138      131457 :                 if (schema_list_item == NULL) {
     139           0 :                         return WERR_NOT_ENOUGH_MEMORY;
     140             :                 }
     141             : 
     142      131457 :                 schema_list_item->obj = cur;
     143      131457 :                 DLIST_ADD_END(schema_list, schema_list_item);
     144             :         }
     145             : 
     146             :         /* resolve objects until all are resolved and in local schema */
     147         135 :         pass_no = 1;
     148         135 :         working_schema = initial_schema;
     149             : 
     150         359 :         while (schema_list) {
     151         224 :                 uint32_t converted_obj_count = 0;
     152         224 :                 uint32_t failed_obj_count = 0;
     153             : 
     154         224 :                 if (resulting_schema != working_schema) {
     155             :                         /*
     156             :                          * If the selfmade schema is not the schema used to
     157             :                          * translate and validate replicated object,
     158             :                          * Which means that we are using the bootstrap schema
     159             :                          * Then we add attributes and classes that were already
     160             :                          * translated to the working schema, the idea is that
     161             :                          * we might need to add new attributes and classes
     162             :                          * to be able to translate critical replicated objects
     163             :                          * and without that we wouldn't be able to translate them
     164             :                          */
     165         132 :                         werr = dsdb_repl_merge_working_schema(ldb,
     166             :                                                         working_schema,
     167             :                                                         resulting_schema);
     168         132 :                         if (!W_ERROR_IS_OK(werr)) {
     169           0 :                                 talloc_free(frame);
     170           0 :                                 return werr;
     171             :                         }
     172             :                 }
     173             : 
     174         224 :                 for (schema_list_item = schema_list;
     175      132353 :                      schema_list_item;
     176      132129 :                      schema_list_item=schema_list_next_item) {
     177           0 :                         struct dsdb_extended_replicated_object object;
     178             : 
     179      132129 :                         cur = schema_list_item->obj;
     180             : 
     181             :                         /*
     182             :                          * Save the next item, now we have saved out
     183             :                          * the current one, so we can DLIST_REMOVE it
     184             :                          * safely
     185             :                          */
     186      132129 :                         schema_list_next_item = schema_list_item->next;
     187             : 
     188             :                         /*
     189             :                          * Convert the objects into LDB messages using the
     190             :                          * schema we have so far. It's ok if we fail to convert
     191             :                          * an object. We should convert more objects on next pass.
     192             :                          */
     193      132129 :                         werr = dsdb_convert_object_ex(ldb, working_schema,
     194             :                                                       NULL,
     195             :                                                       pfm_remote,
     196             :                                                       cur, &empty_key,
     197             :                                                       ignore_attids,
     198             :                                                       0,
     199             :                                                       schema_list_item, &object);
     200      132129 :                         if (!W_ERROR_IS_OK(werr)) {
     201         672 :                                 DEBUG(4,("debug: Failed to convert schema "
     202             :                                          "object %s into ldb msg, "
     203             :                                          "will try during next loop\n",
     204             :                                          cur->object.identifier->dn));
     205             : 
     206         672 :                                 failed_obj_count++;
     207             :                         } else {
     208             :                                 /*
     209             :                                  * Convert the schema from ldb_message format
     210             :                                  * (OIDs as OID strings) into schema, using
     211             :                                  * the remote prefixMap
     212             :                                  *
     213             :                                  * It's not likely, but possible to get the
     214             :                                  * same object twice and we should keep
     215             :                                  * the last instance.
     216             :                                  */
     217      131457 :                                 werr = dsdb_schema_set_el_from_ldb_msg_dups(ldb,
     218             :                                                                 resulting_schema,
     219             :                                                                 object.msg,
     220             :                                                                 true);
     221      131457 :                                 if (!W_ERROR_IS_OK(werr)) {
     222           0 :                                         DEBUG(4,("debug: failed to convert "
     223             :                                                  "object %s into a schema element, "
     224             :                                                  "will try during next loop: %s\n",
     225             :                                                  ldb_dn_get_linearized(object.msg->dn),
     226             :                                                  win_errstr(werr)));
     227           0 :                                         failed_obj_count++;
     228             :                                 } else {
     229      131457 :                                         DEBUG(8,("Converted object %s into a schema element\n",
     230             :                                                  ldb_dn_get_linearized(object.msg->dn)));
     231      131457 :                                         DLIST_REMOVE(schema_list, schema_list_item);
     232      131457 :                                         TALLOC_FREE(schema_list_item);
     233      131457 :                                         converted_obj_count++;
     234             :                                 }
     235             :                         }
     236             :                 }
     237             : 
     238         224 :                 DEBUG(4,("Schema load pass %d: converted %d, %d of %d objects left to be converted.\n",
     239             :                          pass_no, converted_obj_count, failed_obj_count, object_count));
     240             : 
     241             :                 /* check if we converted any objects in this pass */
     242         224 :                 if (converted_obj_count == 0) {
     243           0 :                         DEBUG(0,("Can't continue Schema load: "
     244             :                                  "didn't manage to convert any objects: "
     245             :                                  "all %d remaining of %d objects "
     246             :                                  "failed to convert\n",
     247             :                                  failed_obj_count, object_count));
     248           0 :                         talloc_free(frame);
     249           0 :                         return WERR_INTERNAL_ERROR;
     250             :                 }
     251             : 
     252             :                 /*
     253             :                  * Don't try to load the schema if there is missing object
     254             :                  * _and_ we are on the first pass as some critical objects
     255             :                  * might be missing.
     256             :                  */
     257         224 :                 if (failed_obj_count == 0 || pass_no > cycle_before_switching) {
     258             :                         /* prepare for another cycle */
     259         168 :                         working_schema = resulting_schema;
     260             : 
     261         168 :                         ret = dsdb_setup_sorted_accessors(ldb, working_schema);
     262         168 :                         if (LDB_SUCCESS != ret) {
     263           0 :                                 DEBUG(0,("Failed to create schema-cache indexes!\n"));
     264           0 :                                 talloc_free(frame);
     265           0 :                                 return WERR_INTERNAL_ERROR;
     266             :                         }
     267             :                 }
     268         224 :                 pass_no++;
     269             :         }
     270             : 
     271         135 :         talloc_free(frame);
     272         135 :         return WERR_OK;
     273             : }
     274             : 
     275             : /**
     276             :  * Multi-pass working schema creation
     277             :  * Function will:
     278             :  *  - shallow copy initial schema supplied
     279             :  *  - create a working schema in multiple passes
     280             :  *    until all objects are resolved
     281             :  * Working schema is a schema with Attributes, Classes
     282             :  * and indexes, but w/o subClassOf, possibleSupperiors etc.
     283             :  * It is to be used just us cache for converting attribute values.
     284             :  */
     285          59 : WERROR dsdb_repl_make_working_schema(struct ldb_context *ldb,
     286             :                                      const struct dsdb_schema *initial_schema,
     287             :                                      const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr,
     288             :                                      uint32_t object_count,
     289             :                                      const struct drsuapi_DsReplicaObjectListItemEx *first_object,
     290             :                                      const DATA_BLOB *gensec_skey,
     291             :                                      TALLOC_CTX *mem_ctx,
     292             :                                      struct dsdb_schema **_schema_out)
     293             : {
     294           0 :         WERROR werr;
     295           0 :         struct dsdb_schema_prefixmap *pfm_remote;
     296           0 :         uint32_t r;
     297           0 :         struct dsdb_schema *working_schema;
     298             : 
     299             :         /* make a copy of the iniatial_scheam so we don't mess with it */
     300          59 :         working_schema = dsdb_schema_copy_shallow(mem_ctx, ldb, initial_schema);
     301          59 :         if (!working_schema) {
     302           0 :                 DEBUG(0,(__location__ ": schema copy failed!\n"));
     303           0 :                 return WERR_NOT_ENOUGH_MEMORY;
     304             :         }
     305          59 :         working_schema->resolving_in_progress = true;
     306             : 
     307             :         /* we are going to need remote prefixMap for decoding */
     308          59 :         werr = dsdb_schema_pfm_from_drsuapi_pfm(mapping_ctr, true,
     309             :                                                 working_schema, &pfm_remote, NULL);
     310          59 :         if (!W_ERROR_IS_OK(werr)) {
     311           0 :                 DEBUG(0,(__location__ ": Failed to decode remote prefixMap: %s\n",
     312             :                          win_errstr(werr)));
     313           0 :                 talloc_free(working_schema);
     314           0 :                 return werr;
     315             :         }
     316             : 
     317        3745 :         for (r=0; r < pfm_remote->length; r++) {
     318        3686 :                 const struct dsdb_schema_prefixmap_oid *rm = &pfm_remote->prefixes[r];
     319        3686 :                 bool found_oid = false;
     320           0 :                 uint32_t l;
     321             : 
     322      122946 :                 for (l=0; l < working_schema->prefixmap->length; l++) {
     323      122806 :                         const struct dsdb_schema_prefixmap_oid *lm = &working_schema->prefixmap->prefixes[l];
     324           0 :                         int cmp;
     325             : 
     326      122806 :                         cmp = data_blob_cmp(&rm->bin_oid, &lm->bin_oid);
     327      122806 :                         if (cmp == 0) {
     328        3546 :                                 found_oid = true;
     329        3546 :                                 break;
     330             :                         }
     331             :                 }
     332             : 
     333        3686 :                 if (found_oid) {
     334        3546 :                         continue;
     335             :                 }
     336             : 
     337             :                 /*
     338             :                  * We prefer the same is as we got from the remote peer
     339             :                  * if there's no conflict.
     340             :                  */
     341         140 :                 werr = dsdb_schema_pfm_add_entry(working_schema->prefixmap,
     342             :                                                  rm->bin_oid, &rm->id, NULL);
     343         140 :                 if (!W_ERROR_IS_OK(werr)) {
     344           0 :                         DEBUG(0,(__location__ ": Failed to merge remote prefixMap: %s\n",
     345             :                                  win_errstr(werr)));
     346           0 :                         talloc_free(working_schema);
     347           0 :                         return werr;
     348             :                 }
     349             :         }
     350             : 
     351          59 :         werr = dsdb_repl_resolve_working_schema(ldb,
     352             :                                                 pfm_remote,
     353             :                                                 0, /* cycle_before_switching */
     354             :                                                 working_schema,
     355             :                                                 working_schema,
     356             :                                                 object_count,
     357             :                                                 first_object);
     358          59 :         if (!W_ERROR_IS_OK(werr)) {
     359           0 :                 DEBUG(0, ("%s: dsdb_repl_resolve_working_schema() failed: %s\n",
     360             :                           __location__, win_errstr(werr)));
     361           0 :                 talloc_free(working_schema);
     362           0 :                 return werr;
     363             :         }
     364             : 
     365          59 :         working_schema->resolving_in_progress = false;
     366             : 
     367          59 :         *_schema_out = working_schema;
     368             : 
     369          59 :         return WERR_OK;
     370             : }
     371             : 
     372     9645233 : static bool dsdb_attid_in_list(const uint32_t attid_list[], uint32_t attid)
     373             : {
     374           0 :         const uint32_t *cur;
     375     9645233 :         if (!attid_list) {
     376     7058120 :                 return false;
     377             :         }
     378    15477155 :         for (cur = attid_list; *cur != DRSUAPI_ATTID_INVALID; cur++) {
     379    12915519 :                 if (*cur == attid) {
     380       25477 :                         return true;
     381             :                 }
     382             :         }
     383     2561636 :         return false;
     384             : }
     385             : 
     386      632514 : WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
     387             :                               const struct dsdb_schema *schema,
     388             :                               struct ldb_dn *partition_dn,
     389             :                               const struct dsdb_schema_prefixmap *pfm_remote,
     390             :                               const struct drsuapi_DsReplicaObjectListItemEx *in,
     391             :                               const DATA_BLOB *gensec_skey,
     392             :                               const uint32_t *ignore_attids,
     393             :                               uint32_t dsdb_repl_flags,
     394             :                               TALLOC_CTX *mem_ctx,
     395             :                               struct dsdb_extended_replicated_object *out)
     396             : {
     397      632514 :         WERROR status = WERR_OK;
     398           0 :         uint32_t i;
     399           0 :         struct ldb_message *msg;
     400           0 :         struct replPropertyMetaDataBlob *md;
     401           0 :         int instanceType;
     402      632514 :         struct ldb_message_element *instanceType_e = NULL;
     403      632514 :         NTTIME whenChanged = 0;
     404           0 :         time_t whenChanged_t;
     405           0 :         const char *whenChanged_s;
     406      632514 :         struct dom_sid *sid = NULL;
     407      632514 :         uint32_t rid = 0;
     408           0 :         uint32_t attr_count;
     409             : 
     410      632514 :         if (!in->object.identifier) {
     411           0 :                 return WERR_FOOBAR;
     412             :         }
     413             : 
     414      632514 :         if (!in->object.identifier->dn || !in->object.identifier->dn[0]) {
     415           0 :                 return WERR_FOOBAR;
     416             :         }
     417             : 
     418      632514 :         if (in->object.attribute_ctr.num_attributes != 0 && !in->meta_data_ctr) {
     419           0 :                 return WERR_FOOBAR;
     420             :         }
     421             : 
     422      632514 :         if (in->object.attribute_ctr.num_attributes != in->meta_data_ctr->count) {
     423           0 :                 return WERR_FOOBAR;
     424             :         }
     425             : 
     426      632514 :         sid = &in->object.identifier->sid;
     427      632514 :         if (sid->num_auths > 0) {
     428       74153 :                 rid = sid->sub_auths[sid->num_auths - 1];
     429             :         }
     430             : 
     431      632514 :         msg = ldb_msg_new(mem_ctx);
     432      632514 :         W_ERROR_HAVE_NO_MEMORY(msg);
     433             : 
     434      632514 :         msg->dn                      = ldb_dn_new(msg, ldb, in->object.identifier->dn);
     435      632514 :         W_ERROR_HAVE_NO_MEMORY(msg->dn);
     436             : 
     437      632514 :         msg->num_elements    = in->object.attribute_ctr.num_attributes;
     438      632514 :         msg->elements                = talloc_array(msg, struct ldb_message_element,
     439             :                                                msg->num_elements);
     440      632514 :         W_ERROR_HAVE_NO_MEMORY(msg->elements);
     441             : 
     442      632514 :         md = talloc(mem_ctx, struct replPropertyMetaDataBlob);
     443      632514 :         W_ERROR_HAVE_NO_MEMORY(md);
     444             : 
     445      632514 :         md->version          = 1;
     446      632514 :         md->reserved         = 0;
     447      632514 :         md->ctr.ctr1.count   = in->meta_data_ctr->count;
     448      632514 :         md->ctr.ctr1.reserved        = 0;
     449      632514 :         md->ctr.ctr1.array   = talloc_array(mem_ctx,
     450             :                                                struct replPropertyMetaData1,
     451             :                                                md->ctr.ctr1.count);
     452      632514 :         W_ERROR_HAVE_NO_MEMORY(md->ctr.ctr1.array);
     453             : 
     454    10277075 :         for (i=0, attr_count=0; i < in->meta_data_ctr->count; i++, attr_count++) {
     455           0 :                 struct drsuapi_DsReplicaAttribute *a;
     456           0 :                 struct drsuapi_DsReplicaMetaData *d;
     457           0 :                 struct replPropertyMetaData1 *m;
     458           0 :                 struct ldb_message_element *e;
     459           0 :                 uint32_t j;
     460             : 
     461     9645233 :                 a = &in->object.attribute_ctr.attributes[i];
     462     9645233 :                 d = &in->meta_data_ctr->meta_data[i];
     463     9645233 :                 m = &md->ctr.ctr1.array[attr_count];
     464     9645233 :                 e = &msg->elements[attr_count];
     465             : 
     466     9645233 :                 if (dsdb_attid_in_list(ignore_attids, a->attid)) {
     467       25477 :                         attr_count--;
     468       25477 :                         continue;
     469             :                 }
     470             : 
     471     9619756 :                 if (GUID_all_zero(&d->originating_invocation_id)) {
     472           0 :                         status = WERR_DS_SRC_GUID_MISMATCH;
     473           0 :                         DEBUG(0, ("Refusing replication of object containing invalid zero invocationID on attribute %d of %s: %s\n",
     474             :                                   a->attid,
     475             :                                   ldb_dn_get_linearized(msg->dn),
     476             :                                   win_errstr(status)));
     477           0 :                         return status;
     478             :                 }
     479             : 
     480     9619756 :                 if (a->attid == DRSUAPI_ATTID_instanceType) {
     481      632488 :                         if (instanceType_e != NULL) {
     482           0 :                                 return WERR_FOOBAR;
     483             :                         }
     484      632488 :                         instanceType_e = e;
     485             :                 }
     486             : 
     487    20730054 :                 for (j=0; j<a->value_ctr.num_values; j++) {
     488    11110298 :                         status = drsuapi_decrypt_attribute(a->value_ctr.values[j].blob,
     489             :                                                            gensec_skey, rid,
     490             :                                                            dsdb_repl_flags, a);
     491    11110298 :                         if (!W_ERROR_IS_OK(status)) {
     492           0 :                                 break;
     493             :                         }
     494             :                 }
     495     9619756 :                 if (W_ERROR_EQUAL(status, WERR_TOO_MANY_SECRETS)) {
     496           0 :                         WERROR get_name_status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, pfm_remote,
     497           0 :                                                                                a, msg->elements, e, NULL);
     498           0 :                         if (W_ERROR_IS_OK(get_name_status)) {
     499           0 :                                 DEBUG(0, ("Unxpectedly got secret value %s on %s from DRS server\n",
     500             :                                           e->name, ldb_dn_get_linearized(msg->dn)));
     501             :                         } else {
     502           0 :                                 DEBUG(0, ("Unxpectedly got secret value on %s from DRS server\n",
     503             :                                           ldb_dn_get_linearized(msg->dn)));
     504             :                         }
     505     9619756 :                 } else if (!W_ERROR_IS_OK(status)) {
     506           0 :                         return status;
     507             :                 }
     508             : 
     509             :                 /*
     510             :                  * This function also fills in the local attid value,
     511             :                  * based on comparing the remote and local prefixMap
     512             :                  * tables.  If we don't convert the value, then we can
     513             :                  * have invalid values in the replPropertyMetaData we
     514             :                  * store on disk, as the prefixMap is per host, not
     515             :                  * per-domain.  This may be why Microsoft added the
     516             :                  * msDS-IntID feature, however this is not used for
     517             :                  * extra attributes in the schema partition itself.
     518             :                  */
     519     9619756 :                 status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, pfm_remote,
     520     9619756 :                                                        a, msg->elements, e,
     521             :                                                        &m->attid);
     522     9619756 :                 W_ERROR_NOT_OK_RETURN(status);
     523             : 
     524     9619084 :                 m->version                   = d->version;
     525     9619084 :                 m->originating_change_time   = d->originating_change_time;
     526     9619084 :                 m->originating_invocation_id = d->originating_invocation_id;
     527     9619084 :                 m->originating_usn           = d->originating_usn;
     528     9619084 :                 m->local_usn                 = 0;
     529             : 
     530     9619084 :                 if (a->attid == DRSUAPI_ATTID_name) {
     531      631516 :                         const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
     532      631516 :                         if (rdn_val == NULL) {
     533           0 :                                 DEBUG(0, ("Unxpectedly unable to get RDN from %s for validation\n",
     534             :                                           ldb_dn_get_linearized(msg->dn)));
     535           0 :                                 return WERR_FOOBAR;
     536             :                         }
     537      631516 :                         if (e->num_values != 1) {
     538           0 :                                 DEBUG(0, ("Unxpectedly got wrong number of attribute values (got %u, expected 1) when checking RDN against name of %s\n",
     539             :                                           e->num_values,
     540             :                                           ldb_dn_get_linearized(msg->dn)));
     541           0 :                                 return WERR_FOOBAR;
     542             :                         }
     543      631516 :                         if (data_blob_cmp(rdn_val,
     544      631516 :                                           &e->values[0]) != 0) {
     545           0 :                                 DEBUG(0, ("Unxpectedly got mismatching RDN values when checking RDN against name of %s\n",
     546             :                                           ldb_dn_get_linearized(msg->dn)));
     547           0 :                                 return WERR_FOOBAR;
     548             :                         }
     549             :                 }
     550     9619084 :                 if (d->originating_change_time > whenChanged) {
     551      764974 :                         whenChanged = d->originating_change_time;
     552             :                 }
     553             : 
     554             :         }
     555             : 
     556      631842 :         msg->num_elements = attr_count;
     557      631842 :         md->ctr.ctr1.count = attr_count;
     558             : 
     559      631842 :         if (instanceType_e == NULL) {
     560           0 :                 return WERR_FOOBAR;
     561             :         }
     562             : 
     563      631842 :         instanceType = ldb_msg_find_attr_as_int(msg, "instanceType", 0);
     564             : 
     565      631842 :         if ((instanceType & INSTANCE_TYPE_IS_NC_HEAD)
     566         943 :             && partition_dn != NULL) {
     567         811 :                 int partition_dn_cmp = ldb_dn_compare(partition_dn, msg->dn);
     568         811 :                 if (partition_dn_cmp != 0) {
     569           0 :                         DEBUG(4, ("Remote server advised us of a new partition %s while processing %s, ignoring\n",
     570             :                                   ldb_dn_get_linearized(msg->dn),
     571             :                                   ldb_dn_get_linearized(partition_dn)));
     572           0 :                         return WERR_DS_ADD_REPLICA_INHIBITED;
     573             :                 }
     574             :         }
     575             : 
     576      631842 :         if (dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
     577             :                 /* the instanceType type for partial_replica
     578             :                    replication is sent via DRS with TYPE_WRITE set, but
     579             :                    must be used on the client with TYPE_WRITE removed
     580             :                 */
     581       15280 :                 if (instanceType & INSTANCE_TYPE_WRITE) {
     582             :                         /*
     583             :                          * Make sure we do not change the order
     584             :                          * of msg->elements!
     585             :                          *
     586             :                          * That's why we use
     587             :                          * instanceType_e->num_values = 0
     588             :                          * instead of
     589             :                          * ldb_msg_remove_attr(msg, "instanceType");
     590             :                          */
     591           0 :                         struct ldb_message_element *e;
     592             : 
     593       15280 :                         e = ldb_msg_find_element(msg, "instanceType");
     594       15280 :                         if (e != instanceType_e) {
     595           0 :                                 DEBUG(0,("instanceType_e[%p] changed to e[%p]\n",
     596             :                                          instanceType_e, e));
     597           0 :                                 return WERR_FOOBAR;
     598             :                         }
     599             : 
     600       15280 :                         instanceType_e->num_values = 0;
     601             : 
     602       15280 :                         instanceType &= ~INSTANCE_TYPE_WRITE;
     603       15280 :                         if (ldb_msg_add_fmt(msg, "instanceType", "%d", instanceType) != LDB_SUCCESS) {
     604           0 :                                 return WERR_INTERNAL_ERROR;
     605             :                         }
     606             :                 }
     607             :         } else {
     608      616562 :                 if (!(instanceType & INSTANCE_TYPE_WRITE)) {
     609           0 :                         DBG_ERR("Refusing to replicate %s from a read-only "
     610             :                                 "replica into a read-write replica!\n",
     611             :                                 ldb_dn_get_linearized(msg->dn));
     612           0 :                         return WERR_DS_DRA_SOURCE_IS_PARTIAL_REPLICA;
     613             :                 }
     614             :         }
     615             : 
     616      631842 :         whenChanged_t = nt_time_to_unix(whenChanged);
     617      631842 :         whenChanged_s = ldb_timestring(msg, whenChanged_t);
     618      631842 :         W_ERROR_HAVE_NO_MEMORY(whenChanged_s);
     619             : 
     620      631842 :         out->object_guid = in->object.identifier->guid;
     621             : 
     622      631842 :         if (in->parent_object_guid == NULL) {
     623         943 :                 out->parent_guid = NULL;
     624             :         } else {
     625      630899 :                 out->parent_guid = talloc(mem_ctx, struct GUID);
     626      630899 :                 W_ERROR_HAVE_NO_MEMORY(out->parent_guid);
     627      630899 :                 *out->parent_guid = *in->parent_object_guid;
     628             :         }
     629             : 
     630      631842 :         out->msg             = msg;
     631      631842 :         out->when_changed    = whenChanged_s;
     632      631842 :         out->meta_data               = md;
     633      631842 :         return WERR_OK;
     634             : }
     635             : 
     636        3831 : WERROR dsdb_replicated_objects_convert(struct ldb_context *ldb,
     637             :                                        const struct dsdb_schema *schema,
     638             :                                        struct ldb_dn *partition_dn,
     639             :                                        const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr,
     640             :                                        uint32_t object_count,
     641             :                                        const struct drsuapi_DsReplicaObjectListItemEx *first_object,
     642             :                                        uint32_t linked_attributes_count,
     643             :                                        const struct drsuapi_DsReplicaLinkedAttribute *linked_attributes,
     644             :                                        const struct repsFromTo1 *source_dsa,
     645             :                                        const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector,
     646             :                                        const DATA_BLOB *gensec_skey,
     647             :                                        uint32_t dsdb_repl_flags,
     648             :                                        TALLOC_CTX *mem_ctx,
     649             :                                        struct dsdb_extended_replicated_objects **objects)
     650             : {
     651           0 :         WERROR status;
     652           0 :         struct dsdb_schema_prefixmap *pfm_remote;
     653           0 :         struct dsdb_extended_replicated_objects *out;
     654           0 :         const struct drsuapi_DsReplicaObjectListItemEx *cur;
     655           0 :         struct dsdb_syntax_ctx syntax_ctx;
     656           0 :         uint32_t i;
     657             : 
     658        3831 :         out = talloc_zero(mem_ctx, struct dsdb_extended_replicated_objects);
     659        3831 :         W_ERROR_HAVE_NO_MEMORY(out);
     660        3831 :         out->version         = DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION;
     661        3831 :         out->dsdb_repl_flags    = dsdb_repl_flags;
     662             : 
     663             :         /*
     664             :          * Ensure schema is kept valid for as long as 'out'
     665             :          * which may contain pointers to it
     666             :          */
     667        3831 :         schema = talloc_reference(out, schema);
     668        3831 :         W_ERROR_HAVE_NO_MEMORY(schema);
     669             : 
     670        3831 :         status = dsdb_schema_pfm_from_drsuapi_pfm(mapping_ctr, true,
     671             :                                                   out, &pfm_remote, NULL);
     672        3831 :         if (!W_ERROR_IS_OK(status)) {
     673           0 :                 DEBUG(0,(__location__ ": Failed to decode remote prefixMap: %s\n",
     674             :                          win_errstr(status)));
     675           0 :                 talloc_free(out);
     676           0 :                 return status;
     677             :         }
     678             : 
     679             :         /* use default syntax conversion context */
     680        3831 :         dsdb_syntax_ctx_init(&syntax_ctx, ldb, schema);
     681        3831 :         syntax_ctx.pfm_remote = pfm_remote;
     682             : 
     683        3831 :         if (ldb_dn_compare(partition_dn, ldb_get_schema_basedn(ldb)) != 0) {
     684             :                 /*
     685             :                  * check for schema changes in case
     686             :                  * we are not replicating Schema NC
     687             :                  */
     688        3629 :                 status = dsdb_schema_info_cmp(schema, mapping_ctr);
     689        3629 :                 if (!W_ERROR_IS_OK(status)) {
     690           7 :                         DEBUG(4,("Can't replicate %s because remote schema has changed since we last replicated the schema\n",
     691             :                                  ldb_dn_get_linearized(partition_dn)));
     692           7 :                         talloc_free(out);
     693           7 :                         return status;
     694             :                 }
     695             :         }
     696             : 
     697        3824 :         out->partition_dn    = partition_dn;
     698             : 
     699        3824 :         out->source_dsa              = source_dsa;
     700        3824 :         out->uptodateness_vector= uptodateness_vector;
     701             : 
     702        3824 :         out->num_objects     = 0;
     703        3824 :         out->objects         = talloc_array(out,
     704             :                                                struct dsdb_extended_replicated_object,
     705             :                                                object_count);
     706        3824 :         W_ERROR_HAVE_NO_MEMORY_AND_FREE(out->objects, out);
     707             : 
     708      504209 :         for (i=0, cur = first_object; cur; cur = cur->next_object, i++) {
     709      500385 :                 if (i == object_count) {
     710           0 :                         talloc_free(out);
     711           0 :                         return WERR_FOOBAR;
     712             :                 }
     713             : 
     714      500385 :                 status = dsdb_convert_object_ex(ldb, schema, out->partition_dn,
     715             :                                                 pfm_remote,
     716             :                                                 cur, gensec_skey,
     717             :                                                 NULL,
     718             :                                                 dsdb_repl_flags,
     719      500385 :                                                 out->objects,
     720      500385 :                                                 &out->objects[out->num_objects]);
     721             : 
     722             :                 /*
     723             :                  * Check to see if we have been advised of a
     724             :                  * subdomain or new application partition.  We don't
     725             :                  * want to start on that here, instead the caller
     726             :                  * should consider if it would like to replicate it
     727             :                  * based on the cross-ref object.
     728             :                  */
     729      500385 :                 if (W_ERROR_EQUAL(status, WERR_DS_ADD_REPLICA_INHIBITED)) {
     730           0 :                         struct GUID_txt_buf guid_str;
     731           0 :                         DBG_ERR("Ignoring object outside partition %s %s: %s\n",
     732             :                                 GUID_buf_string(&cur->object.identifier->guid,
     733             :                                                 &guid_str),
     734             :                                 cur->object.identifier->dn,
     735             :                                 win_errstr(status));
     736           0 :                         continue;
     737             :                 }
     738             : 
     739      500385 :                 if (!W_ERROR_IS_OK(status)) {
     740           0 :                         talloc_free(out);
     741           0 :                         DEBUG(0,("Failed to convert object %s: %s\n",
     742             :                                  cur->object.identifier->dn,
     743             :                                  win_errstr(status)));
     744           0 :                         return status;
     745             :                 }
     746             : 
     747             :                 /* Assuming we didn't skip or error, increment the number of objects */
     748      500385 :                 out->num_objects++;
     749             :         }
     750             : 
     751        3824 :         DBG_INFO("Processed %"PRIu32" DRS objects, saw %"PRIu32" objects "
     752             :                  "and expected %"PRIu32" objects\n",
     753             :                  out->num_objects, i, object_count);
     754             : 
     755        3824 :         out->objects = talloc_realloc(out, out->objects,
     756             :                                       struct dsdb_extended_replicated_object,
     757             :                                       out->num_objects);
     758        3824 :         if (out->num_objects != 0 && out->objects == NULL) {
     759           0 :                 DBG_ERR("FAILURE: talloc_realloc() failed after "
     760             :                         "processing %"PRIu32" DRS objects!\n",
     761             :                         out->num_objects);
     762           0 :                 talloc_free(out);
     763           0 :                 return WERR_FOOBAR;
     764             :         }
     765        3824 :         if (i != object_count) {
     766           0 :                 DBG_ERR("FAILURE: saw %"PRIu32" DRS objects, server said we "
     767             :                         "should expect to see %"PRIu32" objects!\n",
     768             :                         i, object_count);
     769           0 :                 talloc_free(out);
     770           0 :                 return WERR_FOOBAR;
     771             :         }
     772             : 
     773        3824 :         out->linked_attributes = talloc_array(out,
     774             :                                               struct drsuapi_DsReplicaLinkedAttribute,
     775             :                                               linked_attributes_count);
     776        3824 :         W_ERROR_HAVE_NO_MEMORY_AND_FREE(out->linked_attributes, out);
     777             : 
     778       18201 :         for (i=0; i < linked_attributes_count; i++) {
     779       14377 :                 const struct drsuapi_DsReplicaLinkedAttribute *ra = &linked_attributes[i];
     780       14377 :                 struct drsuapi_DsReplicaLinkedAttribute *la = &out->linked_attributes[i];
     781             : 
     782       14377 :                 if (ra->identifier == NULL) {
     783           0 :                         talloc_free(out);
     784           0 :                         return WERR_BAD_NET_RESP;
     785             :                 }
     786             : 
     787       14377 :                 *la = *ra;
     788             : 
     789       14377 :                 la->identifier = talloc_zero(out->linked_attributes,
     790             :                                              struct drsuapi_DsReplicaObjectIdentifier);
     791       14377 :                 W_ERROR_HAVE_NO_MEMORY_AND_FREE(la->identifier, out);
     792             : 
     793             :                 /*
     794             :                  * We typically only get the guid filled
     795             :                  * and the repl_meta_data module only cares abouf
     796             :                  * the guid.
     797             :                  */
     798       14377 :                 la->identifier->guid = ra->identifier->guid;
     799             : 
     800       14377 :                 if (ra->value.blob != NULL) {
     801       14377 :                         la->value.blob = talloc_zero(out->linked_attributes,
     802             :                                                      DATA_BLOB);
     803       14377 :                         W_ERROR_HAVE_NO_MEMORY_AND_FREE(la->value.blob, out);
     804             : 
     805       14377 :                         if (ra->value.blob->length != 0) {
     806       14377 :                                 *la->value.blob = data_blob_dup_talloc(la->value.blob,
     807             :                                                                        *ra->value.blob);
     808       14377 :                                 W_ERROR_HAVE_NO_MEMORY_AND_FREE(la->value.blob->data, out);
     809             :                         }
     810             :                 }
     811             : 
     812       14377 :                 status = dsdb_attribute_drsuapi_remote_to_local(&syntax_ctx,
     813       14377 :                                                                 ra->attid,
     814             :                                                                 &la->attid,
     815             :                                                                 NULL);
     816       14377 :                 if (!W_ERROR_IS_OK(status)) {
     817           0 :                         DEBUG(0,(__location__": linked_attribute[%u] attid 0x%08X not found: %s\n",
     818             :                                  i, ra->attid, win_errstr(status)));
     819           0 :                         return status;
     820             :                 }
     821             :         }
     822             : 
     823        3824 :         out->linked_attributes_count = linked_attributes_count;
     824             : 
     825             :         /* free pfm_remote, we won't need it anymore */
     826        3824 :         talloc_free(pfm_remote);
     827             : 
     828        3824 :         *objects = out;
     829        3824 :         return WERR_OK;
     830             : }
     831             : 
     832             : /**
     833             :  * Commits a list of replicated objects.
     834             :  *
     835             :  * @param working_schema dsdb_schema to be used for resolving
     836             :  *                       Classes/Attributes during Schema replication. If not NULL,
     837             :  *                       it will be set on ldb and used while committing replicated objects
     838             :  */
     839        3794 : WERROR dsdb_replicated_objects_commit(struct ldb_context *ldb,
     840             :                                       struct dsdb_schema *working_schema,
     841             :                                       struct dsdb_extended_replicated_objects *objects,
     842             :                                       uint64_t *notify_uSN)
     843             : {
     844           0 :         WERROR werr;
     845           0 :         struct ldb_result *ext_res;
     846        3794 :         struct dsdb_schema *cur_schema = NULL;
     847        3794 :         struct dsdb_schema *new_schema = NULL;
     848           0 :         int ret;
     849           0 :         uint64_t seq_num1, seq_num2;
     850        3794 :         bool used_global_schema = false;
     851             : 
     852        3794 :         TALLOC_CTX *tmp_ctx = talloc_new(objects);
     853        3794 :         if (!tmp_ctx) {
     854           0 :                 DEBUG(0,("Failed to start talloc\n"));
     855           0 :                 return WERR_NOT_ENOUGH_MEMORY;
     856             :         }
     857             : 
     858             :         /* wrap the extended operation in a transaction 
     859             :            See [MS-DRSR] 3.3.2 Transactions
     860             :          */
     861        3794 :         ret = ldb_transaction_start(ldb);
     862        3794 :         if (ret != LDB_SUCCESS) {
     863           0 :                 DEBUG(0,(__location__ " Failed to start transaction: %s\n",
     864             :                          ldb_errstring(ldb)));
     865           0 :                 return WERR_FOOBAR;
     866             :         }
     867             : 
     868        3794 :         ret = dsdb_load_partition_usn(ldb, objects->partition_dn, &seq_num1, NULL);
     869        3794 :         if (ret != LDB_SUCCESS) {
     870           0 :                 DEBUG(0,(__location__ " Failed to load partition uSN\n"));
     871           0 :                 ldb_transaction_cancel(ldb);
     872           0 :                 TALLOC_FREE(tmp_ctx);
     873           0 :                 return WERR_FOOBAR;             
     874             :         }
     875             : 
     876             :         /*
     877             :          * Set working_schema for ldb in case we are replicating from Schema NC.
     878             :          * Schema won't be reloaded during Replicated Objects commit, as it is
     879             :          * done in a transaction. So we need some way to search for newly
     880             :          * added Classes and Attributes
     881             :          */
     882        3794 :         if (working_schema) {
     883             :                 /* store current schema so we can fall back in case of failure */
     884          59 :                 cur_schema = dsdb_get_schema(ldb, tmp_ctx);
     885          59 :                 used_global_schema = dsdb_uses_global_schema(ldb);
     886             : 
     887          59 :                 ret = dsdb_reference_schema(ldb, working_schema, SCHEMA_MEMORY_ONLY);
     888          59 :                 if (ret != LDB_SUCCESS) {
     889           0 :                         DEBUG(0,(__location__ "Failed to reference working schema - %s\n",
     890             :                                  ldb_strerror(ret)));
     891             :                         /* TODO: Map LDB Error to NTSTATUS? */
     892           0 :                         ldb_transaction_cancel(ldb);
     893           0 :                         TALLOC_FREE(tmp_ctx);
     894           0 :                         return WERR_INTERNAL_ERROR;
     895             :                 }
     896             :         }
     897             : 
     898        3794 :         ret = ldb_extended(ldb, DSDB_EXTENDED_REPLICATED_OBJECTS_OID, objects, &ext_res);
     899        3794 :         if (ret != LDB_SUCCESS) {
     900             :                 /* restore previous schema */
     901          71 :                 if (used_global_schema) { 
     902           0 :                         dsdb_set_global_schema(ldb);
     903          71 :                 } else if (cur_schema) {
     904           0 :                         dsdb_reference_schema(ldb, cur_schema, SCHEMA_MEMORY_ONLY);
     905             :                 }
     906             : 
     907          71 :                 if (W_ERROR_EQUAL(objects->error, WERR_DS_DRA_RECYCLED_TARGET)) {
     908          37 :                         DEBUG(3,("Missing target while attempting to apply records: %s\n",
     909             :                                  ldb_errstring(ldb)));
     910          34 :                 } else if (W_ERROR_EQUAL(objects->error, WERR_DS_DRA_MISSING_PARENT)) {
     911          31 :                         DEBUG(3,("Missing parent while attempting to apply records: %s\n",
     912             :                                  ldb_errstring(ldb)));
     913             :                 } else {
     914           3 :                         DEBUG(1,("Failed to apply records: %s: %s\n",
     915             :                                  ldb_errstring(ldb), ldb_strerror(ret)));
     916             :                 }
     917          71 :                 ldb_transaction_cancel(ldb);
     918          71 :                 TALLOC_FREE(tmp_ctx);
     919             : 
     920          71 :                 if (!W_ERROR_IS_OK(objects->error)) {
     921          69 :                         return objects->error;
     922             :                 }
     923           2 :                 return WERR_FOOBAR;
     924             :         }
     925        3723 :         talloc_free(ext_res);
     926             : 
     927             :         /* Save our updated prefixMap and check the schema is good. */
     928        3723 :         if (working_schema) {
     929           0 :                 struct ldb_result *ext_res_2;
     930             : 
     931          59 :                 werr = dsdb_write_prefixes_from_schema_to_ldb(working_schema,
     932             :                                                               ldb,
     933             :                                                               working_schema);
     934          59 :                 if (!W_ERROR_IS_OK(werr)) {
     935             :                         /* restore previous schema */
     936           0 :                         if (used_global_schema) { 
     937           0 :                                 dsdb_set_global_schema(ldb);
     938           0 :                         } else if (cur_schema ) {
     939           0 :                                 dsdb_reference_schema(ldb,
     940             :                                                       cur_schema,
     941             :                                                       SCHEMA_MEMORY_ONLY);
     942             :                         }
     943           0 :                         DEBUG(0,("Failed to save updated prefixMap: %s\n",
     944             :                                  win_errstr(werr)));
     945           0 :                         ldb_transaction_cancel(ldb);
     946           0 :                         TALLOC_FREE(tmp_ctx);
     947           0 :                         return werr;
     948             :                 }
     949             : 
     950             :                 /*
     951             :                  * Use dsdb_schema_from_db through dsdb extended to check we
     952             :                  * can load the schema currently sitting in the transaction.
     953             :                  * We need this check because someone might have written to
     954             :                  * the schema or prefixMap before we started the transaction,
     955             :                  * which may have caused corruption.
     956             :                  */
     957          59 :                 ret = ldb_extended(ldb, DSDB_EXTENDED_SCHEMA_LOAD,
     958             :                                    NULL, &ext_res_2);
     959             : 
     960          59 :                 if (ret != LDB_SUCCESS) {
     961           0 :                         if (used_global_schema) {
     962           0 :                                 dsdb_set_global_schema(ldb);
     963           0 :                         } else if (cur_schema) {
     964           0 :                                 dsdb_reference_schema(ldb, cur_schema, SCHEMA_MEMORY_ONLY);
     965             :                         }
     966           0 :                         DEBUG(0,("Corrupt schema write attempt detected, "
     967             :                                  "aborting schema modification operation.\n"
     968             :                                  "This probably happened due to bad timing of "
     969             :                                  "another schema edit: %s (%s)\n",
     970             :                                  ldb_errstring(ldb),
     971             :                                  ldb_strerror(ret)));
     972           0 :                         ldb_transaction_cancel(ldb);
     973           0 :                         TALLOC_FREE(tmp_ctx);
     974           0 :                         return WERR_FOOBAR;
     975             :                 }
     976             :         }
     977             : 
     978        3723 :         ret = ldb_transaction_prepare_commit(ldb);
     979        3723 :         if (ret != LDB_SUCCESS) {
     980             :                 /* restore previous schema */
     981           0 :                 if (used_global_schema) { 
     982           0 :                         dsdb_set_global_schema(ldb);
     983           0 :                 } else if (cur_schema ) {
     984           0 :                         dsdb_reference_schema(ldb, cur_schema, SCHEMA_MEMORY_ONLY);
     985             :                 }
     986           0 :                 DBG_ERR(" Failed to prepare commit of transaction: %s (%s)\n",
     987             :                         ldb_errstring(ldb),
     988             :                         ldb_strerror(ret));
     989           0 :                 TALLOC_FREE(tmp_ctx);
     990           0 :                 return WERR_FOOBAR;
     991             :         }
     992             : 
     993        3723 :         ret = dsdb_load_partition_usn(ldb, objects->partition_dn, &seq_num2, NULL);
     994        3723 :         if (ret != LDB_SUCCESS) {
     995             :                 /* restore previous schema */
     996           0 :                 if (used_global_schema) { 
     997           0 :                         dsdb_set_global_schema(ldb);
     998           0 :                 } else if (cur_schema ) {
     999           0 :                         dsdb_reference_schema(ldb, cur_schema, SCHEMA_MEMORY_ONLY);
    1000             :                 }
    1001           0 :                 DEBUG(0,(__location__ " Failed to load partition uSN\n"));
    1002           0 :                 ldb_transaction_cancel(ldb);
    1003           0 :                 TALLOC_FREE(tmp_ctx);
    1004           0 :                 return WERR_FOOBAR;             
    1005             :         }
    1006             : 
    1007        3723 :         ret = ldb_transaction_commit(ldb);
    1008        3723 :         if (ret != LDB_SUCCESS) {
    1009             :                 /* restore previous schema */
    1010           0 :                 if (used_global_schema) { 
    1011           0 :                         dsdb_set_global_schema(ldb);
    1012           0 :                 } else if (cur_schema ) {
    1013           0 :                         dsdb_reference_schema(ldb, cur_schema, SCHEMA_MEMORY_ONLY);
    1014             :                 }
    1015           0 :                 DEBUG(0,(__location__ " Failed to commit transaction\n"));
    1016           0 :                 TALLOC_FREE(tmp_ctx);
    1017           0 :                 return WERR_FOOBAR;
    1018             :         }
    1019             : 
    1020        3723 :         if (seq_num1 > *notify_uSN) {
    1021             :                 /*
    1022             :                  * A notify was already required before
    1023             :                  * the current transaction.
    1024             :                  */
    1025        2046 :         } else if (objects->originating_updates) {
    1026             :                 /*
    1027             :                  * Applying the replicated changes
    1028             :                  * required originating updates,
    1029             :                  * so a notify is required.
    1030             :                  */
    1031             :         } else {
    1032             :                 /*
    1033             :                  * There's no need to notify the
    1034             :                  * server about the change we just from it.
    1035             :                  */
    1036        2029 :                 *notify_uSN = seq_num2;
    1037             :         }
    1038             : 
    1039             :         /*
    1040             :          * Reset the Schema used by ldb. This will lead to
    1041             :          * a schema cache being refreshed from database.
    1042             :          */
    1043        3723 :         if (working_schema) {
    1044             :                 /* Reload the schema */
    1045          59 :                 new_schema = dsdb_get_schema(ldb, tmp_ctx);
    1046             :                 /* TODO:
    1047             :                  * If dsdb_get_schema() fails, we just fall back
    1048             :                  * to what we had.  However, the database is probably
    1049             :                  * unable to operate for other users from this
    1050             :                  * point... */
    1051          59 :                 if (new_schema == NULL || new_schema == working_schema) {
    1052           0 :                         DBG_ERR("Failed to re-load schema after commit of "
    1053             :                                 "transaction (working: %p/%"PRIu64", new: "
    1054             :                                 "%p/%"PRIu64")\n", new_schema,
    1055             :                                 new_schema != NULL ?
    1056             :                                 new_schema->metadata_usn : 0,
    1057             :                                 working_schema, working_schema->metadata_usn);
    1058           0 :                         dsdb_reference_schema(ldb, cur_schema, SCHEMA_MEMORY_ONLY);
    1059           0 :                         if (used_global_schema) {
    1060           0 :                                 dsdb_set_global_schema(ldb);
    1061             :                         }
    1062           0 :                         TALLOC_FREE(tmp_ctx);
    1063           0 :                         return WERR_INTERNAL_ERROR;
    1064          59 :                 } else if (used_global_schema) {
    1065          59 :                         dsdb_make_schema_global(ldb, new_schema);
    1066             :                 }
    1067             :         }
    1068             : 
    1069        3723 :         DEBUG(2,("Replicated %u objects (%u linked attributes) for %s\n",
    1070             :                  objects->num_objects, objects->linked_attributes_count,
    1071             :                  ldb_dn_get_linearized(objects->partition_dn)));
    1072             :                  
    1073        3723 :         TALLOC_FREE(tmp_ctx);
    1074        3723 :         return WERR_OK;
    1075             : }
    1076             : 
    1077          94 : static WERROR dsdb_origin_object_convert(struct ldb_context *ldb,
    1078             :                                          const struct dsdb_schema *schema,
    1079             :                                          const struct drsuapi_DsReplicaObjectListItem *in,
    1080             :                                          TALLOC_CTX *mem_ctx,
    1081             :                                          struct ldb_message **_msg)
    1082             : {
    1083           0 :         WERROR status;
    1084           0 :         unsigned int i;
    1085           0 :         struct ldb_message *msg;
    1086             : 
    1087          94 :         if (!in->object.identifier) {
    1088           0 :                 return WERR_FOOBAR;
    1089             :         }
    1090             : 
    1091          94 :         if (!in->object.identifier->dn || !in->object.identifier->dn[0]) {
    1092           0 :                 return WERR_FOOBAR;
    1093             :         }
    1094             : 
    1095          94 :         msg = ldb_msg_new(mem_ctx);
    1096          94 :         W_ERROR_HAVE_NO_MEMORY(msg);
    1097             : 
    1098          94 :         msg->dn      = ldb_dn_new(msg, ldb, in->object.identifier->dn);
    1099          94 :         W_ERROR_HAVE_NO_MEMORY(msg->dn);
    1100             : 
    1101          94 :         msg->num_elements    = in->object.attribute_ctr.num_attributes;
    1102          94 :         msg->elements                = talloc_array(msg, struct ldb_message_element,
    1103             :                                                msg->num_elements);
    1104          94 :         W_ERROR_HAVE_NO_MEMORY(msg->elements);
    1105             : 
    1106         999 :         for (i=0; i < msg->num_elements; i++) {
    1107           0 :                 struct drsuapi_DsReplicaAttribute *a;
    1108           0 :                 struct ldb_message_element *e;
    1109             : 
    1110         905 :                 a = &in->object.attribute_ctr.attributes[i];
    1111         905 :                 e = &msg->elements[i];
    1112             : 
    1113         905 :                 status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, schema->prefixmap,
    1114         905 :                                                        a, msg->elements, e, NULL);
    1115         905 :                 W_ERROR_NOT_OK_RETURN(status);
    1116             :         }
    1117             : 
    1118             : 
    1119          94 :         *_msg = msg;
    1120             : 
    1121          94 :         return WERR_OK;
    1122             : }
    1123             : 
    1124          94 : WERROR dsdb_origin_objects_commit(struct ldb_context *ldb,
    1125             :                                   TALLOC_CTX *mem_ctx,
    1126             :                                   const struct drsuapi_DsReplicaObjectListItem *first_object,
    1127             :                                   uint32_t *_num,
    1128             :                                   uint32_t dsdb_repl_flags,
    1129             :                                   struct drsuapi_DsReplicaObjectIdentifier2 **_ids)
    1130             : {
    1131           0 :         WERROR status;
    1132           0 :         const struct dsdb_schema *schema;
    1133           0 :         const struct drsuapi_DsReplicaObjectListItem *cur;
    1134           0 :         struct ldb_message **objects;
    1135           0 :         struct drsuapi_DsReplicaObjectIdentifier2 *ids;
    1136           0 :         uint32_t i;
    1137          94 :         uint32_t num_objects = 0;
    1138          94 :         const char * const attrs[] = {
    1139             :                 "objectGUID",
    1140             :                 "objectSid",
    1141             :                 NULL
    1142             :         };
    1143           0 :         struct ldb_result *res;
    1144           0 :         int ret;
    1145             : 
    1146         188 :         for (cur = first_object; cur; cur = cur->next_object) {
    1147          94 :                 num_objects++;
    1148             :         }
    1149             : 
    1150          94 :         if (num_objects == 0) {
    1151           0 :                 return WERR_OK;
    1152             :         }
    1153             : 
    1154          94 :         ret = ldb_transaction_start(ldb);
    1155          94 :         if (ret != LDB_SUCCESS) {
    1156           0 :                 return WERR_DS_INTERNAL_FAILURE;
    1157             :         }
    1158             : 
    1159          94 :         objects = talloc_array(mem_ctx, struct ldb_message *,
    1160             :                                num_objects);
    1161          94 :         if (objects == NULL) {
    1162           0 :                 status = WERR_NOT_ENOUGH_MEMORY;
    1163           0 :                 goto cancel;
    1164             :         }
    1165             : 
    1166          94 :         schema = dsdb_get_schema(ldb, objects);
    1167          94 :         if (!schema) {
    1168           0 :                 return WERR_DS_SCHEMA_NOT_LOADED;
    1169             :         }
    1170             : 
    1171         188 :         for (i=0, cur = first_object; cur; cur = cur->next_object, i++) {
    1172          94 :                 status = dsdb_origin_object_convert(ldb, schema, cur,
    1173          94 :                                                     objects, &objects[i]);
    1174          94 :                 if (!W_ERROR_IS_OK(status)) {
    1175           0 :                         goto cancel;
    1176             :                 }
    1177             :         }
    1178             : 
    1179          94 :         ids = talloc_array(mem_ctx,
    1180             :                            struct drsuapi_DsReplicaObjectIdentifier2,
    1181             :                            num_objects);
    1182          94 :         if (ids == NULL) {
    1183           0 :                 status = WERR_NOT_ENOUGH_MEMORY;
    1184           0 :                 goto cancel;
    1185             :         }
    1186             : 
    1187          94 :         if (dsdb_repl_flags & DSDB_REPL_FLAG_ADD_NCNAME) {
    1188             :                 /* check for possible NC creation */
    1189         188 :                 for (i=0; i < num_objects; i++) {
    1190          94 :                         struct ldb_message *msg = objects[i];
    1191           0 :                         struct ldb_message_element *el;
    1192           0 :                         struct ldb_dn *nc_dn;
    1193             : 
    1194          94 :                         if (ldb_msg_check_string_attribute(msg, "objectClass", "crossRef") == 0) {
    1195          94 :                                 continue;
    1196             :                         }
    1197           0 :                         el = ldb_msg_find_element(msg, "nCName");
    1198           0 :                         if (el == NULL || el->num_values != 1) {
    1199           0 :                                 continue;
    1200             :                         }
    1201           0 :                         nc_dn = ldb_dn_from_ldb_val(objects, ldb, &el->values[0]);
    1202           0 :                         if (!ldb_dn_validate(nc_dn)) {
    1203           0 :                                 continue;
    1204             :                         }
    1205           0 :                         ret = dsdb_create_partial_replica_NC(ldb, nc_dn);
    1206           0 :                         if (ret != LDB_SUCCESS) {
    1207           0 :                                 status = WERR_DS_INTERNAL_FAILURE;
    1208           0 :                                 goto cancel;
    1209             :                         }
    1210             :                 }
    1211             :         }
    1212             : 
    1213         188 :         for (i=0; i < num_objects; i++) {
    1214          94 :                 struct dom_sid *sid = NULL;
    1215           0 :                 struct ldb_request *add_req;
    1216             : 
    1217          94 :                 DEBUG(6,(__location__ ": adding %s\n", 
    1218             :                          ldb_dn_get_linearized(objects[i]->dn)));
    1219             : 
    1220          94 :                 ret = ldb_build_add_req(&add_req,
    1221             :                                         ldb,
    1222             :                                         objects,
    1223          94 :                                         objects[i],
    1224             :                                         NULL,
    1225             :                                         NULL,
    1226             :                                         ldb_op_default_callback,
    1227             :                                         NULL);
    1228          94 :                 if (ret != LDB_SUCCESS) {
    1229           0 :                         status = WERR_DS_INTERNAL_FAILURE;
    1230           0 :                         goto cancel;
    1231             :                 }
    1232             : 
    1233          94 :                 ret = ldb_request_add_control(add_req, LDB_CONTROL_RELAX_OID, true, NULL);
    1234          94 :                 if (ret != LDB_SUCCESS) {
    1235           0 :                         status = WERR_DS_INTERNAL_FAILURE;
    1236           0 :                         goto cancel;
    1237             :                 }
    1238             :                 
    1239          94 :                 ret = ldb_request(ldb, add_req);
    1240          94 :                 if (ret == LDB_SUCCESS) {
    1241          94 :                         ret = ldb_wait(add_req->handle, LDB_WAIT_ALL);
    1242             :                 }
    1243          94 :                 if (ret != LDB_SUCCESS) {
    1244           0 :                         DEBUG(0,(__location__ ": Failed add of %s - %s\n",
    1245             :                                  ldb_dn_get_linearized(objects[i]->dn), ldb_errstring(ldb)));
    1246           0 :                         status = WERR_DS_INTERNAL_FAILURE;
    1247           0 :                         goto cancel;
    1248             :                 }
    1249             : 
    1250          94 :                 talloc_free(add_req);
    1251             : 
    1252          94 :                 ret = ldb_search(ldb, objects, &res, objects[i]->dn,
    1253             :                                  LDB_SCOPE_BASE, attrs,
    1254             :                                  "(objectClass=*)");
    1255          94 :                 if (ret != LDB_SUCCESS) {
    1256           0 :                         status = WERR_DS_INTERNAL_FAILURE;
    1257           0 :                         goto cancel;
    1258             :                 }
    1259          94 :                 ids[i].guid = samdb_result_guid(res->msgs[0], "objectGUID");
    1260          94 :                 sid = samdb_result_dom_sid(objects, res->msgs[0], "objectSid");
    1261          94 :                 if (sid) {
    1262           0 :                         ids[i].sid = *sid;
    1263             :                 } else {
    1264          94 :                         ZERO_STRUCT(ids[i].sid);
    1265             :                 }
    1266             :         }
    1267             : 
    1268          94 :         ret = ldb_transaction_commit(ldb);
    1269          94 :         if (ret != LDB_SUCCESS) {
    1270           0 :                 return WERR_DS_INTERNAL_FAILURE;
    1271             :         }
    1272             : 
    1273          94 :         talloc_free(objects);
    1274             : 
    1275          94 :         *_num = num_objects;
    1276          94 :         *_ids = ids;
    1277          94 :         return WERR_OK;
    1278             : 
    1279           0 : cancel:
    1280           0 :         talloc_free(objects);
    1281           0 :         ldb_transaction_cancel(ldb);
    1282           0 :         return status;
    1283             : }

Generated by: LCOV version 1.14