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 | /**
|
---|
35 | * Multi-pass working schema creation
|
---|
36 | * Function will:
|
---|
37 | * - shallow copy initial schema supplied
|
---|
38 | * - create a working schema in multiple passes
|
---|
39 | * until all objects are resolved
|
---|
40 | * Working schema is a schema with Attributes, Classes
|
---|
41 | * and indexes, but w/o subClassOf, possibleSupperiors etc.
|
---|
42 | * It is to be used just us cache for converting attribute values.
|
---|
43 | */
|
---|
44 | WERROR dsdb_repl_make_working_schema(struct ldb_context *ldb,
|
---|
45 | const struct dsdb_schema *initial_schema,
|
---|
46 | const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr,
|
---|
47 | uint32_t object_count,
|
---|
48 | const struct drsuapi_DsReplicaObjectListItemEx *first_object,
|
---|
49 | const DATA_BLOB *gensec_skey,
|
---|
50 | TALLOC_CTX *mem_ctx,
|
---|
51 | struct dsdb_schema **_schema_out)
|
---|
52 | {
|
---|
53 | struct schema_list {
|
---|
54 | struct schema_list *next, *prev;
|
---|
55 | const struct drsuapi_DsReplicaObjectListItemEx *obj;
|
---|
56 | };
|
---|
57 |
|
---|
58 | WERROR werr;
|
---|
59 | struct dsdb_schema_prefixmap *pfm_remote;
|
---|
60 | struct schema_list *schema_list = NULL, *schema_list_item, *schema_list_next_item;
|
---|
61 | struct dsdb_schema *working_schema;
|
---|
62 | const struct drsuapi_DsReplicaObjectListItemEx *cur;
|
---|
63 | int ret, pass_no;
|
---|
64 | uint32_t ignore_attids[] = {
|
---|
65 | DRSUAPI_ATTID_auxiliaryClass,
|
---|
66 | DRSUAPI_ATTID_mayContain,
|
---|
67 | DRSUAPI_ATTID_mustContain,
|
---|
68 | DRSUAPI_ATTID_possSuperiors,
|
---|
69 | DRSUAPI_ATTID_systemPossSuperiors,
|
---|
70 | DRSUAPI_ATTID_INVALID
|
---|
71 | };
|
---|
72 |
|
---|
73 | /* make a copy of the iniatial_scheam so we don't mess with it */
|
---|
74 | working_schema = dsdb_schema_copy_shallow(mem_ctx, ldb, initial_schema);
|
---|
75 | if (!working_schema) {
|
---|
76 | DEBUG(0,(__location__ ": schema copy failed!\n"));
|
---|
77 | return WERR_NOMEM;
|
---|
78 | }
|
---|
79 |
|
---|
80 | /* we are going to need remote prefixMap for decoding */
|
---|
81 | werr = dsdb_schema_pfm_from_drsuapi_pfm(mapping_ctr, true,
|
---|
82 | mem_ctx, &pfm_remote, NULL);
|
---|
83 | if (!W_ERROR_IS_OK(werr)) {
|
---|
84 | DEBUG(0,(__location__ ": Failed to decode remote prefixMap: %s",
|
---|
85 | win_errstr(werr)));
|
---|
86 | return werr;
|
---|
87 | }
|
---|
88 |
|
---|
89 | /* create a list of objects yet to be converted */
|
---|
90 | for (cur = first_object; cur; cur = cur->next_object) {
|
---|
91 | schema_list_item = talloc(mem_ctx, struct schema_list);
|
---|
92 | schema_list_item->obj = cur;
|
---|
93 | DLIST_ADD_END(schema_list, schema_list_item, struct schema_list);
|
---|
94 | }
|
---|
95 |
|
---|
96 | /* resolve objects until all are resolved and in local schema */
|
---|
97 | pass_no = 1;
|
---|
98 |
|
---|
99 | while (schema_list) {
|
---|
100 | uint32_t converted_obj_count = 0;
|
---|
101 | uint32_t failed_obj_count = 0;
|
---|
102 | TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
|
---|
103 | W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
|
---|
104 |
|
---|
105 | for (schema_list_item = schema_list; schema_list_item; schema_list_item=schema_list_next_item) {
|
---|
106 | struct dsdb_extended_replicated_object object;
|
---|
107 |
|
---|
108 | cur = schema_list_item->obj;
|
---|
109 |
|
---|
110 | /* Save the next item, now we have saved out
|
---|
111 | * the current one, so we can DLIST_REMOVE it
|
---|
112 | * safely */
|
---|
113 | schema_list_next_item = schema_list_item->next;
|
---|
114 |
|
---|
115 | /*
|
---|
116 | * Convert the objects into LDB messages using the
|
---|
117 | * schema we have so far. It's ok if we fail to convert
|
---|
118 | * an object. We should convert more objects on next pass.
|
---|
119 | */
|
---|
120 | werr = dsdb_convert_object_ex(ldb, working_schema, pfm_remote,
|
---|
121 | cur, gensec_skey,
|
---|
122 | ignore_attids,
|
---|
123 | tmp_ctx, &object);
|
---|
124 | if (!W_ERROR_IS_OK(werr)) {
|
---|
125 | DEBUG(1,("Warning: Failed to convert schema object %s into ldb msg\n",
|
---|
126 | cur->object.identifier->dn));
|
---|
127 |
|
---|
128 | failed_obj_count++;
|
---|
129 | } else {
|
---|
130 | /*
|
---|
131 | * Convert the schema from ldb_message format
|
---|
132 | * (OIDs as OID strings) into schema, using
|
---|
133 | * the remote prefixMap
|
---|
134 | */
|
---|
135 | werr = dsdb_schema_set_el_from_ldb_msg(ldb,
|
---|
136 | working_schema,
|
---|
137 | object.msg);
|
---|
138 | if (!W_ERROR_IS_OK(werr)) {
|
---|
139 | DEBUG(1,("Warning: failed to convert object %s into a schema element: %s\n",
|
---|
140 | ldb_dn_get_linearized(object.msg->dn),
|
---|
141 | win_errstr(werr)));
|
---|
142 | failed_obj_count++;
|
---|
143 | } else {
|
---|
144 | DLIST_REMOVE(schema_list, schema_list_item);
|
---|
145 | talloc_free(schema_list_item);
|
---|
146 | converted_obj_count++;
|
---|
147 | }
|
---|
148 | }
|
---|
149 | }
|
---|
150 | talloc_free(tmp_ctx);
|
---|
151 |
|
---|
152 | DEBUG(4,("Schema load pass %d: %d/%d of %d objects left to be converted.\n",
|
---|
153 | pass_no, failed_obj_count, converted_obj_count, object_count));
|
---|
154 | pass_no++;
|
---|
155 |
|
---|
156 | /* check if we converted any objects in this pass */
|
---|
157 | if (converted_obj_count == 0) {
|
---|
158 | DEBUG(0,("Can't continue Schema load: didn't manage to convert any objects: all %d remaining of %d objects failed to convert\n", failed_obj_count, object_count));
|
---|
159 | return WERR_INTERNAL_ERROR;
|
---|
160 | }
|
---|
161 |
|
---|
162 | /* rebuild indexes */
|
---|
163 | ret = dsdb_setup_sorted_accessors(ldb, working_schema);
|
---|
164 | if (LDB_SUCCESS != ret) {
|
---|
165 | DEBUG(0,("Failed to create schema-cache indexes!\n"));
|
---|
166 | return WERR_INTERNAL_ERROR;
|
---|
167 | }
|
---|
168 | };
|
---|
169 |
|
---|
170 | *_schema_out = working_schema;
|
---|
171 |
|
---|
172 | return WERR_OK;
|
---|
173 | }
|
---|
174 |
|
---|
175 | static bool dsdb_attid_in_list(const uint32_t attid_list[], uint32_t attid)
|
---|
176 | {
|
---|
177 | const uint32_t *cur;
|
---|
178 | if (!attid_list) {
|
---|
179 | return false;
|
---|
180 | }
|
---|
181 | for (cur = attid_list; *cur != DRSUAPI_ATTID_INVALID; cur++) {
|
---|
182 | if (*cur == attid) {
|
---|
183 | return true;
|
---|
184 | }
|
---|
185 | }
|
---|
186 | return false;
|
---|
187 | }
|
---|
188 |
|
---|
189 | WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
|
---|
190 | const struct dsdb_schema *schema,
|
---|
191 | const struct dsdb_schema_prefixmap *pfm_remote,
|
---|
192 | const struct drsuapi_DsReplicaObjectListItemEx *in,
|
---|
193 | const DATA_BLOB *gensec_skey,
|
---|
194 | const uint32_t *ignore_attids,
|
---|
195 | TALLOC_CTX *mem_ctx,
|
---|
196 | struct dsdb_extended_replicated_object *out)
|
---|
197 | {
|
---|
198 | NTSTATUS nt_status;
|
---|
199 | WERROR status;
|
---|
200 | uint32_t i;
|
---|
201 | struct ldb_message *msg;
|
---|
202 | struct replPropertyMetaDataBlob *md;
|
---|
203 | struct ldb_val guid_value;
|
---|
204 | NTTIME whenChanged = 0;
|
---|
205 | time_t whenChanged_t;
|
---|
206 | const char *whenChanged_s;
|
---|
207 | const char *rdn_name = NULL;
|
---|
208 | const struct ldb_val *rdn_value = NULL;
|
---|
209 | const struct dsdb_attribute *rdn_attr = NULL;
|
---|
210 | uint32_t rdn_attid;
|
---|
211 | struct drsuapi_DsReplicaAttribute *name_a = NULL;
|
---|
212 | struct drsuapi_DsReplicaMetaData *name_d = NULL;
|
---|
213 | struct replPropertyMetaData1 *rdn_m = NULL;
|
---|
214 | struct dom_sid *sid = NULL;
|
---|
215 | uint32_t rid = 0;
|
---|
216 | uint32_t attr_count;
|
---|
217 | int ret;
|
---|
218 |
|
---|
219 | if (!in->object.identifier) {
|
---|
220 | return WERR_FOOBAR;
|
---|
221 | }
|
---|
222 |
|
---|
223 | if (!in->object.identifier->dn || !in->object.identifier->dn[0]) {
|
---|
224 | return WERR_FOOBAR;
|
---|
225 | }
|
---|
226 |
|
---|
227 | if (in->object.attribute_ctr.num_attributes != 0 && !in->meta_data_ctr) {
|
---|
228 | return WERR_FOOBAR;
|
---|
229 | }
|
---|
230 |
|
---|
231 | if (in->object.attribute_ctr.num_attributes != in->meta_data_ctr->count) {
|
---|
232 | return WERR_FOOBAR;
|
---|
233 | }
|
---|
234 |
|
---|
235 | sid = &in->object.identifier->sid;
|
---|
236 | if (sid->num_auths > 0) {
|
---|
237 | rid = sid->sub_auths[sid->num_auths - 1];
|
---|
238 | }
|
---|
239 |
|
---|
240 | msg = ldb_msg_new(mem_ctx);
|
---|
241 | W_ERROR_HAVE_NO_MEMORY(msg);
|
---|
242 |
|
---|
243 | msg->dn = ldb_dn_new(msg, ldb, in->object.identifier->dn);
|
---|
244 | W_ERROR_HAVE_NO_MEMORY(msg->dn);
|
---|
245 |
|
---|
246 | rdn_name = ldb_dn_get_rdn_name(msg->dn);
|
---|
247 | rdn_attr = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
|
---|
248 | if (!rdn_attr) {
|
---|
249 | return WERR_FOOBAR;
|
---|
250 | }
|
---|
251 | rdn_attid = rdn_attr->attributeID_id;
|
---|
252 | rdn_value = ldb_dn_get_rdn_val(msg->dn);
|
---|
253 |
|
---|
254 | msg->num_elements = in->object.attribute_ctr.num_attributes;
|
---|
255 | msg->elements = talloc_array(msg, struct ldb_message_element,
|
---|
256 | msg->num_elements);
|
---|
257 | W_ERROR_HAVE_NO_MEMORY(msg->elements);
|
---|
258 |
|
---|
259 | md = talloc(mem_ctx, struct replPropertyMetaDataBlob);
|
---|
260 | W_ERROR_HAVE_NO_MEMORY(md);
|
---|
261 |
|
---|
262 | md->version = 1;
|
---|
263 | md->reserved = 0;
|
---|
264 | md->ctr.ctr1.count = in->meta_data_ctr->count;
|
---|
265 | md->ctr.ctr1.reserved = 0;
|
---|
266 | md->ctr.ctr1.array = talloc_array(mem_ctx,
|
---|
267 | struct replPropertyMetaData1,
|
---|
268 | md->ctr.ctr1.count + 1); /* +1 because of the RDN attribute */
|
---|
269 | W_ERROR_HAVE_NO_MEMORY(md->ctr.ctr1.array);
|
---|
270 |
|
---|
271 | for (i=0, attr_count=0; i < in->meta_data_ctr->count; i++, attr_count++) {
|
---|
272 | struct drsuapi_DsReplicaAttribute *a;
|
---|
273 | struct drsuapi_DsReplicaMetaData *d;
|
---|
274 | struct replPropertyMetaData1 *m;
|
---|
275 | struct ldb_message_element *e;
|
---|
276 | uint32_t j;
|
---|
277 |
|
---|
278 | a = &in->object.attribute_ctr.attributes[i];
|
---|
279 | d = &in->meta_data_ctr->meta_data[i];
|
---|
280 | m = &md->ctr.ctr1.array[attr_count];
|
---|
281 | e = &msg->elements[attr_count];
|
---|
282 |
|
---|
283 | if (dsdb_attid_in_list(ignore_attids, a->attid)) {
|
---|
284 | attr_count--;
|
---|
285 | continue;
|
---|
286 | }
|
---|
287 |
|
---|
288 | for (j=0; j<a->value_ctr.num_values; j++) {
|
---|
289 | status = drsuapi_decrypt_attribute(a->value_ctr.values[j].blob, gensec_skey, rid, a);
|
---|
290 | W_ERROR_NOT_OK_RETURN(status);
|
---|
291 | }
|
---|
292 |
|
---|
293 | status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, pfm_remote,
|
---|
294 | a, msg->elements, e);
|
---|
295 | W_ERROR_NOT_OK_RETURN(status);
|
---|
296 |
|
---|
297 | m->attid = a->attid;
|
---|
298 | m->version = d->version;
|
---|
299 | m->originating_change_time = d->originating_change_time;
|
---|
300 | m->originating_invocation_id = d->originating_invocation_id;
|
---|
301 | m->originating_usn = d->originating_usn;
|
---|
302 | m->local_usn = 0;
|
---|
303 |
|
---|
304 | if (d->originating_change_time > whenChanged) {
|
---|
305 | whenChanged = d->originating_change_time;
|
---|
306 | }
|
---|
307 |
|
---|
308 | if (a->attid == DRSUAPI_ATTID_name) {
|
---|
309 | name_a = a;
|
---|
310 | name_d = d;
|
---|
311 | }
|
---|
312 | }
|
---|
313 |
|
---|
314 | msg->num_elements = attr_count;
|
---|
315 | md->ctr.ctr1.count = attr_count;
|
---|
316 | if (name_a) {
|
---|
317 | rdn_m = &md->ctr.ctr1.array[md->ctr.ctr1.count];
|
---|
318 | }
|
---|
319 |
|
---|
320 | if (rdn_m) {
|
---|
321 | struct ldb_message_element *el;
|
---|
322 | el = ldb_msg_find_element(msg, rdn_attr->lDAPDisplayName);
|
---|
323 | if (!el) {
|
---|
324 | ret = ldb_msg_add_value(msg, rdn_attr->lDAPDisplayName, rdn_value, NULL);
|
---|
325 | if (ret != LDB_SUCCESS) {
|
---|
326 | return WERR_FOOBAR;
|
---|
327 | }
|
---|
328 | } else {
|
---|
329 | if (el->num_values != 1) {
|
---|
330 | DEBUG(0,(__location__ ": Unexpected num_values=%u\n",
|
---|
331 | el->num_values));
|
---|
332 | return WERR_FOOBAR;
|
---|
333 | }
|
---|
334 | if (!ldb_val_equal_exact(&el->values[0], rdn_value)) {
|
---|
335 | DEBUG(0,(__location__ ": RDN value changed? '%*.*s' '%*.*s'\n",
|
---|
336 | (int)el->values[0].length, (int)el->values[0].length, el->values[0].data,
|
---|
337 | (int)rdn_value->length, (int)rdn_value->length, rdn_value->data));
|
---|
338 | return WERR_FOOBAR;
|
---|
339 | }
|
---|
340 | }
|
---|
341 |
|
---|
342 | rdn_m->attid = rdn_attid;
|
---|
343 | rdn_m->version = name_d->version;
|
---|
344 | rdn_m->originating_change_time = name_d->originating_change_time;
|
---|
345 | rdn_m->originating_invocation_id = name_d->originating_invocation_id;
|
---|
346 | rdn_m->originating_usn = name_d->originating_usn;
|
---|
347 | rdn_m->local_usn = 0;
|
---|
348 | md->ctr.ctr1.count++;
|
---|
349 |
|
---|
350 | }
|
---|
351 |
|
---|
352 | whenChanged_t = nt_time_to_unix(whenChanged);
|
---|
353 | whenChanged_s = ldb_timestring(msg, whenChanged_t);
|
---|
354 | W_ERROR_HAVE_NO_MEMORY(whenChanged_s);
|
---|
355 |
|
---|
356 | nt_status = GUID_to_ndr_blob(&in->object.identifier->guid, msg, &guid_value);
|
---|
357 | if (!NT_STATUS_IS_OK(nt_status)) {
|
---|
358 | return ntstatus_to_werror(nt_status);
|
---|
359 | }
|
---|
360 |
|
---|
361 | out->msg = msg;
|
---|
362 | out->guid_value = guid_value;
|
---|
363 | out->when_changed = whenChanged_s;
|
---|
364 | out->meta_data = md;
|
---|
365 | return WERR_OK;
|
---|
366 | }
|
---|
367 |
|
---|
368 | WERROR dsdb_replicated_objects_convert(struct ldb_context *ldb,
|
---|
369 | const struct dsdb_schema *schema,
|
---|
370 | const char *partition_dn_str,
|
---|
371 | const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr,
|
---|
372 | uint32_t object_count,
|
---|
373 | const struct drsuapi_DsReplicaObjectListItemEx *first_object,
|
---|
374 | uint32_t linked_attributes_count,
|
---|
375 | const struct drsuapi_DsReplicaLinkedAttribute *linked_attributes,
|
---|
376 | const struct repsFromTo1 *source_dsa,
|
---|
377 | const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector,
|
---|
378 | const DATA_BLOB *gensec_skey,
|
---|
379 | TALLOC_CTX *mem_ctx,
|
---|
380 | struct dsdb_extended_replicated_objects **objects)
|
---|
381 | {
|
---|
382 | WERROR status;
|
---|
383 | struct ldb_dn *partition_dn;
|
---|
384 | struct dsdb_schema_prefixmap *pfm_remote;
|
---|
385 | struct dsdb_extended_replicated_objects *out;
|
---|
386 | const struct drsuapi_DsReplicaObjectListItemEx *cur;
|
---|
387 | uint32_t i;
|
---|
388 |
|
---|
389 | out = talloc_zero(mem_ctx, struct dsdb_extended_replicated_objects);
|
---|
390 | W_ERROR_HAVE_NO_MEMORY(out);
|
---|
391 | out->version = DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION;
|
---|
392 |
|
---|
393 | /*
|
---|
394 | * Ensure schema is kept valid for as long as 'out'
|
---|
395 | * which may contain pointers to it
|
---|
396 | */
|
---|
397 | schema = talloc_reference(out, schema);
|
---|
398 | W_ERROR_HAVE_NO_MEMORY(schema);
|
---|
399 |
|
---|
400 | partition_dn = ldb_dn_new(out, ldb, partition_dn_str);
|
---|
401 | W_ERROR_HAVE_NO_MEMORY_AND_FREE(partition_dn, out);
|
---|
402 |
|
---|
403 | status = dsdb_schema_pfm_from_drsuapi_pfm(mapping_ctr, true,
|
---|
404 | out, &pfm_remote, NULL);
|
---|
405 | if (!W_ERROR_IS_OK(status)) {
|
---|
406 | DEBUG(0,(__location__ ": Failed to decode remote prefixMap: %s",
|
---|
407 | win_errstr(status)));
|
---|
408 | talloc_free(out);
|
---|
409 | return status;
|
---|
410 | }
|
---|
411 |
|
---|
412 | if (ldb_dn_compare(partition_dn, ldb_get_schema_basedn(ldb)) != 0) {
|
---|
413 | /*
|
---|
414 | * check for schema changes in case
|
---|
415 | * we are not replicating Schema NC
|
---|
416 | */
|
---|
417 | status = dsdb_schema_info_cmp(schema, mapping_ctr);
|
---|
418 | if (!W_ERROR_IS_OK(status)) {
|
---|
419 | DEBUG(1,("Remote schema has changed while replicating %s\n",
|
---|
420 | partition_dn_str));
|
---|
421 | talloc_free(out);
|
---|
422 | return status;
|
---|
423 | }
|
---|
424 | }
|
---|
425 |
|
---|
426 | out->partition_dn = partition_dn;
|
---|
427 |
|
---|
428 | out->source_dsa = source_dsa;
|
---|
429 | out->uptodateness_vector= uptodateness_vector;
|
---|
430 |
|
---|
431 | out->num_objects = object_count;
|
---|
432 | out->objects = talloc_array(out,
|
---|
433 | struct dsdb_extended_replicated_object,
|
---|
434 | out->num_objects);
|
---|
435 | W_ERROR_HAVE_NO_MEMORY_AND_FREE(out->objects, out);
|
---|
436 |
|
---|
437 | /* pass the linked attributes down to the repl_meta_data
|
---|
438 | module */
|
---|
439 | out->linked_attributes_count = linked_attributes_count;
|
---|
440 | out->linked_attributes = linked_attributes;
|
---|
441 |
|
---|
442 | for (i=0, cur = first_object; cur; cur = cur->next_object, i++) {
|
---|
443 | if (i == out->num_objects) {
|
---|
444 | talloc_free(out);
|
---|
445 | return WERR_FOOBAR;
|
---|
446 | }
|
---|
447 |
|
---|
448 | status = dsdb_convert_object_ex(ldb, schema, pfm_remote,
|
---|
449 | cur, gensec_skey,
|
---|
450 | NULL,
|
---|
451 | out->objects, &out->objects[i]);
|
---|
452 | if (!W_ERROR_IS_OK(status)) {
|
---|
453 | talloc_free(out);
|
---|
454 | DEBUG(0,("Failed to convert object %s: %s\n",
|
---|
455 | cur->object.identifier->dn,
|
---|
456 | win_errstr(status)));
|
---|
457 | return status;
|
---|
458 | }
|
---|
459 | }
|
---|
460 | if (i != out->num_objects) {
|
---|
461 | talloc_free(out);
|
---|
462 | return WERR_FOOBAR;
|
---|
463 | }
|
---|
464 |
|
---|
465 | /* free pfm_remote, we won't need it anymore */
|
---|
466 | talloc_free(pfm_remote);
|
---|
467 |
|
---|
468 | *objects = out;
|
---|
469 | return WERR_OK;
|
---|
470 | }
|
---|
471 |
|
---|
472 | /**
|
---|
473 | * Commits a list of replicated objects.
|
---|
474 | *
|
---|
475 | * @param working_schema dsdb_schema to be used for resolving
|
---|
476 | * Classes/Attributes during Schema replication. If not NULL,
|
---|
477 | * it will be set on ldb and used while committing replicated objects
|
---|
478 | */
|
---|
479 | WERROR dsdb_replicated_objects_commit(struct ldb_context *ldb,
|
---|
480 | struct dsdb_schema *working_schema,
|
---|
481 | struct dsdb_extended_replicated_objects *objects,
|
---|
482 | uint64_t *notify_uSN)
|
---|
483 | {
|
---|
484 | WERROR werr;
|
---|
485 | struct ldb_result *ext_res;
|
---|
486 | struct dsdb_schema *cur_schema = NULL;
|
---|
487 | int ret;
|
---|
488 | uint64_t seq_num1, seq_num2;
|
---|
489 |
|
---|
490 | /* TODO: handle linked attributes */
|
---|
491 |
|
---|
492 | /* wrap the extended operation in a transaction
|
---|
493 | See [MS-DRSR] 3.3.2 Transactions
|
---|
494 | */
|
---|
495 | ret = ldb_transaction_start(ldb);
|
---|
496 | if (ret != LDB_SUCCESS) {
|
---|
497 | DEBUG(0,(__location__ " Failed to start transaction\n"));
|
---|
498 | return WERR_FOOBAR;
|
---|
499 | }
|
---|
500 |
|
---|
501 | ret = dsdb_load_partition_usn(ldb, objects->partition_dn, &seq_num1, NULL);
|
---|
502 | if (ret != LDB_SUCCESS) {
|
---|
503 | DEBUG(0,(__location__ " Failed to load partition uSN\n"));
|
---|
504 | ldb_transaction_cancel(ldb);
|
---|
505 | return WERR_FOOBAR;
|
---|
506 | }
|
---|
507 |
|
---|
508 | /*
|
---|
509 | * Set working_schema for ldb in case we are replicating from Schema NC.
|
---|
510 | * Schema won't be reloaded during Replicated Objects commit, as it is
|
---|
511 | * done in a transaction. So we need some way to search for newly
|
---|
512 | * added Classes and Attributes
|
---|
513 | */
|
---|
514 | if (working_schema) {
|
---|
515 | /* store current schema so we can fall back in case of failure */
|
---|
516 | cur_schema = dsdb_get_schema(ldb, working_schema);
|
---|
517 |
|
---|
518 | ret = dsdb_reference_schema(ldb, working_schema, false);
|
---|
519 | if (ret != LDB_SUCCESS) {
|
---|
520 | DEBUG(0,(__location__ "Failed to reference working schema - %s\n",
|
---|
521 | ldb_strerror(ret)));
|
---|
522 | /* TODO: Map LDB Error to NTSTATUS? */
|
---|
523 | ldb_transaction_cancel(ldb);
|
---|
524 | return WERR_INTERNAL_ERROR;
|
---|
525 | }
|
---|
526 | }
|
---|
527 |
|
---|
528 | ret = ldb_extended(ldb, DSDB_EXTENDED_REPLICATED_OBJECTS_OID, objects, &ext_res);
|
---|
529 | if (ret != LDB_SUCCESS) {
|
---|
530 | /* restore previous schema */
|
---|
531 | if (cur_schema ) {
|
---|
532 | dsdb_reference_schema(ldb, cur_schema, false);
|
---|
533 | dsdb_make_schema_global(ldb, cur_schema);
|
---|
534 | }
|
---|
535 |
|
---|
536 | DEBUG(0,("Failed to apply records: %s: %s\n",
|
---|
537 | ldb_errstring(ldb), ldb_strerror(ret)));
|
---|
538 | ldb_transaction_cancel(ldb);
|
---|
539 | return WERR_FOOBAR;
|
---|
540 | }
|
---|
541 | talloc_free(ext_res);
|
---|
542 |
|
---|
543 | /* Save our updated prefixMap */
|
---|
544 | if (working_schema) {
|
---|
545 | werr = dsdb_write_prefixes_from_schema_to_ldb(working_schema,
|
---|
546 | ldb,
|
---|
547 | working_schema);
|
---|
548 | if (!W_ERROR_IS_OK(werr)) {
|
---|
549 | /* restore previous schema */
|
---|
550 | if (cur_schema ) {
|
---|
551 | dsdb_reference_schema(ldb, cur_schema, false);
|
---|
552 | dsdb_make_schema_global(ldb, cur_schema);
|
---|
553 | }
|
---|
554 | DEBUG(0,("Failed to save updated prefixMap: %s\n",
|
---|
555 | win_errstr(werr)));
|
---|
556 | return werr;
|
---|
557 | }
|
---|
558 | }
|
---|
559 |
|
---|
560 | ret = ldb_transaction_prepare_commit(ldb);
|
---|
561 | if (ret != LDB_SUCCESS) {
|
---|
562 | /* restore previous schema */
|
---|
563 | if (cur_schema ) {
|
---|
564 | dsdb_reference_schema(ldb, cur_schema, false);
|
---|
565 | dsdb_make_schema_global(ldb, cur_schema);
|
---|
566 | }
|
---|
567 | DEBUG(0,(__location__ " Failed to prepare commit of transaction: %s\n",
|
---|
568 | ldb_errstring(ldb)));
|
---|
569 | return WERR_FOOBAR;
|
---|
570 | }
|
---|
571 |
|
---|
572 | ret = dsdb_load_partition_usn(ldb, objects->partition_dn, &seq_num2, NULL);
|
---|
573 | if (ret != LDB_SUCCESS) {
|
---|
574 | /* restore previous schema */
|
---|
575 | if (cur_schema ) {
|
---|
576 | dsdb_reference_schema(ldb, cur_schema, false);
|
---|
577 | dsdb_make_schema_global(ldb, cur_schema);
|
---|
578 | }
|
---|
579 | DEBUG(0,(__location__ " Failed to load partition uSN\n"));
|
---|
580 | ldb_transaction_cancel(ldb);
|
---|
581 | return WERR_FOOBAR;
|
---|
582 | }
|
---|
583 |
|
---|
584 | /* if this replication partner didn't need to be notified
|
---|
585 | before this transaction then it still doesn't need to be
|
---|
586 | notified, as the changes came from this server */
|
---|
587 | if (seq_num2 > seq_num1 && seq_num1 <= *notify_uSN) {
|
---|
588 | *notify_uSN = seq_num2;
|
---|
589 | }
|
---|
590 |
|
---|
591 | ret = ldb_transaction_commit(ldb);
|
---|
592 | if (ret != LDB_SUCCESS) {
|
---|
593 | /* restore previous schema */
|
---|
594 | if (cur_schema ) {
|
---|
595 | dsdb_reference_schema(ldb, cur_schema, false);
|
---|
596 | dsdb_make_schema_global(ldb, cur_schema);
|
---|
597 | }
|
---|
598 | DEBUG(0,(__location__ " Failed to commit transaction\n"));
|
---|
599 | return WERR_FOOBAR;
|
---|
600 | }
|
---|
601 |
|
---|
602 | /*
|
---|
603 | * Reset the Schema used by ldb. This will lead to
|
---|
604 | * a schema cache being refreshed from database.
|
---|
605 | */
|
---|
606 | if (working_schema) {
|
---|
607 | cur_schema = dsdb_get_schema(ldb, NULL);
|
---|
608 | /* TODO: What we do in case dsdb_get_schema() fail?
|
---|
609 | * We can't fallback at this point anymore */
|
---|
610 | if (cur_schema) {
|
---|
611 | dsdb_make_schema_global(ldb, cur_schema);
|
---|
612 | }
|
---|
613 | }
|
---|
614 |
|
---|
615 | DEBUG(2,("Replicated %u objects (%u linked attributes) for %s\n",
|
---|
616 | objects->num_objects, objects->linked_attributes_count,
|
---|
617 | ldb_dn_get_linearized(objects->partition_dn)));
|
---|
618 |
|
---|
619 | return WERR_OK;
|
---|
620 | }
|
---|
621 |
|
---|
622 | static WERROR dsdb_origin_object_convert(struct ldb_context *ldb,
|
---|
623 | const struct dsdb_schema *schema,
|
---|
624 | const struct drsuapi_DsReplicaObjectListItem *in,
|
---|
625 | TALLOC_CTX *mem_ctx,
|
---|
626 | struct ldb_message **_msg)
|
---|
627 | {
|
---|
628 | WERROR status;
|
---|
629 | unsigned int i;
|
---|
630 | struct ldb_message *msg;
|
---|
631 |
|
---|
632 | if (!in->object.identifier) {
|
---|
633 | return WERR_FOOBAR;
|
---|
634 | }
|
---|
635 |
|
---|
636 | if (!in->object.identifier->dn || !in->object.identifier->dn[0]) {
|
---|
637 | return WERR_FOOBAR;
|
---|
638 | }
|
---|
639 |
|
---|
640 | msg = ldb_msg_new(mem_ctx);
|
---|
641 | W_ERROR_HAVE_NO_MEMORY(msg);
|
---|
642 |
|
---|
643 | msg->dn = ldb_dn_new(msg, ldb, in->object.identifier->dn);
|
---|
644 | W_ERROR_HAVE_NO_MEMORY(msg->dn);
|
---|
645 |
|
---|
646 | msg->num_elements = in->object.attribute_ctr.num_attributes;
|
---|
647 | msg->elements = talloc_array(msg, struct ldb_message_element,
|
---|
648 | msg->num_elements);
|
---|
649 | W_ERROR_HAVE_NO_MEMORY(msg->elements);
|
---|
650 |
|
---|
651 | for (i=0; i < msg->num_elements; i++) {
|
---|
652 | struct drsuapi_DsReplicaAttribute *a;
|
---|
653 | struct ldb_message_element *e;
|
---|
654 |
|
---|
655 | a = &in->object.attribute_ctr.attributes[i];
|
---|
656 | e = &msg->elements[i];
|
---|
657 |
|
---|
658 | status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, schema->prefixmap,
|
---|
659 | a, msg->elements, e);
|
---|
660 | W_ERROR_NOT_OK_RETURN(status);
|
---|
661 | }
|
---|
662 |
|
---|
663 |
|
---|
664 | *_msg = msg;
|
---|
665 |
|
---|
666 | return WERR_OK;
|
---|
667 | }
|
---|
668 |
|
---|
669 | WERROR dsdb_origin_objects_commit(struct ldb_context *ldb,
|
---|
670 | TALLOC_CTX *mem_ctx,
|
---|
671 | const struct drsuapi_DsReplicaObjectListItem *first_object,
|
---|
672 | uint32_t *_num,
|
---|
673 | struct drsuapi_DsReplicaObjectIdentifier2 **_ids)
|
---|
674 | {
|
---|
675 | WERROR status;
|
---|
676 | const struct dsdb_schema *schema;
|
---|
677 | const struct drsuapi_DsReplicaObjectListItem *cur;
|
---|
678 | struct ldb_message **objects;
|
---|
679 | struct drsuapi_DsReplicaObjectIdentifier2 *ids;
|
---|
680 | uint32_t i;
|
---|
681 | uint32_t num_objects = 0;
|
---|
682 | const char * const attrs[] = {
|
---|
683 | "objectGUID",
|
---|
684 | "objectSid",
|
---|
685 | NULL
|
---|
686 | };
|
---|
687 | struct ldb_result *res;
|
---|
688 | int ret;
|
---|
689 |
|
---|
690 | for (cur = first_object; cur; cur = cur->next_object) {
|
---|
691 | num_objects++;
|
---|
692 | }
|
---|
693 |
|
---|
694 | if (num_objects == 0) {
|
---|
695 | return WERR_OK;
|
---|
696 | }
|
---|
697 |
|
---|
698 | ret = ldb_transaction_start(ldb);
|
---|
699 | if (ret != LDB_SUCCESS) {
|
---|
700 | return WERR_DS_INTERNAL_FAILURE;
|
---|
701 | }
|
---|
702 |
|
---|
703 | objects = talloc_array(mem_ctx, struct ldb_message *,
|
---|
704 | num_objects);
|
---|
705 | if (objects == NULL) {
|
---|
706 | status = WERR_NOMEM;
|
---|
707 | goto cancel;
|
---|
708 | }
|
---|
709 |
|
---|
710 | schema = dsdb_get_schema(ldb, objects);
|
---|
711 | if (!schema) {
|
---|
712 | return WERR_DS_SCHEMA_NOT_LOADED;
|
---|
713 | }
|
---|
714 |
|
---|
715 | for (i=0, cur = first_object; cur; cur = cur->next_object, i++) {
|
---|
716 | status = dsdb_origin_object_convert(ldb, schema, cur,
|
---|
717 | objects, &objects[i]);
|
---|
718 | if (!W_ERROR_IS_OK(status)) {
|
---|
719 | goto cancel;
|
---|
720 | }
|
---|
721 | }
|
---|
722 |
|
---|
723 | ids = talloc_array(mem_ctx,
|
---|
724 | struct drsuapi_DsReplicaObjectIdentifier2,
|
---|
725 | num_objects);
|
---|
726 | if (ids == NULL) {
|
---|
727 | status = WERR_NOMEM;
|
---|
728 | goto cancel;
|
---|
729 | }
|
---|
730 |
|
---|
731 | for (i=0; i < num_objects; i++) {
|
---|
732 | struct dom_sid *sid = NULL;
|
---|
733 | struct ldb_request *add_req;
|
---|
734 |
|
---|
735 | DEBUG(6,(__location__ ": adding %s\n",
|
---|
736 | ldb_dn_get_linearized(objects[i]->dn)));
|
---|
737 |
|
---|
738 | ret = ldb_build_add_req(&add_req,
|
---|
739 | ldb,
|
---|
740 | objects,
|
---|
741 | objects[i],
|
---|
742 | NULL,
|
---|
743 | NULL,
|
---|
744 | ldb_op_default_callback,
|
---|
745 | NULL);
|
---|
746 | if (ret != LDB_SUCCESS) {
|
---|
747 | status = WERR_DS_INTERNAL_FAILURE;
|
---|
748 | goto cancel;
|
---|
749 | }
|
---|
750 |
|
---|
751 | ret = ldb_request_add_control(add_req, LDB_CONTROL_RELAX_OID, true, NULL);
|
---|
752 | if (ret != LDB_SUCCESS) {
|
---|
753 | status = WERR_DS_INTERNAL_FAILURE;
|
---|
754 | goto cancel;
|
---|
755 | }
|
---|
756 |
|
---|
757 | ret = ldb_request(ldb, add_req);
|
---|
758 | if (ret == LDB_SUCCESS) {
|
---|
759 | ret = ldb_wait(add_req->handle, LDB_WAIT_ALL);
|
---|
760 | }
|
---|
761 | if (ret != LDB_SUCCESS) {
|
---|
762 | DEBUG(0,(__location__ ": Failed add of %s - %s\n",
|
---|
763 | ldb_dn_get_linearized(objects[i]->dn), ldb_errstring(ldb)));
|
---|
764 | status = WERR_DS_INTERNAL_FAILURE;
|
---|
765 | goto cancel;
|
---|
766 | }
|
---|
767 |
|
---|
768 | talloc_free(add_req);
|
---|
769 |
|
---|
770 | ret = ldb_search(ldb, objects, &res, objects[i]->dn,
|
---|
771 | LDB_SCOPE_BASE, attrs,
|
---|
772 | "(objectClass=*)");
|
---|
773 | if (ret != LDB_SUCCESS) {
|
---|
774 | status = WERR_DS_INTERNAL_FAILURE;
|
---|
775 | goto cancel;
|
---|
776 | }
|
---|
777 | ids[i].guid = samdb_result_guid(res->msgs[0], "objectGUID");
|
---|
778 | sid = samdb_result_dom_sid(objects, res->msgs[0], "objectSid");
|
---|
779 | if (sid) {
|
---|
780 | ids[i].sid = *sid;
|
---|
781 | } else {
|
---|
782 | ZERO_STRUCT(ids[i].sid);
|
---|
783 | }
|
---|
784 | }
|
---|
785 |
|
---|
786 | ret = ldb_transaction_commit(ldb);
|
---|
787 | if (ret != LDB_SUCCESS) {
|
---|
788 | return WERR_DS_INTERNAL_FAILURE;
|
---|
789 | }
|
---|
790 |
|
---|
791 | talloc_free(objects);
|
---|
792 |
|
---|
793 | *_num = num_objects;
|
---|
794 | *_ids = ids;
|
---|
795 | return WERR_OK;
|
---|
796 |
|
---|
797 | cancel:
|
---|
798 | talloc_free(objects);
|
---|
799 | ldb_transaction_cancel(ldb);
|
---|
800 | return status;
|
---|
801 | }
|
---|