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