1 /*
2    Unix SMB/CIFS implementation.
3 
4    DRSUAPI schemaInfo unit tests
5 
6    Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2010
7 
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21 
22 #include "includes.h"
23 #include "system/filesys.h"
24 #include "torture/smbtorture.h"
25 #include "dsdb/samdb/samdb.h"
26 #include "dsdb/samdb/ldb_modules/util.h"
27 #include "ldb_wrap.h"
28 #include <ldb_module.h>
29 #include "torture/rpc/drsuapi.h"
30 #include "librpc/ndr/libndr.h"
31 #include "param/param.h"
32 #include "torture/drs/proto.h"
33 #include "torture/drs/proto.h"
34 
35 
36 /**
37  * schemaInfo to init ldb context with
38  *   Rev:  0
39  *   GUID: 00000000-0000-0000-0000-000000000000
40  */
41 #define SCHEMA_INFO_INIT_STR		"FF0000000000000000000000000000000000000000"
42 
43 /**
44  * Default schema_info string to be used for testing
45  *   Rev:  01
46  *   GUID: 071c82fd-45c7-4351-a3db-51f75a630a7f
47  */
48 #define SCHEMA_INFO_DEFAULT_STR 	"FF00000001FD821C07C7455143A3DB51F75A630A7F"
49 
50 /**
51  * Schema info data to test with
52  */
53 struct schemainfo_data {
54 	DATA_BLOB 	ndr_blob;
55 	struct dsdb_schema_info schi;
56 	WERROR		werr_expected;
57 	bool 		test_both_ways;
58 };
59 
60 /**
61  * Schema info test data in human-readable format (... kind of)
62  */
63 static const struct {
64 	const char 	*schema_info_str;
65 	uint32_t	revision;
66 	const char	*guid_str;
67 	WERROR		werr_expected;
68 	bool 		test_both_ways;
69 } _schemainfo_test_data[] = {
70 	{
71 		.schema_info_str = "FF0000000000000000000000000000000000000000",
72 		.revision = 0,
73 		.guid_str = "00000000-0000-0000-0000-000000000000",
74 		.werr_expected = WERR_OK,
75 		.test_both_ways = true
76 	},
77 	{
78 		.schema_info_str = "FF00000001FD821C07C7455143A3DB51F75A630A7F",
79 		.revision = 1,
80 		.guid_str = "071c82fd-45c7-4351-a3db-51f75a630a7f",
81 		.werr_expected = WERR_OK,
82 		.test_both_ways = true
83 	},
84 	{
85 		.schema_info_str = "FFFFFFFFFFFD821C07C7455143A3DB51F75A630A7F",
86 		.revision = 0xFFFFFFFF,
87 		.guid_str = "071c82fd-45c7-4351-a3db-51f75a630a7f",
88 		.werr_expected = WERR_OK,
89 		.test_both_ways = true
90 	},
91 	{ /* len == 21 */
92 		.schema_info_str = "FF00000001FD821C07C7455143A3DB51F75A630A7F00",
93 		.revision = 1,
94 		.guid_str = "071c82fd-45c7-4351-a3db-51f75a630a7f",
95 		.werr_expected = WERR_INVALID_PARAMETER,
96 		.test_both_ways = false
97 	},
98 	{ /* marker == FF */
99 		.schema_info_str = "AA00000001FD821C07C7455143A3DB51F75A630A7F",
100 		.revision = 1,
101 		.guid_str = "071c82fd-45c7-4351-a3db-51f75a630a7f",
102 		.werr_expected = WERR_INVALID_PARAMETER,
103 		.test_both_ways = false
104 	}
105 };
106 
107 /**
108  * Private data to be shared among all test in Test case
109  */
110 struct drsut_schemainfo_data {
111 	struct ldb_context *ldb;
112 	struct ldb_module  *ldb_module;
113 	struct dsdb_schema *schema;
114 
115 	/* Initial schemaInfo set in ldb to test with */
116 	struct dsdb_schema_info *schema_info;
117 
118 	uint32_t test_data_count;
119 	struct schemainfo_data *test_data;
120 };
121 
122 /**
123  * torture macro to assert for equal dsdb_schema_info's
124  */
125 #define torture_assert_schema_info_equal(torture_ctx,got,expected,cmt)\
126 	do { const struct dsdb_schema_info *__got = (got), *__expected = (expected); \
127 	if (__got->revision != __expected->revision) { \
128 		torture_result(torture_ctx, TORTURE_FAIL, \
129 			       __location__": "#got".revision %d did not match "#expected".revision %d: %s", \
130 			       (int)__got->revision, (int)__expected->revision, cmt); \
131 		return false; \
132 	} \
133 	if (!GUID_equal(&__got->invocation_id, &__expected->invocation_id)) { \
134 		torture_result(torture_ctx, TORTURE_FAIL, \
135 			       __location__": "#got".invocation_id did not match "#expected".invocation_id: %s", cmt); \
136 		return false; \
137 	} \
138 	} while(0)
139 
140 /*
141  * forward declaration for internal functions
142  */
143 static bool _drsut_ldb_schema_info_reset(struct torture_context *tctx,
144 					 struct ldb_context *ldb,
145 					 const char *schema_info_str,
146 					 bool in_setup);
147 
148 
149 /**
150  * Creates dsdb_schema_info object based on NDR data
151  * passed as hex string
152  */
_drsut_schemainfo_new(struct torture_context * tctx,const char * schema_info_str,struct dsdb_schema_info ** _si)153 static bool _drsut_schemainfo_new(struct torture_context *tctx,
154 				  const char *schema_info_str, struct dsdb_schema_info **_si)
155 {
156 	WERROR werr;
157 	DATA_BLOB blob;
158 
159 	blob = strhex_to_data_blob(tctx, schema_info_str);
160 	if (!blob.data) {
161 		torture_comment(tctx, "Not enough memory!\n");
162 		return false;
163 	}
164 
165 	werr = dsdb_schema_info_from_blob(&blob, tctx, _si);
166 	if (!W_ERROR_IS_OK(werr)) {
167 		torture_comment(tctx,
168 		                "Failed to create dsdb_schema_info object for %s: %s",
169 		                schema_info_str,
170 		                win_errstr(werr));
171 		return false;
172 	}
173 
174 	data_blob_free(&blob);
175 
176 	return true;
177 }
178 
179 /**
180  * Creates dsdb_schema_info object based on predefined data
181  * Function is public as it is intended to be used by other
182  * tests (e.g. prefixMap tests)
183  */
drsut_schemainfo_new(struct torture_context * tctx,struct dsdb_schema_info ** _si)184 bool drsut_schemainfo_new(struct torture_context *tctx, struct dsdb_schema_info **_si)
185 {
186 	return _drsut_schemainfo_new(tctx, SCHEMA_INFO_DEFAULT_STR, _si);
187 }
188 
189 
190 /*
191  * Tests dsdb_schema_info_new() and dsdb_schema_info_blob_new()
192  */
test_dsdb_schema_info_new(struct torture_context * tctx,struct drsut_schemainfo_data * priv)193 static bool test_dsdb_schema_info_new(struct torture_context *tctx,
194 				      struct drsut_schemainfo_data *priv)
195 {
196 	WERROR werr;
197 	DATA_BLOB ndr_blob;
198 	DATA_BLOB ndr_blob_expected;
199 	struct dsdb_schema_info *schi;
200 	TALLOC_CTX *mem_ctx;
201 
202 	mem_ctx = talloc_new(priv);
203 	torture_assert(tctx, mem_ctx, "Not enough memory!");
204 	ndr_blob_expected = strhex_to_data_blob(mem_ctx, SCHEMA_INFO_INIT_STR);
205 	torture_assert(tctx, ndr_blob_expected.data, "Not enough memory!");
206 
207 	werr = dsdb_schema_info_new(mem_ctx, &schi);
208 	torture_assert_werr_ok(tctx, werr, "dsdb_schema_info_new() failed");
209 	torture_assert_int_equal(tctx, schi->revision, 0,
210 				 "dsdb_schema_info_new() creates schemaInfo with invalid revision");
211 	torture_assert(tctx, GUID_all_zero(&schi->invocation_id),
212 			"dsdb_schema_info_new() creates schemaInfo with not ZERO GUID");
213 
214 	werr = dsdb_schema_info_blob_new(mem_ctx, &ndr_blob);
215 	torture_assert_werr_ok(tctx, werr, "dsdb_schema_info_blob_new() failed");
216 	torture_assert_data_blob_equal(tctx, ndr_blob, ndr_blob_expected,
217 				       "dsdb_schema_info_blob_new() returned invalid blob");
218 
219 	talloc_free(mem_ctx);
220 	return true;
221 }
222 
223 /*
224  * Tests dsdb_schema_info_from_blob()
225  */
test_dsdb_schema_info_from_blob(struct torture_context * tctx,struct drsut_schemainfo_data * priv)226 static bool test_dsdb_schema_info_from_blob(struct torture_context *tctx,
227 					    struct drsut_schemainfo_data *priv)
228 {
229 	int i;
230 	WERROR werr;
231 	char *msg;
232 	struct dsdb_schema_info *schema_info;
233 	TALLOC_CTX *mem_ctx;
234 
235 	mem_ctx = talloc_new(priv);
236 	torture_assert(tctx, mem_ctx, "Not enough memory!");
237 
238 	for (i = 0; i < priv->test_data_count; i++) {
239 		struct schemainfo_data *data = &priv->test_data[i];
240 
241 		msg = talloc_asprintf(tctx, "dsdb_schema_info_from_blob() [%d]-[%s]",
242 		                      i, _schemainfo_test_data[i].schema_info_str);
243 
244 		werr = dsdb_schema_info_from_blob(&data->ndr_blob, mem_ctx, &schema_info);
245 		torture_assert_werr_equal(tctx, werr, data->werr_expected, msg);
246 
247 		/* test returned data */
248 		if (W_ERROR_IS_OK(werr)) {
249 			torture_assert_schema_info_equal(tctx,
250 			                                 schema_info, &data->schi,
251 			                                 "after dsdb_schema_info_from_blob() call");
252 		}
253 	}
254 
255 	talloc_free(mem_ctx);
256 
257 	return true;
258 }
259 
260 /*
261  * Tests dsdb_blob_from_schema_info()
262  */
test_dsdb_blob_from_schema_info(struct torture_context * tctx,struct drsut_schemainfo_data * priv)263 static bool test_dsdb_blob_from_schema_info(struct torture_context *tctx,
264 					    struct drsut_schemainfo_data *priv)
265 {
266 	int i;
267 	WERROR werr;
268 	char *msg;
269 	DATA_BLOB ndr_blob;
270 	TALLOC_CTX *mem_ctx;
271 
272 	mem_ctx = talloc_new(priv);
273 	torture_assert(tctx, mem_ctx, "Not enough memory!");
274 
275 	for (i = 0; i < priv->test_data_count; i++) {
276 		struct schemainfo_data *data = &priv->test_data[i];
277 
278 		/* not all test are valid reverse type of conversion */
279 		if (!data->test_both_ways) {
280 			continue;
281 		}
282 
283 		msg = talloc_asprintf(tctx, "dsdb_blob_from_schema_info() [%d]-[%s]",
284 		                      i, _schemainfo_test_data[i].schema_info_str);
285 
286 		werr = dsdb_blob_from_schema_info(&data->schi, mem_ctx, &ndr_blob);
287 		torture_assert_werr_equal(tctx, werr, data->werr_expected, msg);
288 
289 		/* test returned data */
290 		if (W_ERROR_IS_OK(werr)) {
291 			torture_assert_data_blob_equal(tctx,
292 			                               ndr_blob, data->ndr_blob,
293 			                               "dsdb_blob_from_schema_info()");
294 		}
295 	}
296 
297 	talloc_free(mem_ctx);
298 
299 	return true;
300 }
301 
test_dsdb_schema_info_cmp(struct torture_context * tctx,struct drsut_schemainfo_data * priv)302 static bool test_dsdb_schema_info_cmp(struct torture_context *tctx,
303 				      struct drsut_schemainfo_data *priv)
304 {
305 	DATA_BLOB blob;
306 	struct drsuapi_DsReplicaOIDMapping_Ctr *ctr;
307 	struct dsdb_schema_info schema_info;
308 
309 	ctr = talloc_zero(priv, struct drsuapi_DsReplicaOIDMapping_Ctr);
310 	torture_assert(tctx, ctr, "Not enough memory!");
311 
312 	/* not enough elements */
313 	torture_assert_werr_equal(tctx,
314 				  dsdb_schema_info_cmp(priv->schema, ctr),
315 				  WERR_INVALID_PARAMETER,
316 				  "dsdb_schema_info_cmp(): unexpected result");
317 
318 	/* an empty element for schemaInfo */
319 	ctr->num_mappings = 1;
320 	ctr->mappings = talloc_zero_array(ctr, struct drsuapi_DsReplicaOIDMapping, 1);
321 	torture_assert(tctx, ctr->mappings, "Not enough memory!");
322 	torture_assert_werr_equal(tctx,
323 				  dsdb_schema_info_cmp(priv->schema, ctr),
324 				  WERR_INVALID_PARAMETER,
325 				  "dsdb_schema_info_cmp(): unexpected result");
326 
327 	/* test with invalid schemaInfo - length != 21 */
328 	blob = strhex_to_data_blob(ctr, "FF00000001FD821C07C7455143A3DB51F75A630A7F00");
329 	torture_assert(tctx, blob.data, "Not enough memory!");
330 	ctr->mappings[0].oid.length     = blob.length;
331 	ctr->mappings[0].oid.binary_oid = blob.data;
332 	torture_assert_werr_equal(tctx,
333 				  dsdb_schema_info_cmp(priv->schema, ctr),
334 				  WERR_INVALID_PARAMETER,
335 				  "dsdb_schema_info_cmp(): unexpected result");
336 
337 	/* test with invalid schemaInfo - marker != 0xFF */
338 	blob = strhex_to_data_blob(ctr, "AA00000001FD821C07C7455143A3DB51F75A630A7F");
339 	torture_assert(tctx, blob.data, "Not enough memory!");
340 	ctr->mappings[0].oid.length     = blob.length;
341 	ctr->mappings[0].oid.binary_oid = blob.data;
342 	torture_assert_werr_equal(tctx,
343 				  dsdb_schema_info_cmp(priv->schema, ctr),
344 				  WERR_INVALID_PARAMETER,
345 				  "dsdb_schema_info_cmp(): unexpected result");
346 
347 	/* test with valid schemaInfo, but older one should be ok */
348 	blob = strhex_to_data_blob(ctr, "FF0000000000000000000000000000000000000000");
349 	torture_assert(tctx, blob.data, "Not enough memory!");
350 	ctr->mappings[0].oid.length     = blob.length;
351 	ctr->mappings[0].oid.binary_oid = blob.data;
352 	torture_assert_werr_equal(tctx,
353 				  dsdb_schema_info_cmp(priv->schema, ctr),
354 				  WERR_OK,
355 				  "dsdb_schema_info_cmp(): unexpected result");
356 
357 	/* test with correct schemaInfo, but invalid ATTID */
358 	schema_info = *priv->schema->schema_info;
359 	torture_assert_werr_ok(tctx,
360 		dsdb_blob_from_schema_info(&schema_info, tctx, &blob),
361 		"dsdb_blob_from_schema_info() failed");
362 	ctr->mappings[0].id_prefix	= 1;
363 	ctr->mappings[0].oid.length     = blob.length;
364 	ctr->mappings[0].oid.binary_oid = blob.data;
365 	torture_assert_werr_equal(tctx,
366 				  dsdb_schema_info_cmp(priv->schema, ctr),
367 				  WERR_INVALID_PARAMETER,
368 				  "dsdb_schema_info_cmp(): unexpected result");
369 
370 	/* test with valid schemaInfo */
371 	ctr->mappings[0].id_prefix	= 0;
372 	torture_assert_werr_ok(tctx,
373 			       dsdb_schema_info_cmp(priv->schema, ctr),
374 			       "dsdb_schema_info_cmp(): unexpected result");
375 
376 	/* test with valid schemaInfo, but older revision */
377 	schema_info = *priv->schema->schema_info;
378 	schema_info.revision -= 1;
379 	torture_assert_werr_ok(tctx,
380 		dsdb_blob_from_schema_info(&schema_info, tctx, &blob),
381 		"dsdb_blob_from_schema_info() failed");
382 	ctr->mappings[0].oid.length     = blob.length;
383 	ctr->mappings[0].oid.binary_oid = blob.data;
384 	torture_assert_werr_equal(tctx,
385 				  dsdb_schema_info_cmp(priv->schema, ctr),
386 				  WERR_OK,
387 				  "dsdb_schema_info_cmp(): unexpected result");
388 
389 	/* test with valid schemaInfo, but newer revision */
390 	schema_info = *priv->schema->schema_info;
391 	schema_info.revision += 1;
392 	torture_assert_werr_ok(tctx,
393 		dsdb_blob_from_schema_info(&schema_info, tctx, &blob),
394 		"dsdb_blob_from_schema_info() failed");
395 	ctr->mappings[0].oid.length     = blob.length;
396 	ctr->mappings[0].oid.binary_oid = blob.data;
397 	torture_assert_werr_equal(tctx,
398 				  dsdb_schema_info_cmp(priv->schema, ctr),
399 				  WERR_DS_DRA_SCHEMA_MISMATCH,
400 				  "dsdb_schema_info_cmp(): unexpected result");
401 
402 	/* test with valid schemaInfo, but newer revision and other invocationId */
403 	schema_info = *priv->schema->schema_info;
404 	schema_info.revision += 1;
405 	schema_info.invocation_id.time_mid += 1;
406 	torture_assert_werr_ok(tctx,
407 		dsdb_blob_from_schema_info(&schema_info, tctx, &blob),
408 		"dsdb_blob_from_schema_info() failed");
409 	ctr->mappings[0].oid.length     = blob.length;
410 	ctr->mappings[0].oid.binary_oid = blob.data;
411 	torture_assert_werr_equal(tctx,
412 				  dsdb_schema_info_cmp(priv->schema, ctr),
413 				  WERR_DS_DRA_SCHEMA_MISMATCH,
414 				  "dsdb_schema_info_cmp(): unexpected result");
415 
416 	/* test with valid schemaInfo, but older revision and other invocationId */
417 	schema_info = *priv->schema->schema_info;
418 	schema_info.revision -= 1;
419 	schema_info.invocation_id.time_mid += 1;
420 	torture_assert_werr_ok(tctx,
421 		dsdb_blob_from_schema_info(&schema_info, tctx, &blob),
422 		"dsdb_blob_from_schema_info() failed");
423 	ctr->mappings[0].oid.length     = blob.length;
424 	ctr->mappings[0].oid.binary_oid = blob.data;
425 	torture_assert_werr_equal(tctx,
426 				  dsdb_schema_info_cmp(priv->schema, ctr),
427 				  WERR_OK,
428 				  "dsdb_schema_info_cmp(): unexpected result");
429 
430 	/* test with valid schemaInfo, but same revision and other invocationId */
431 	schema_info = *priv->schema->schema_info;
432 	schema_info.invocation_id.time_mid += 1;
433 	torture_assert_werr_ok(tctx,
434 		dsdb_blob_from_schema_info(&schema_info, tctx, &blob),
435 		"dsdb_blob_from_schema_info() failed");
436 	ctr->mappings[0].oid.length     = blob.length;
437 	ctr->mappings[0].oid.binary_oid = blob.data;
438 	torture_assert_werr_equal(tctx,
439 				  dsdb_schema_info_cmp(priv->schema, ctr),
440 				  WERR_DS_DRA_SCHEMA_CONFLICT,
441 				  "dsdb_schema_info_cmp(): unexpected result");
442 
443 	talloc_free(ctr);
444 	return true;
445 }
446 
447 /*
448  * Tests dsdb_module_schema_info_blob_read()
449  *   and dsdb_module_schema_info_blob_write()
450  */
test_dsdb_module_schema_info_blob_rw(struct torture_context * tctx,struct drsut_schemainfo_data * priv)451 static bool test_dsdb_module_schema_info_blob_rw(struct torture_context *tctx,
452 						struct drsut_schemainfo_data *priv)
453 {
454 	int ldb_err;
455 	DATA_BLOB blob_write;
456 	DATA_BLOB blob_read;
457 
458 	/* reset schmeInfo to know value */
459 	torture_assert(tctx,
460 		       _drsut_ldb_schema_info_reset(tctx, priv->ldb, SCHEMA_INFO_INIT_STR, false),
461 		       "_drsut_ldb_schema_info_reset() failed");
462 
463 	/* write tests' default schemaInfo */
464 	blob_write = strhex_to_data_blob(priv, SCHEMA_INFO_DEFAULT_STR);
465 	torture_assert(tctx, blob_write.data, "Not enough memory!");
466 
467 	ldb_err = dsdb_module_schema_info_blob_write(priv->ldb_module,
468 						     DSDB_FLAG_TOP_MODULE,
469 						     &blob_write, NULL);
470 	torture_assert_int_equal(tctx, ldb_err, LDB_SUCCESS, "dsdb_module_schema_info_blob_write() failed");
471 
472 	ldb_err = dsdb_module_schema_info_blob_read(priv->ldb_module, DSDB_FLAG_TOP_MODULE,
473 						    priv, &blob_read, NULL);
474 	torture_assert_int_equal(tctx, ldb_err, LDB_SUCCESS, "dsdb_module_schema_info_blob_read() failed");
475 
476 	/* check if we get what we wrote */
477 	torture_assert_data_blob_equal(tctx, blob_read, blob_write,
478 				       "Write/Read of schemeInfo blob failed");
479 
480 	return true;
481 }
482 
483 /*
484  * Tests dsdb_schema_update_schema_info()
485  */
test_dsdb_module_schema_info_update(struct torture_context * tctx,struct drsut_schemainfo_data * priv)486 static bool test_dsdb_module_schema_info_update(struct torture_context *tctx,
487 						struct drsut_schemainfo_data *priv)
488 {
489 	int ldb_err;
490 	WERROR werr;
491 	DATA_BLOB blob;
492 	struct dsdb_schema_info *schema_info;
493 
494 	/* reset schmeInfo to know value */
495 	torture_assert(tctx,
496 		       _drsut_ldb_schema_info_reset(tctx, priv->ldb, SCHEMA_INFO_INIT_STR, false),
497 		       "_drsut_ldb_schema_info_reset() failed");
498 
499 	ldb_err = dsdb_module_schema_info_update(priv->ldb_module,
500 						 priv->schema,
501 						 DSDB_FLAG_TOP_MODULE | DSDB_FLAG_AS_SYSTEM, NULL);
502 	torture_assert_int_equal(tctx, ldb_err, LDB_SUCCESS, "dsdb_module_schema_info_update() failed");
503 
504 	/* get updated schemaInfo */
505 	ldb_err = dsdb_module_schema_info_blob_read(priv->ldb_module, DSDB_FLAG_TOP_MODULE,
506 						    priv, &blob, NULL);
507 	torture_assert_int_equal(tctx, ldb_err, LDB_SUCCESS, "dsdb_module_schema_info_blob_read() failed");
508 
509 	werr = dsdb_schema_info_from_blob(&blob, priv, &schema_info);
510 	torture_assert_werr_ok(tctx, werr, "dsdb_schema_info_from_blob() failed");
511 
512 	/* check against default schema_info */
513 	torture_assert_schema_info_equal(tctx, schema_info, priv->schema_info,
514 					  "schemaInfo attribute no updated correctly");
515 
516 	return true;
517 }
518 
519 
520 /**
521  * Reset schemaInfo record to know value
522  */
_drsut_ldb_schema_info_reset(struct torture_context * tctx,struct ldb_context * ldb,const char * schema_info_str,bool in_setup)523 static bool _drsut_ldb_schema_info_reset(struct torture_context *tctx,
524 					 struct ldb_context *ldb,
525 					 const char *schema_info_str,
526 					 bool in_setup)
527 {
528 	bool bret = true;
529 	int ldb_err;
530 	DATA_BLOB blob;
531 	struct ldb_message *msg;
532 	TALLOC_CTX *mem_ctx = talloc_new(tctx);
533 
534 	blob = strhex_to_data_blob(mem_ctx, schema_info_str);
535 	torture_assert_goto(tctx, blob.data, bret, DONE, "Not enough memory!");
536 
537 	msg = ldb_msg_new(mem_ctx);
538 	torture_assert_goto(tctx, msg, bret, DONE, "Not enough memory!");
539 
540 	msg->dn = ldb_get_schema_basedn(ldb);
541 	ldb_err = ldb_msg_add_value(msg, "schemaInfo", &blob, NULL);
542 	torture_assert_int_equal_goto(tctx, ldb_err, LDB_SUCCESS, bret, DONE,
543 				      "ldb_msg_add_value() failed");
544 
545 	if (in_setup) {
546 		ldb_err = ldb_add(ldb, msg);
547 	} else {
548 		ldb_err = dsdb_replace(ldb, msg, DSDB_MODIFY_PERMISSIVE);
549 	}
550 	torture_assert_int_equal_goto(tctx, ldb_err, LDB_SUCCESS, bret, DONE,
551 				      "dsdb_replace() failed");
552 
553 DONE:
554 	talloc_free(mem_ctx);
555 	return bret;
556 }
557 
558 /**
559  * Prepare temporary LDB and opens it
560  */
_drsut_ldb_setup(struct torture_context * tctx,struct drsut_schemainfo_data * priv)561 static bool _drsut_ldb_setup(struct torture_context *tctx, struct drsut_schemainfo_data *priv)
562 {
563 	int ldb_err;
564 	char *ldb_url;
565 	bool bret = true;
566 	char *tempdir = NULL;
567 	NTSTATUS status;
568 	TALLOC_CTX* mem_ctx;
569 
570 	mem_ctx = talloc_new(priv);
571 	torture_assert(tctx, mem_ctx, "Not enough memory!");
572 
573 	status = torture_temp_dir(tctx, "drs_", &tempdir);
574 	torture_assert_ntstatus_ok_goto(tctx, status, bret, DONE, "creating temp dir");
575 
576 	ldb_url = talloc_asprintf(priv, "%s/drs_schemainfo.ldb", tempdir);
577 	torture_assert_goto(tctx, ldb_url, bret, DONE, "Not enough memory!");
578 
579 	/* create LDB */
580 	priv->ldb = ldb_wrap_connect(priv, tctx->ev, tctx->lp_ctx,
581 	                             ldb_url, NULL, NULL, 0);
582 	torture_assert_goto(tctx, priv->ldb, bret, DONE,  "ldb_wrap_connect() failed");
583 
584 	/* set some schemaNamingContext */
585 	ldb_err = ldb_set_opaque(priv->ldb,
586 				 "schemaNamingContext",
587 				 ldb_dn_new(priv->ldb, priv->ldb, "CN=Schema,CN=Config"));
588 	torture_assert_int_equal_goto(tctx, ldb_err, LDB_SUCCESS, bret, DONE,
589 				      "ldb_set_opaque() failed");
590 
591 	/* add schemaInfo attribute so tested layer could work properly */
592 	torture_assert_goto(tctx,
593 			    _drsut_ldb_schema_info_reset(tctx, priv->ldb, SCHEMA_INFO_INIT_STR, true),
594 			    bret, DONE,
595 			    "_drsut_ldb_schema_info_reset() failed");
596 
597 DONE:
598 	talloc_free(tempdir);
599 	talloc_free(mem_ctx);
600 	return bret;
601 }
602 
603 /*
604  * Setup/Teardown for test case
605  */
torture_drs_unit_schemainfo_setup(struct torture_context * tctx,struct drsut_schemainfo_data ** _priv)606 static bool torture_drs_unit_schemainfo_setup(struct torture_context *tctx,
607 					      struct drsut_schemainfo_data **_priv)
608 {
609 	int i;
610 	int ldb_err;
611 	NTSTATUS status;
612 	DATA_BLOB ndr_blob;
613 	struct GUID guid;
614 	struct drsut_schemainfo_data *priv;
615 
616 	priv = talloc_zero(tctx, struct drsut_schemainfo_data);
617 	torture_assert(tctx, priv, "Not enough memory!");
618 
619 	/* returned allocated pointer here
620 	 * teardown() will be called even in case of failure,
621 	 * so we'll get a changes to clean up  */
622 	*_priv = priv;
623 
624 	/* create initial schemaInfo */
625 	torture_assert(tctx,
626 		       _drsut_schemainfo_new(tctx, SCHEMA_INFO_DEFAULT_STR, &priv->schema_info),
627 		       "Failed to create schema_info test object");
628 
629 	/* create data to test with */
630 	priv->test_data_count = ARRAY_SIZE(_schemainfo_test_data);
631 	priv->test_data = talloc_array(tctx, struct schemainfo_data, priv->test_data_count);
632 
633 	for (i = 0; i < ARRAY_SIZE(_schemainfo_test_data); i++) {
634 		struct schemainfo_data *data = &priv->test_data[i];
635 
636 		ndr_blob = strhex_to_data_blob(priv,
637 		                               _schemainfo_test_data[i].schema_info_str);
638 		torture_assert(tctx, ndr_blob.data, "Not enough memory!");
639 
640 		status = GUID_from_string(_schemainfo_test_data[i].guid_str, &guid);
641 		torture_assert_ntstatus_ok(tctx, status,
642 					   talloc_asprintf(tctx,
643 					                   "GUID_from_string() failed for %s",
644 					                   _schemainfo_test_data[i].guid_str));
645 
646 		data->ndr_blob           = ndr_blob;
647 		data->schi.invocation_id = guid;
648 		data->schi.revision      = _schemainfo_test_data[i].revision;
649 		data->werr_expected      = _schemainfo_test_data[i].werr_expected;
650 		data->test_both_ways     = _schemainfo_test_data[i].test_both_ways;
651 
652 	}
653 
654 	/* create temporary LDB and populate with data */
655 	if (!_drsut_ldb_setup(tctx, priv)) {
656 		return false;
657 	}
658 
659 	/* create ldb_module mockup object */
660 	priv->ldb_module = ldb_module_new(priv, priv->ldb, "schemaInfo_test_module", NULL);
661 	torture_assert(tctx, priv->ldb_module, "Not enough memory!");
662 
663 	/* create schema mockup object */
664 	priv->schema = dsdb_new_schema(priv);
665 
666 	/* set schema_info in dsdb_schema for testing */
667 	torture_assert(tctx,
668 		       _drsut_schemainfo_new(tctx, SCHEMA_INFO_DEFAULT_STR, &priv->schema->schema_info),
669 		       "Failed to create schema_info test object");
670 
671 	/* pre-cache invocationId for samdb_ntds_invocation_id()
672 	 * to work with our mock ldb */
673 	ldb_err = ldb_set_opaque(priv->ldb, "cache.invocation_id",
674 	                         &priv->schema_info->invocation_id);
675 	torture_assert_int_equal(tctx, ldb_err, LDB_SUCCESS, "ldb_set_opaque() failed");
676 
677 	/* Perform all tests in transactions so that
678 	 * underlying modify calls not to fail */
679 	ldb_err = ldb_transaction_start(priv->ldb);
680 	torture_assert_int_equal(tctx,
681 				 ldb_err,
682 				 LDB_SUCCESS,
683 				 "ldb_transaction_start() failed");
684 
685 	return true;
686 }
687 
torture_drs_unit_schemainfo_teardown(struct torture_context * tctx,struct drsut_schemainfo_data * priv)688 static bool torture_drs_unit_schemainfo_teardown(struct torture_context *tctx,
689 						 struct drsut_schemainfo_data *priv)
690 {
691 	int ldb_err;
692 
693 	/* commit pending transaction so we will
694 	 * be able to check what LDB state is */
695 	ldb_err = ldb_transaction_commit(priv->ldb);
696 	if (ldb_err != LDB_SUCCESS) {
697 		torture_comment(tctx, "ldb_transaction_commit() - %s (%s)",
698 		                ldb_strerror(ldb_err),
699 		                ldb_errstring(priv->ldb));
700 	}
701 
702 	talloc_free(priv);
703 
704 	return true;
705 }
706 
707 /**
708  * Test case initialization for
709  * drs.unit.schemaInfo
710  */
torture_drs_unit_schemainfo(struct torture_suite * suite)711 struct torture_tcase * torture_drs_unit_schemainfo(struct torture_suite *suite)
712 {
713 	typedef bool (*pfn_setup)(struct torture_context *, void **);
714 	typedef bool (*pfn_teardown)(struct torture_context *, void *);
715 	typedef bool (*pfn_run)(struct torture_context *, void *);
716 
717 	struct torture_tcase * tc = torture_suite_add_tcase(suite, "schemaInfo");
718 
719 	torture_tcase_set_fixture(tc,
720 				  (pfn_setup)torture_drs_unit_schemainfo_setup,
721 				  (pfn_teardown)torture_drs_unit_schemainfo_teardown);
722 
723 	tc->description = talloc_strdup(tc, "Unit tests for DRSUAPI::schemaInfo implementation");
724 
725 	torture_tcase_add_simple_test(tc, "dsdb_schema_info_new",
726 				      (pfn_run)test_dsdb_schema_info_new);
727 	torture_tcase_add_simple_test(tc, "dsdb_schema_info_from_blob",
728 				      (pfn_run)test_dsdb_schema_info_from_blob);
729 	torture_tcase_add_simple_test(tc, "dsdb_blob_from_schema_info",
730 				      (pfn_run)test_dsdb_blob_from_schema_info);
731 	torture_tcase_add_simple_test(tc, "dsdb_schema_info_cmp",
732 				      (pfn_run)test_dsdb_schema_info_cmp);
733 	torture_tcase_add_simple_test(tc, "dsdb_module_schema_info_blob read|write",
734 				      (pfn_run)test_dsdb_module_schema_info_blob_rw);
735 	torture_tcase_add_simple_test(tc, "dsdb_module_schema_info_update",
736 				      (pfn_run)test_dsdb_module_schema_info_update);
737 
738 
739 	return tc;
740 }
741