dsdb: Add log when ignoring a replicated object outside of partition
[samba.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 WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
388                               const struct dsdb_schema *schema,
389                               struct ldb_dn *partition_dn,
390                               const struct dsdb_schema_prefixmap *pfm_remote,
391                               const struct drsuapi_DsReplicaObjectListItemEx *in,
392                               const DATA_BLOB *gensec_skey,
393                               const uint32_t *ignore_attids,
394                               uint32_t dsdb_repl_flags,
395                               TALLOC_CTX *mem_ctx,
396                               struct dsdb_extended_replicated_object *out)
397 {
398         WERROR status = WERR_OK;
399         uint32_t i;
400         struct ldb_message *msg;
401         struct replPropertyMetaDataBlob *md;
402         int instanceType;
403         struct ldb_message_element *instanceType_e = NULL;
404         NTTIME whenChanged = 0;
405         time_t whenChanged_t;
406         const char *whenChanged_s;
407         struct dom_sid *sid = NULL;
408         uint32_t rid = 0;
409         uint32_t attr_count;
410
411         if (!in->object.identifier) {
412                 return WERR_FOOBAR;
413         }
414
415         if (!in->object.identifier->dn || !in->object.identifier->dn[0]) {
416                 return WERR_FOOBAR;
417         }
418
419         if (in->object.attribute_ctr.num_attributes != 0 && !in->meta_data_ctr) {
420                 return WERR_FOOBAR;
421         }
422
423         if (in->object.attribute_ctr.num_attributes != in->meta_data_ctr->count) {
424                 return WERR_FOOBAR;
425         }
426
427         sid = &in->object.identifier->sid;
428         if (sid->num_auths > 0) {
429                 rid = sid->sub_auths[sid->num_auths - 1];
430         }
431
432         msg = ldb_msg_new(mem_ctx);
433         W_ERROR_HAVE_NO_MEMORY(msg);
434
435         msg->dn                 = ldb_dn_new(msg, ldb, in->object.identifier->dn);
436         W_ERROR_HAVE_NO_MEMORY(msg->dn);
437
438         msg->num_elements       = in->object.attribute_ctr.num_attributes;
439         msg->elements           = talloc_array(msg, struct ldb_message_element,
440                                                msg->num_elements);
441         W_ERROR_HAVE_NO_MEMORY(msg->elements);
442
443         md = talloc(mem_ctx, struct replPropertyMetaDataBlob);
444         W_ERROR_HAVE_NO_MEMORY(md);
445
446         md->version             = 1;
447         md->reserved            = 0;
448         md->ctr.ctr1.count      = in->meta_data_ctr->count;
449         md->ctr.ctr1.reserved   = 0;
450         md->ctr.ctr1.array      = talloc_array(mem_ctx,
451                                                struct replPropertyMetaData1,
452                                                md->ctr.ctr1.count);
453         W_ERROR_HAVE_NO_MEMORY(md->ctr.ctr1.array);
454
455         for (i=0, attr_count=0; i < in->meta_data_ctr->count; i++, attr_count++) {
456                 struct drsuapi_DsReplicaAttribute *a;
457                 struct drsuapi_DsReplicaMetaData *d;
458                 struct replPropertyMetaData1 *m;
459                 struct ldb_message_element *e;
460                 uint32_t j;
461
462                 a = &in->object.attribute_ctr.attributes[i];
463                 d = &in->meta_data_ctr->meta_data[i];
464                 m = &md->ctr.ctr1.array[attr_count];
465                 e = &msg->elements[attr_count];
466
467                 if (dsdb_attid_in_list(ignore_attids, a->attid)) {
468                         attr_count--;
469                         continue;
470                 }
471
472                 if (GUID_all_zero(&d->originating_invocation_id)) {
473                         status = WERR_DS_SRC_GUID_MISMATCH;
474                         DEBUG(0, ("Refusing replication of object containing invalid zero invocationID on attribute %d of %s: %s\n",
475                                   a->attid,
476                                   ldb_dn_get_linearized(msg->dn),
477                                   win_errstr(status)));
478                         return status;
479                 }
480
481                 if (a->attid == DRSUAPI_ATTID_instanceType) {
482                         if (instanceType_e != NULL) {
483                                 return WERR_FOOBAR;
484                         }
485                         instanceType_e = e;
486                 }
487
488                 for (j=0; j<a->value_ctr.num_values; j++) {
489                         status = drsuapi_decrypt_attribute(a->value_ctr.values[j].blob,
490                                                            gensec_skey, rid,
491                                                            dsdb_repl_flags, a);
492                         if (!W_ERROR_IS_OK(status)) {
493                                 break;
494                         }
495                 }
496                 if (W_ERROR_EQUAL(status, WERR_TOO_MANY_SECRETS)) {
497                         WERROR get_name_status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, pfm_remote,
498                                                                                a, msg->elements, e, NULL);
499                         if (W_ERROR_IS_OK(get_name_status)) {
500                                 DEBUG(0, ("Unxpectedly got secret value %s on %s from DRS server\n",
501                                           e->name, ldb_dn_get_linearized(msg->dn)));
502                         } else {
503                                 DEBUG(0, ("Unxpectedly got secret value on %s from DRS server",
504                                           ldb_dn_get_linearized(msg->dn)));
505                         }
506                 } else if (!W_ERROR_IS_OK(status)) {
507                         return status;
508                 }
509
510                 /*
511                  * This function also fills in the local attid value,
512                  * based on comparing the remote and local prefixMap
513                  * tables.  If we don't convert the value, then we can
514                  * have invalid values in the replPropertyMetaData we
515                  * store on disk, as the prefixMap is per host, not
516                  * per-domain.  This may be why Microsoft added the
517                  * msDS-IntID feature, however this is not used for
518                  * extra attributes in the schema partition itself.
519                  */
520                 status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, pfm_remote,
521                                                        a, msg->elements, e,
522                                                        &m->attid);
523                 W_ERROR_NOT_OK_RETURN(status);
524
525                 m->version                      = d->version;
526                 m->originating_change_time      = d->originating_change_time;
527                 m->originating_invocation_id    = d->originating_invocation_id;
528                 m->originating_usn              = d->originating_usn;
529                 m->local_usn                    = 0;
530
531                 if (a->attid == DRSUAPI_ATTID_name) {
532                         const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
533                         if (rdn_val == NULL) {
534                                 DEBUG(0, ("Unxpectedly unable to get RDN from %s for validation",
535                                           ldb_dn_get_linearized(msg->dn)));
536                                 return WERR_FOOBAR;
537                         }
538                         if (e->num_values != 1) {
539                                 DEBUG(0, ("Unxpectedly got wrong number of attribute values (got %u, expected 1) when checking RDN against name of %s",
540                                           e->num_values,
541                                           ldb_dn_get_linearized(msg->dn)));
542                                 return WERR_FOOBAR;
543                         }
544                         if (data_blob_cmp(rdn_val,
545                                           &e->values[0]) != 0) {
546                                 DEBUG(0, ("Unxpectedly got mismatching RDN values when checking RDN against name of %s",
547                                           ldb_dn_get_linearized(msg->dn)));
548                                 return WERR_FOOBAR;
549                         }
550                 }
551                 if (d->originating_change_time > whenChanged) {
552                         whenChanged = d->originating_change_time;
553                 }
554
555         }
556
557         msg->num_elements = attr_count;
558         md->ctr.ctr1.count = attr_count;
559
560         if (instanceType_e == NULL) {
561                 return WERR_FOOBAR;
562         }
563
564         instanceType = ldb_msg_find_attr_as_int(msg, "instanceType", 0);
565
566         if ((instanceType & INSTANCE_TYPE_IS_NC_HEAD)
567             && partition_dn != NULL) {
568                 int partition_dn_cmp = ldb_dn_compare(partition_dn, msg->dn);
569                 if (partition_dn_cmp != 0) {
570                         DEBUG(4, ("Remote server advised us of a new partition %s while processing %s, ignoring\n",
571                                   ldb_dn_get_linearized(msg->dn),
572                                   ldb_dn_get_linearized(partition_dn)));
573                         return WERR_DS_ADD_REPLICA_INHIBITED;
574                 }
575         }
576
577         if (dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
578                 /* the instanceType type for partial_replica
579                    replication is sent via DRS with TYPE_WRITE set, but
580                    must be used on the client with TYPE_WRITE removed
581                 */
582                 if (instanceType & INSTANCE_TYPE_WRITE) {
583                         /*
584                          * Make sure we do not change the order
585                          * of msg->elements!
586                          *
587                          * That's why we use
588                          * instanceType_e->num_values = 0
589                          * instead of
590                          * ldb_msg_remove_attr(msg, "instanceType");
591                          */
592                         struct ldb_message_element *e;
593
594                         e = ldb_msg_find_element(msg, "instanceType");
595                         if (e != instanceType_e) {
596                                 DEBUG(0,("instanceType_e[%p] changed to e[%p]\n",
597                                          instanceType_e, e));
598                                 return WERR_FOOBAR;
599                         }
600
601                         instanceType_e->num_values = 0;
602
603                         instanceType &= ~INSTANCE_TYPE_WRITE;
604                         if (ldb_msg_add_fmt(msg, "instanceType", "%d", instanceType) != LDB_SUCCESS) {
605                                 return WERR_INTERNAL_ERROR;
606                         }
607                 }
608         } else {
609                 if (!(instanceType & INSTANCE_TYPE_WRITE)) {
610                         DEBUG(0, ("Refusing to replicate %s from a read-only repilca into a read-write replica!\n",
611                                   ldb_dn_get_linearized(msg->dn)));
612                         return WERR_DS_DRA_SOURCE_IS_PARTIAL_REPLICA;
613                 }
614         }
615
616         whenChanged_t = nt_time_to_unix(whenChanged);
617         whenChanged_s = ldb_timestring(msg, whenChanged_t);
618         W_ERROR_HAVE_NO_MEMORY(whenChanged_s);
619
620         out->object_guid = in->object.identifier->guid;
621
622         if (in->parent_object_guid == NULL) {
623                 out->parent_guid = NULL;
624         } else {
625                 out->parent_guid = talloc(mem_ctx, struct GUID);
626                 W_ERROR_HAVE_NO_MEMORY(out->parent_guid);
627                 *out->parent_guid = *in->parent_object_guid;
628         }
629
630         out->msg                = msg;
631         out->when_changed       = whenChanged_s;
632         out->meta_data          = md;
633         return WERR_OK;
634 }
635
636 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         WERROR status;
652         struct dsdb_schema_prefixmap *pfm_remote;
653         struct dsdb_extended_replicated_objects *out;
654         const struct drsuapi_DsReplicaObjectListItemEx *cur;
655         struct dsdb_syntax_ctx syntax_ctx;
656         uint32_t i;
657
658         out = talloc_zero(mem_ctx, struct dsdb_extended_replicated_objects);
659         W_ERROR_HAVE_NO_MEMORY(out);
660         out->version            = DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION;
661         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         schema = talloc_reference(out, schema);
668         W_ERROR_HAVE_NO_MEMORY(schema);
669
670         status = dsdb_schema_pfm_from_drsuapi_pfm(mapping_ctr, true,
671                                                   out, &pfm_remote, NULL);
672         if (!W_ERROR_IS_OK(status)) {
673                 DEBUG(0,(__location__ ": Failed to decode remote prefixMap: %s\n",
674                          win_errstr(status)));
675                 talloc_free(out);
676                 return status;
677         }
678
679         /* use default syntax conversion context */
680         dsdb_syntax_ctx_init(&syntax_ctx, ldb, schema);
681         syntax_ctx.pfm_remote = pfm_remote;
682
683         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                 status = dsdb_schema_info_cmp(schema, mapping_ctr);
689                 if (!W_ERROR_IS_OK(status)) {
690                         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                         talloc_free(out);
693                         return status;
694                 }
695         }
696
697         out->partition_dn       = partition_dn;
698
699         out->source_dsa         = source_dsa;
700         out->uptodateness_vector= uptodateness_vector;
701
702         out->num_objects        = 0;
703         out->objects            = talloc_array(out,
704                                                struct dsdb_extended_replicated_object,
705                                                object_count);
706         W_ERROR_HAVE_NO_MEMORY_AND_FREE(out->objects, out);
707
708         for (i=0, cur = first_object; cur; cur = cur->next_object, i++) {
709                 if (i == object_count) {
710                         talloc_free(out);
711                         return WERR_FOOBAR;
712                 }
713
714                 status = dsdb_convert_object_ex(ldb, schema, out->partition_dn,
715                                                 pfm_remote,
716                                                 cur, gensec_skey,
717                                                 NULL,
718                                                 dsdb_repl_flags,
719                                                 out->objects,
720                                                 &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                 if (W_ERROR_EQUAL(status, WERR_DS_ADD_REPLICA_INHIBITED)) {
730                         struct GUID_txt_buf guid_str;
731                         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                         continue;
737                 }
738
739                 if (!W_ERROR_IS_OK(status)) {
740                         talloc_free(out);
741                         DEBUG(0,("Failed to convert object %s: %s\n",
742                                  cur->object.identifier->dn,
743                                  win_errstr(status)));
744                         return status;
745                 }
746
747                 /* Assuming we didn't skip or error, increment the number of objects */
748                 out->num_objects++;
749         }
750         out->objects = talloc_realloc(out, out->objects,
751                                       struct dsdb_extended_replicated_object,
752                                       out->num_objects);
753         if (out->num_objects != 0 && out->objects == NULL) {
754                 talloc_free(out);
755                 return WERR_FOOBAR;
756         }
757         if (i != object_count) {
758                 talloc_free(out);
759                 return WERR_FOOBAR;
760         }
761
762         out->linked_attributes = talloc_array(out,
763                                               struct drsuapi_DsReplicaLinkedAttribute,
764                                               linked_attributes_count);
765         W_ERROR_HAVE_NO_MEMORY_AND_FREE(out->linked_attributes, out);
766
767         for (i=0; i < linked_attributes_count; i++) {
768                 const struct drsuapi_DsReplicaLinkedAttribute *ra = &linked_attributes[i];
769                 struct drsuapi_DsReplicaLinkedAttribute *la = &out->linked_attributes[i];
770
771                 if (ra->identifier == NULL) {
772                         talloc_free(out);
773                         return WERR_BAD_NET_RESP;
774                 }
775
776                 *la = *ra;
777
778                 la->identifier = talloc_zero(out->linked_attributes,
779                                              struct drsuapi_DsReplicaObjectIdentifier);
780                 W_ERROR_HAVE_NO_MEMORY_AND_FREE(la->identifier, out);
781
782                 /*
783                  * We typically only get the guid filled
784                  * and the repl_meta_data module only cares abouf
785                  * the guid.
786                  */
787                 la->identifier->guid = ra->identifier->guid;
788
789                 if (ra->value.blob != NULL) {
790                         la->value.blob = talloc_zero(out->linked_attributes,
791                                                      DATA_BLOB);
792                         W_ERROR_HAVE_NO_MEMORY_AND_FREE(la->value.blob, out);
793
794                         if (ra->value.blob->length != 0) {
795                                 *la->value.blob = data_blob_dup_talloc(la->value.blob,
796                                                                        *ra->value.blob);
797                                 W_ERROR_HAVE_NO_MEMORY_AND_FREE(la->value.blob->data, out);
798                         }
799                 }
800
801                 status = dsdb_attribute_drsuapi_remote_to_local(&syntax_ctx,
802                                                                 ra->attid,
803                                                                 &la->attid,
804                                                                 NULL);
805                 if (!W_ERROR_IS_OK(status)) {
806                         DEBUG(0,(__location__": linked_attribute[%u] attid 0x%08X not found: %s\n",
807                                  i, ra->attid, win_errstr(status)));
808                         return status;
809                 }
810         }
811
812         out->linked_attributes_count = linked_attributes_count;
813
814         /* free pfm_remote, we won't need it anymore */
815         talloc_free(pfm_remote);
816
817         *objects = out;
818         return WERR_OK;
819 }
820
821 /**
822  * Commits a list of replicated objects.
823  *
824  * @param working_schema dsdb_schema to be used for resolving
825  *                       Classes/Attributes during Schema replication. If not NULL,
826  *                       it will be set on ldb and used while committing replicated objects
827  */
828 WERROR dsdb_replicated_objects_commit(struct ldb_context *ldb,
829                                       struct dsdb_schema *working_schema,
830                                       struct dsdb_extended_replicated_objects *objects,
831                                       uint64_t *notify_uSN)
832 {
833         WERROR werr;
834         struct ldb_result *ext_res;
835         struct dsdb_schema *cur_schema = NULL;
836         struct dsdb_schema *new_schema = NULL;
837         int ret;
838         uint64_t seq_num1, seq_num2;
839         bool used_global_schema = false;
840
841         TALLOC_CTX *tmp_ctx = talloc_new(objects);
842         if (!tmp_ctx) {
843                 DEBUG(0,("Failed to start talloc\n"));
844                 return WERR_NOT_ENOUGH_MEMORY;
845         }
846
847         /* wrap the extended operation in a transaction 
848            See [MS-DRSR] 3.3.2 Transactions
849          */
850         ret = ldb_transaction_start(ldb);
851         if (ret != LDB_SUCCESS) {
852                 DEBUG(0,(__location__ " Failed to start transaction: %s\n",
853                          ldb_errstring(ldb)));
854                 return WERR_FOOBAR;
855         }
856
857         ret = dsdb_load_partition_usn(ldb, objects->partition_dn, &seq_num1, NULL);
858         if (ret != LDB_SUCCESS) {
859                 DEBUG(0,(__location__ " Failed to load partition uSN\n"));
860                 ldb_transaction_cancel(ldb);
861                 TALLOC_FREE(tmp_ctx);
862                 return WERR_FOOBAR;             
863         }
864
865         /*
866          * Set working_schema for ldb in case we are replicating from Schema NC.
867          * Schema won't be reloaded during Replicated Objects commit, as it is
868          * done in a transaction. So we need some way to search for newly
869          * added Classes and Attributes
870          */
871         if (working_schema) {
872                 /* store current schema so we can fall back in case of failure */
873                 cur_schema = dsdb_get_schema(ldb, tmp_ctx);
874                 used_global_schema = dsdb_uses_global_schema(ldb);
875
876                 ret = dsdb_reference_schema(ldb, working_schema, SCHEMA_MEMORY_ONLY);
877                 if (ret != LDB_SUCCESS) {
878                         DEBUG(0,(__location__ "Failed to reference working schema - %s\n",
879                                  ldb_strerror(ret)));
880                         /* TODO: Map LDB Error to NTSTATUS? */
881                         ldb_transaction_cancel(ldb);
882                         TALLOC_FREE(tmp_ctx);
883                         return WERR_INTERNAL_ERROR;
884                 }
885         }
886
887         ret = ldb_extended(ldb, DSDB_EXTENDED_REPLICATED_OBJECTS_OID, objects, &ext_res);
888         if (ret != LDB_SUCCESS) {
889                 /* restore previous schema */
890                 if (used_global_schema) { 
891                         dsdb_set_global_schema(ldb);
892                 } else if (cur_schema) {
893                         dsdb_reference_schema(ldb, cur_schema, SCHEMA_MEMORY_ONLY);
894                 }
895
896                 if (W_ERROR_EQUAL(objects->error, WERR_DS_DRA_RECYCLED_TARGET)) {
897                         DEBUG(3,("Missing target while attempting to apply records: %s\n",
898                                  ldb_errstring(ldb)));
899                 } else if (W_ERROR_EQUAL(objects->error, WERR_DS_DRA_MISSING_PARENT)) {
900                         DEBUG(3,("Missing parent while attempting to apply records: %s\n",
901                                  ldb_errstring(ldb)));
902                 } else {
903                         DEBUG(1,("Failed to apply records: %s: %s\n",
904                                  ldb_errstring(ldb), ldb_strerror(ret)));
905                 }
906                 ldb_transaction_cancel(ldb);
907                 TALLOC_FREE(tmp_ctx);
908
909                 if (!W_ERROR_IS_OK(objects->error)) {
910                         return objects->error;
911                 }
912                 return WERR_FOOBAR;
913         }
914         talloc_free(ext_res);
915
916         /* Save our updated prefixMap */
917         if (working_schema) {
918                 werr = dsdb_write_prefixes_from_schema_to_ldb(working_schema,
919                                                               ldb,
920                                                               working_schema);
921                 if (!W_ERROR_IS_OK(werr)) {
922                         /* restore previous schema */
923                         if (used_global_schema) { 
924                                 dsdb_set_global_schema(ldb);
925                         } else if (cur_schema ) {
926                                 dsdb_reference_schema(ldb, cur_schema, SCHEMA_MEMORY_ONLY);
927                         }
928                         DEBUG(0,("Failed to save updated prefixMap: %s\n",
929                                  win_errstr(werr)));
930                         ldb_transaction_cancel(ldb);
931                         TALLOC_FREE(tmp_ctx);
932                         return werr;
933                 }
934         }
935
936         ret = ldb_transaction_prepare_commit(ldb);
937         if (ret != LDB_SUCCESS) {
938                 /* restore previous schema */
939                 if (used_global_schema) { 
940                         dsdb_set_global_schema(ldb);
941                 } else if (cur_schema ) {
942                         dsdb_reference_schema(ldb, cur_schema, SCHEMA_MEMORY_ONLY);
943                 }
944                 DBG_ERR(" Failed to prepare commit of transaction: %s (%s)\n",
945                         ldb_errstring(ldb),
946                         ldb_strerror(ret));
947                 TALLOC_FREE(tmp_ctx);
948                 return WERR_FOOBAR;
949         }
950
951         ret = dsdb_load_partition_usn(ldb, objects->partition_dn, &seq_num2, NULL);
952         if (ret != LDB_SUCCESS) {
953                 /* restore previous schema */
954                 if (used_global_schema) { 
955                         dsdb_set_global_schema(ldb);
956                 } else if (cur_schema ) {
957                         dsdb_reference_schema(ldb, cur_schema, SCHEMA_MEMORY_ONLY);
958                 }
959                 DEBUG(0,(__location__ " Failed to load partition uSN\n"));
960                 ldb_transaction_cancel(ldb);
961                 TALLOC_FREE(tmp_ctx);
962                 return WERR_FOOBAR;             
963         }
964
965         ret = ldb_transaction_commit(ldb);
966         if (ret != LDB_SUCCESS) {
967                 /* restore previous schema */
968                 if (used_global_schema) { 
969                         dsdb_set_global_schema(ldb);
970                 } else if (cur_schema ) {
971                         dsdb_reference_schema(ldb, cur_schema, SCHEMA_MEMORY_ONLY);
972                 }
973                 DEBUG(0,(__location__ " Failed to commit transaction\n"));
974                 TALLOC_FREE(tmp_ctx);
975                 return WERR_FOOBAR;
976         }
977
978         if (seq_num1 > *notify_uSN) {
979                 /*
980                  * A notify was already required before
981                  * the current transaction.
982                  */
983         } else if (objects->originating_updates) {
984                 /*
985                  * Applying the replicated changes
986                  * required originating updates,
987                  * so a notify is required.
988                  */
989         } else {
990                 /*
991                  * There's no need to notify the
992                  * server about the change we just from it.
993                  */
994                 *notify_uSN = seq_num2;
995         }
996
997         /*
998          * Reset the Schema used by ldb. This will lead to
999          * a schema cache being refreshed from database.
1000          */
1001         if (working_schema) {
1002                 /* Reload the schema */
1003                 new_schema = dsdb_get_schema(ldb, tmp_ctx);
1004                 /* TODO:
1005                  * If dsdb_get_schema() fails, we just fall back
1006                  * to what we had.  However, the database is probably
1007                  * unable to operate for other users from this
1008                  * point... */
1009                 if (new_schema == NULL || new_schema == working_schema) {
1010                         DBG_ERR("Failed to re-load schema after commit of "
1011                                 "transaction (working: %p/%"PRIu64", new: "
1012                                 "%p/%"PRIu64")\n", new_schema,
1013                                 new_schema != NULL ?
1014                                 new_schema->metadata_usn : 0,
1015                                 working_schema, working_schema->metadata_usn);
1016                         dsdb_reference_schema(ldb, cur_schema, SCHEMA_MEMORY_ONLY);
1017                         if (used_global_schema) {
1018                                 dsdb_set_global_schema(ldb);
1019                         }
1020                         TALLOC_FREE(tmp_ctx);
1021                         return WERR_INTERNAL_ERROR;
1022                 } else if (used_global_schema) {
1023                         dsdb_make_schema_global(ldb, new_schema);
1024                 }
1025         }
1026
1027         DEBUG(2,("Replicated %u objects (%u linked attributes) for %s\n",
1028                  objects->num_objects, objects->linked_attributes_count,
1029                  ldb_dn_get_linearized(objects->partition_dn)));
1030                  
1031         TALLOC_FREE(tmp_ctx);
1032         return WERR_OK;
1033 }
1034
1035 static WERROR dsdb_origin_object_convert(struct ldb_context *ldb,
1036                                          const struct dsdb_schema *schema,
1037                                          const struct drsuapi_DsReplicaObjectListItem *in,
1038                                          TALLOC_CTX *mem_ctx,
1039                                          struct ldb_message **_msg)
1040 {
1041         WERROR status;
1042         unsigned int i;
1043         struct ldb_message *msg;
1044
1045         if (!in->object.identifier) {
1046                 return WERR_FOOBAR;
1047         }
1048
1049         if (!in->object.identifier->dn || !in->object.identifier->dn[0]) {
1050                 return WERR_FOOBAR;
1051         }
1052
1053         msg = ldb_msg_new(mem_ctx);
1054         W_ERROR_HAVE_NO_MEMORY(msg);
1055
1056         msg->dn = ldb_dn_new(msg, ldb, in->object.identifier->dn);
1057         W_ERROR_HAVE_NO_MEMORY(msg->dn);
1058
1059         msg->num_elements       = in->object.attribute_ctr.num_attributes;
1060         msg->elements           = talloc_array(msg, struct ldb_message_element,
1061                                                msg->num_elements);
1062         W_ERROR_HAVE_NO_MEMORY(msg->elements);
1063
1064         for (i=0; i < msg->num_elements; i++) {
1065                 struct drsuapi_DsReplicaAttribute *a;
1066                 struct ldb_message_element *e;
1067
1068                 a = &in->object.attribute_ctr.attributes[i];
1069                 e = &msg->elements[i];
1070
1071                 status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, schema->prefixmap,
1072                                                        a, msg->elements, e, NULL);
1073                 W_ERROR_NOT_OK_RETURN(status);
1074         }
1075
1076
1077         *_msg = msg;
1078
1079         return WERR_OK;
1080 }
1081
1082 WERROR dsdb_origin_objects_commit(struct ldb_context *ldb,
1083                                   TALLOC_CTX *mem_ctx,
1084                                   const struct drsuapi_DsReplicaObjectListItem *first_object,
1085                                   uint32_t *_num,
1086                                   uint32_t dsdb_repl_flags,
1087                                   struct drsuapi_DsReplicaObjectIdentifier2 **_ids)
1088 {
1089         WERROR status;
1090         const struct dsdb_schema *schema;
1091         const struct drsuapi_DsReplicaObjectListItem *cur;
1092         struct ldb_message **objects;
1093         struct drsuapi_DsReplicaObjectIdentifier2 *ids;
1094         uint32_t i;
1095         uint32_t num_objects = 0;
1096         const char * const attrs[] = {
1097                 "objectGUID",
1098                 "objectSid",
1099                 NULL
1100         };
1101         struct ldb_result *res;
1102         int ret;
1103
1104         for (cur = first_object; cur; cur = cur->next_object) {
1105                 num_objects++;
1106         }
1107
1108         if (num_objects == 0) {
1109                 return WERR_OK;
1110         }
1111
1112         ret = ldb_transaction_start(ldb);
1113         if (ret != LDB_SUCCESS) {
1114                 return WERR_DS_INTERNAL_FAILURE;
1115         }
1116
1117         objects = talloc_array(mem_ctx, struct ldb_message *,
1118                                num_objects);
1119         if (objects == NULL) {
1120                 status = WERR_NOT_ENOUGH_MEMORY;
1121                 goto cancel;
1122         }
1123
1124         schema = dsdb_get_schema(ldb, objects);
1125         if (!schema) {
1126                 return WERR_DS_SCHEMA_NOT_LOADED;
1127         }
1128
1129         for (i=0, cur = first_object; cur; cur = cur->next_object, i++) {
1130                 status = dsdb_origin_object_convert(ldb, schema, cur,
1131                                                     objects, &objects[i]);
1132                 if (!W_ERROR_IS_OK(status)) {
1133                         goto cancel;
1134                 }
1135         }
1136
1137         ids = talloc_array(mem_ctx,
1138                            struct drsuapi_DsReplicaObjectIdentifier2,
1139                            num_objects);
1140         if (ids == NULL) {
1141                 status = WERR_NOT_ENOUGH_MEMORY;
1142                 goto cancel;
1143         }
1144
1145         if (dsdb_repl_flags & DSDB_REPL_FLAG_ADD_NCNAME) {
1146                 /* check for possible NC creation */
1147                 for (i=0; i < num_objects; i++) {
1148                         struct ldb_message *msg = objects[i];
1149                         struct ldb_message_element *el;
1150                         struct ldb_dn *nc_dn;
1151
1152                         if (ldb_msg_check_string_attribute(msg, "objectClass", "crossRef") == 0) {
1153                                 continue;
1154                         }
1155                         el = ldb_msg_find_element(msg, "nCName");
1156                         if (el == NULL || el->num_values != 1) {
1157                                 continue;
1158                         }
1159                         nc_dn = ldb_dn_from_ldb_val(objects, ldb, &el->values[0]);
1160                         if (!ldb_dn_validate(nc_dn)) {
1161                                 continue;
1162                         }
1163                         ret = dsdb_create_partial_replica_NC(ldb, nc_dn);
1164                         if (ret != LDB_SUCCESS) {
1165                                 status = WERR_DS_INTERNAL_FAILURE;
1166                                 goto cancel;
1167                         }
1168                 }
1169         }
1170
1171         for (i=0; i < num_objects; i++) {
1172                 struct dom_sid *sid = NULL;
1173                 struct ldb_request *add_req;
1174
1175                 DEBUG(6,(__location__ ": adding %s\n", 
1176                          ldb_dn_get_linearized(objects[i]->dn)));
1177
1178                 ret = ldb_build_add_req(&add_req,
1179                                         ldb,
1180                                         objects,
1181                                         objects[i],
1182                                         NULL,
1183                                         NULL,
1184                                         ldb_op_default_callback,
1185                                         NULL);
1186                 if (ret != LDB_SUCCESS) {
1187                         status = WERR_DS_INTERNAL_FAILURE;
1188                         goto cancel;
1189                 }
1190
1191                 ret = ldb_request_add_control(add_req, LDB_CONTROL_RELAX_OID, true, NULL);
1192                 if (ret != LDB_SUCCESS) {
1193                         status = WERR_DS_INTERNAL_FAILURE;
1194                         goto cancel;
1195                 }
1196                 
1197                 ret = ldb_request(ldb, add_req);
1198                 if (ret == LDB_SUCCESS) {
1199                         ret = ldb_wait(add_req->handle, LDB_WAIT_ALL);
1200                 }
1201                 if (ret != LDB_SUCCESS) {
1202                         DEBUG(0,(__location__ ": Failed add of %s - %s\n",
1203                                  ldb_dn_get_linearized(objects[i]->dn), ldb_errstring(ldb)));
1204                         status = WERR_DS_INTERNAL_FAILURE;
1205                         goto cancel;
1206                 }
1207
1208                 talloc_free(add_req);
1209
1210                 ret = ldb_search(ldb, objects, &res, objects[i]->dn,
1211                                  LDB_SCOPE_BASE, attrs,
1212                                  "(objectClass=*)");
1213                 if (ret != LDB_SUCCESS) {
1214                         status = WERR_DS_INTERNAL_FAILURE;
1215                         goto cancel;
1216                 }
1217                 ids[i].guid = samdb_result_guid(res->msgs[0], "objectGUID");
1218                 sid = samdb_result_dom_sid(objects, res->msgs[0], "objectSid");
1219                 if (sid) {
1220                         ids[i].sid = *sid;
1221                 } else {
1222                         ZERO_STRUCT(ids[i].sid);
1223                 }
1224         }
1225
1226         ret = ldb_transaction_commit(ldb);
1227         if (ret != LDB_SUCCESS) {
1228                 return WERR_DS_INTERNAL_FAILURE;
1229         }
1230
1231         talloc_free(objects);
1232
1233         *_num = num_objects;
1234         *_ids = ids;
1235         return WERR_OK;
1236
1237 cancel:
1238         talloc_free(objects);
1239         ldb_transaction_cancel(ldb);
1240         return status;
1241 }