diff options
Diffstat (limited to 'source4/torture/drs/unit')
-rw-r--r-- | source4/torture/drs/unit/prefixmap_tests.c | 900 | ||||
-rw-r--r-- | source4/torture/drs/unit/schemainfo_tests.c | 740 |
2 files changed, 1640 insertions, 0 deletions
diff --git a/source4/torture/drs/unit/prefixmap_tests.c b/source4/torture/drs/unit/prefixmap_tests.c new file mode 100644 index 0000000..35764cd --- /dev/null +++ b/source4/torture/drs/unit/prefixmap_tests.c @@ -0,0 +1,900 @@ +/* + Unix SMB/CIFS implementation. + + DRSUAPI prefixMap unit tests + + Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2009-2010 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "system/filesys.h" +#include "torture/smbtorture.h" +#include "dsdb/samdb/samdb.h" +#include "torture/rpc/drsuapi.h" +#include "torture/drs/proto.h" +#include "param/param.h" +#include "librpc/ndr/libndr.h" + +/** + * Private data to be shared among all test in Test case + */ +struct drsut_prefixmap_data { + struct dsdb_schema_prefixmap *pfm_new; + struct dsdb_schema_prefixmap *pfm_full; + + /* default schemaInfo value to test with */ + struct dsdb_schema_info *schi_default; + + struct ldb_context *ldb_ctx; +}; + +/** + * Test-oid data structure + */ +struct drsut_pfm_oid_data { + uint32_t id; + const char *bin_oid; + const char *oid_prefix; +}; + +/** + * Default prefixMap initialization data. + * This prefixMap is what dsdb_schema_pfm_new() should return. + * Based on: MS-DRSR, 5.16.4 ATTRTYP-to-OID Conversion + * procedure NewPrefixTable( ) + */ +static const struct drsut_pfm_oid_data _prefixmap_test_new_data[] = { + {.id=0x00000000, .bin_oid="5504", .oid_prefix="2.5.4"}, + {.id=0x00000001, .bin_oid="5506", .oid_prefix="2.5.6"}, + {.id=0x00000002, .bin_oid="2A864886F7140102", .oid_prefix="1.2.840.113556.1.2"}, + {.id=0x00000003, .bin_oid="2A864886F7140103", .oid_prefix="1.2.840.113556.1.3"}, + {.id=0x00000004, .bin_oid="6086480165020201", .oid_prefix="2.16.840.1.101.2.2.1"}, + {.id=0x00000005, .bin_oid="6086480165020203", .oid_prefix="2.16.840.1.101.2.2.3"}, + {.id=0x00000006, .bin_oid="6086480165020105", .oid_prefix="2.16.840.1.101.2.1.5"}, + {.id=0x00000007, .bin_oid="6086480165020104", .oid_prefix="2.16.840.1.101.2.1.4"}, + {.id=0x00000008, .bin_oid="5505", .oid_prefix="2.5.5"}, + {.id=0x00000009, .bin_oid="2A864886F7140104", .oid_prefix="1.2.840.113556.1.4"}, + {.id=0x0000000A, .bin_oid="2A864886F7140105", .oid_prefix="1.2.840.113556.1.5"}, + {.id=0x00000013, .bin_oid="0992268993F22C64", .oid_prefix="0.9.2342.19200300.100"}, + {.id=0x00000014, .bin_oid="6086480186F84203", .oid_prefix="2.16.840.1.113730.3"}, + {.id=0x00000015, .bin_oid="0992268993F22C6401", .oid_prefix="0.9.2342.19200300.100.1"}, + {.id=0x00000016, .bin_oid="6086480186F8420301", .oid_prefix="2.16.840.1.113730.3.1"}, + {.id=0x00000017, .bin_oid="2A864886F7140105B658", .oid_prefix="1.2.840.113556.1.5.7000"}, + {.id=0x00000018, .bin_oid="5515", .oid_prefix="2.5.21"}, + {.id=0x00000019, .bin_oid="5512", .oid_prefix="2.5.18"}, + {.id=0x0000001A, .bin_oid="5514", .oid_prefix="2.5.20"}, +}; + +/** + * Data to be used for creating full prefix map for testing. + * 'full-prefixMap' is based on what w2k8 returns as a prefixMap + * on clean installation - i.e. prefixMap for clean Schema + */ +static const struct drsut_pfm_oid_data _prefixmap_full_map_data[] = { + {.id=0x00000000, .bin_oid="0x5504", .oid_prefix="2.5.4"}, + {.id=0x00000001, .bin_oid="0x5506", .oid_prefix="2.5.6"}, + {.id=0x00000002, .bin_oid="0x2A864886F7140102", .oid_prefix="1.2.840.113556.1.2"}, + {.id=0x00000003, .bin_oid="0x2A864886F7140103", .oid_prefix="1.2.840.113556.1.3"}, + {.id=0x00000004, .bin_oid="0x6086480165020201", .oid_prefix="2.16.840.1.101.2.2.1"}, + {.id=0x00000005, .bin_oid="0x6086480165020203", .oid_prefix="2.16.840.1.101.2.2.3"}, + {.id=0x00000006, .bin_oid="0x6086480165020105", .oid_prefix="2.16.840.1.101.2.1.5"}, + {.id=0x00000007, .bin_oid="0x6086480165020104", .oid_prefix="2.16.840.1.101.2.1.4"}, + {.id=0x00000008, .bin_oid="0x5505", .oid_prefix="2.5.5"}, + {.id=0x00000009, .bin_oid="0x2A864886F7140104", .oid_prefix="1.2.840.113556.1.4"}, + {.id=0x0000000a, .bin_oid="0x2A864886F7140105", .oid_prefix="1.2.840.113556.1.5"}, + {.id=0x00000013, .bin_oid="0x0992268993F22C64", .oid_prefix="0.9.2342.19200300.100"}, + {.id=0x00000014, .bin_oid="0x6086480186F84203", .oid_prefix="2.16.840.1.113730.3"}, + {.id=0x00000015, .bin_oid="0x0992268993F22C6401", .oid_prefix="0.9.2342.19200300.100.1"}, + {.id=0x00000016, .bin_oid="0x6086480186F8420301", .oid_prefix="2.16.840.1.113730.3.1"}, + {.id=0x00000017, .bin_oid="0x2A864886F7140105B658", .oid_prefix="1.2.840.113556.1.5.7000"}, + {.id=0x00000018, .bin_oid="0x5515", .oid_prefix="2.5.21"}, + {.id=0x00000019, .bin_oid="0x5512", .oid_prefix="2.5.18"}, + {.id=0x0000001a, .bin_oid="0x5514", .oid_prefix="2.5.20"}, + {.id=0x0000000b, .bin_oid="0x2A864886F71401048204", .oid_prefix="1.2.840.113556.1.4.260"}, + {.id=0x0000000c, .bin_oid="0x2A864886F714010538", .oid_prefix="1.2.840.113556.1.5.56"}, + {.id=0x0000000d, .bin_oid="0x2A864886F71401048206", .oid_prefix="1.2.840.113556.1.4.262"}, + {.id=0x0000000e, .bin_oid="0x2A864886F714010539", .oid_prefix="1.2.840.113556.1.5.57"}, + {.id=0x0000000f, .bin_oid="0x2A864886F71401048207", .oid_prefix="1.2.840.113556.1.4.263"}, + {.id=0x00000010, .bin_oid="0x2A864886F71401053A", .oid_prefix="1.2.840.113556.1.5.58"}, + {.id=0x00000011, .bin_oid="0x2A864886F714010549", .oid_prefix="1.2.840.113556.1.5.73"}, + {.id=0x00000012, .bin_oid="0x2A864886F71401048231", .oid_prefix="1.2.840.113556.1.4.305"}, + {.id=0x0000001b, .bin_oid="0x2B060104018B3A6577", .oid_prefix="1.3.6.1.4.1.1466.101.119"}, + {.id=0x0000001c, .bin_oid="0x6086480186F8420302", .oid_prefix="2.16.840.1.113730.3.2"}, + {.id=0x0000001d, .bin_oid="0x2B06010401817A01", .oid_prefix="1.3.6.1.4.1.250.1"}, + {.id=0x0000001e, .bin_oid="0x2A864886F70D0109", .oid_prefix="1.2.840.113549.1.9"}, + {.id=0x0000001f, .bin_oid="0x0992268993F22C6404", .oid_prefix="0.9.2342.19200300.100.4"}, + {.id=0x00000020, .bin_oid="0x2A864886F714010617", .oid_prefix="1.2.840.113556.1.6.23"}, + {.id=0x00000021, .bin_oid="0x2A864886F71401061201", .oid_prefix="1.2.840.113556.1.6.18.1"}, + {.id=0x00000022, .bin_oid="0x2A864886F71401061202", .oid_prefix="1.2.840.113556.1.6.18.2"}, + {.id=0x00000023, .bin_oid="0x2A864886F71401060D03", .oid_prefix="1.2.840.113556.1.6.13.3"}, + {.id=0x00000024, .bin_oid="0x2A864886F71401060D04", .oid_prefix="1.2.840.113556.1.6.13.4"}, + {.id=0x00000025, .bin_oid="0x2B0601010101", .oid_prefix="1.3.6.1.1.1.1"}, + {.id=0x00000026, .bin_oid="0x2B0601010102", .oid_prefix="1.3.6.1.1.1.2"}, + {.id=0x000003ed, .bin_oid="0x2A864886F7140104B65866", .oid_prefix="1.2.840.113556.1.4.7000.102"}, + {.id=0x00000428, .bin_oid="0x2A864886F7140105B6583E", .oid_prefix="1.2.840.113556.1.5.7000.62"}, + {.id=0x0000044c, .bin_oid="0x2A864886F7140104B6586683", .oid_prefix="1.2.840.113556.1.4.7000.102:0x83"}, + {.id=0x0000044f, .bin_oid="0x2A864886F7140104B6586681", .oid_prefix="1.2.840.113556.1.4.7000.102:0x81"}, + {.id=0x0000047d, .bin_oid="0x2A864886F7140105B6583E81", .oid_prefix="1.2.840.113556.1.5.7000.62:0x81"}, + {.id=0x00000561, .bin_oid="0x2A864886F7140105B6583E83", .oid_prefix="1.2.840.113556.1.5.7000.62:0x83"}, + {.id=0x000007d1, .bin_oid="0x2A864886F71401061401", .oid_prefix="1.2.840.113556.1.6.20.1"}, + {.id=0x000007e1, .bin_oid="0x2A864886F71401061402", .oid_prefix="1.2.840.113556.1.6.20.2"}, + {.id=0x00001b86, .bin_oid="0x2A817A", .oid_prefix="1.2.250"}, + {.id=0x00001c78, .bin_oid="0x2A817A81", .oid_prefix="1.2.250:0x81"}, + {.id=0x00001c7b, .bin_oid="0x2A817A8180", .oid_prefix="1.2.250:0x8180"}, +}; + + +/** + * OID-to-ATTID mappings to be used for testing. + * An entry is marked as 'exists=true' if it exists in + * base prefixMap (_prefixmap_test_new_data) + */ +static const struct { + const char *oid; + uint32_t id; + uint32_t attid; + bool exists; +} _prefixmap_test_data[] = { + {.oid="2.5.4.0", .id=0x00000000, .attid=0x000000, .exists=true}, + {.oid="2.5.4.42", .id=0x00000000, .attid=0x00002a, .exists=true}, + {.oid="1.2.840.113556.1.2.1", .id=0x00000002, .attid=0x020001, .exists=true}, + {.oid="1.2.840.113556.1.2.13", .id=0x00000002, .attid=0x02000d, .exists=true}, + {.oid="1.2.840.113556.1.2.281", .id=0x00000002, .attid=0x020119, .exists=true}, + {.oid="1.2.840.113556.1.4.125", .id=0x00000009, .attid=0x09007d, .exists=true}, + {.oid="1.2.840.113556.1.4.146", .id=0x00000009, .attid=0x090092, .exists=true}, + {.oid="1.2.250.1", .id=0x00001b86, .attid=0x1b860001, .exists=false}, + {.oid="1.2.250.16386", .id=0x00001c78, .attid=0x1c788002, .exists=false}, + {.oid="1.2.250.2097154", .id=0x00001c7b, .attid=0x1c7b8002, .exists=false}, +}; + + +/** + * Creates dsdb_schema_prefixmap based on predefined data + */ +static WERROR _drsut_prefixmap_new(const struct drsut_pfm_oid_data *_pfm_init_data, uint32_t count, + TALLOC_CTX *mem_ctx, struct dsdb_schema_prefixmap **_pfm) +{ + uint32_t i; + struct dsdb_schema_prefixmap *pfm; + + pfm = talloc(mem_ctx, struct dsdb_schema_prefixmap); + W_ERROR_HAVE_NO_MEMORY(pfm); + + pfm->length = count; + pfm->prefixes = talloc_array(pfm, struct dsdb_schema_prefixmap_oid, pfm->length); + if (!pfm->prefixes) { + talloc_free(pfm); + return WERR_NOT_ENOUGH_MEMORY; + } + + for (i = 0; i < pfm->length; i++) { + pfm->prefixes[i].id = _pfm_init_data[i].id; + pfm->prefixes[i].bin_oid = strhex_to_data_blob(pfm, _pfm_init_data[i].bin_oid); + if (!pfm->prefixes[i].bin_oid.data) { + talloc_free(pfm); + return WERR_NOT_ENOUGH_MEMORY; + } + } + + *_pfm = pfm; + + return WERR_OK; +} + +/** + * Compares two prefixMaps for being equal - same items on same indexes + */ +static bool _torture_drs_pfm_compare_same(struct torture_context *tctx, + const struct dsdb_schema_prefixmap *pfm_left, + const struct dsdb_schema_prefixmap *pfm_right, + bool quiet) +{ + uint32_t i; + char *err_msg = NULL; + + if (pfm_left->length != pfm_right->length) { + err_msg = talloc_asprintf(tctx, "prefixMaps differ in size; left = %d, right = %d", + pfm_left->length, pfm_right->length); + goto failed; + } + + for (i = 0; i < pfm_left->length; i++) { + struct dsdb_schema_prefixmap_oid *entry_left = &pfm_left->prefixes[i]; + struct dsdb_schema_prefixmap_oid *entry_right = &pfm_right->prefixes[i]; + + if (entry_left->id != entry_right->id) { + err_msg = talloc_asprintf(tctx, "Different IDs for index=%d", i); + goto failed; + } + if (data_blob_cmp(&entry_left->bin_oid, &entry_right->bin_oid)) { + err_msg = talloc_asprintf(tctx, "Different bin_oid for index=%d", i); + goto failed; + } + } + + return true; + +failed: + if (!quiet) { + torture_comment(tctx, "_torture_drs_pfm_compare_same: %s", err_msg); + } + talloc_free(err_msg); + + return false; +} + +/* + * Tests dsdb_schema_pfm_new() + */ +static bool torture_drs_unit_pfm_new(struct torture_context *tctx, struct drsut_prefixmap_data *priv) +{ + WERROR werr; + bool bret; + TALLOC_CTX *mem_ctx; + struct dsdb_schema_prefixmap *pfm = NULL; + + mem_ctx = talloc_new(priv); + + /* create new prefix map */ + werr = dsdb_schema_pfm_new(mem_ctx, &pfm); + torture_assert_werr_ok(tctx, werr, "dsdb_schema_pfm_new() failed!"); + torture_assert(tctx, pfm != NULL, "NULL prefixMap created!"); + torture_assert(tctx, pfm->length > 0, "Empty prefixMap created!"); + torture_assert(tctx, pfm->prefixes != NULL, "No prefixes for newly created prefixMap!"); + + /* compare newly created prefixMap with template one */ + bret = _torture_drs_pfm_compare_same(tctx, priv->pfm_new, pfm, false); + + talloc_free(mem_ctx); + + return bret; +} + +/** + * Tests dsdb_schema_pfm_make_attid() using full prefixMap. + * In this test we know exactly which ATTID and prefixMap->ID + * should be returned, i.e. no prefixMap entries should be added. + */ +static bool torture_drs_unit_pfm_make_attid_full_map(struct torture_context *tctx, struct drsut_prefixmap_data *priv) +{ + WERROR werr; + uint32_t i, count; + uint32_t attid; + char *err_msg; + + count = ARRAY_SIZE(_prefixmap_test_data); + for (i = 0; i < count; i++) { + werr = dsdb_schema_pfm_make_attid(priv->pfm_full, _prefixmap_test_data[i].oid, &attid); + /* prepare error message */ + err_msg = talloc_asprintf(priv, "dsdb_schema_pfm_make_attid() failed with %s", + _prefixmap_test_data[i].oid); + torture_assert(tctx, err_msg, "Unexpected: Have no memory!"); + /* verify result and returned ATTID */ + torture_assert_werr_ok(tctx, werr, err_msg); + torture_assert_int_equal(tctx, attid, _prefixmap_test_data[i].attid, err_msg); + /* reclaim memory for prepared error message */ + talloc_free(err_msg); + } + + return true; +} + +/** + * Tests dsdb_schema_pfm_make_attid() using initially small prefixMap. + * In this test we don't know exactly which ATTID and prefixMap->ID + * should be returned, but we can verify lo-word of ATTID. + * This test verifies implementation branch when a new + * prefix should be added into prefixMap. + */ +static bool torture_drs_unit_pfm_make_attid_small_map(struct torture_context *tctx, struct drsut_prefixmap_data *priv) +{ + WERROR werr; + uint32_t i, j; + uint32_t idx; + uint32_t attid, attid_2; + char *err_msg; + struct dsdb_schema_prefixmap *pfm = NULL; + TALLOC_CTX *mem_ctx; + + mem_ctx = talloc_new(priv); + + /* create new prefix map */ + werr = dsdb_schema_pfm_new(mem_ctx, &pfm); + torture_assert_werr_ok(tctx, werr, "dsdb_schema_pfm_new() failed!"); + + /* make some ATTIDs and check result */ + for (i = 0; i < ARRAY_SIZE(_prefixmap_test_data); i++) { + werr = dsdb_schema_pfm_make_attid(pfm, _prefixmap_test_data[i].oid, &attid); + + /* prepare error message */ + err_msg = talloc_asprintf(mem_ctx, "dsdb_schema_pfm_make_attid() failed with %s", + _prefixmap_test_data[i].oid); + torture_assert(tctx, err_msg, "Unexpected: Have no memory!"); + + /* verify result and returned ATTID */ + torture_assert_werr_ok(tctx, werr, err_msg); + /* verify ATTID lo-word */ + torture_assert_int_equal(tctx, attid & 0xFFFF, _prefixmap_test_data[i].attid & 0xFFFF, err_msg); + + /* try again, this time verify for whole ATTID */ + werr = dsdb_schema_pfm_make_attid(pfm, _prefixmap_test_data[i].oid, &attid_2); + torture_assert_werr_ok(tctx, werr, err_msg); + torture_assert_int_equal(tctx, attid_2, attid, err_msg); + + /* reclaim memory for prepared error message */ + talloc_free(err_msg); + + /* check there is such an index in modified prefixMap */ + idx = (attid >> 16); + for (j = 0; j < pfm->length; j++) { + if (pfm->prefixes[j].id == idx) + break; + } + if (j >= pfm->length) { + torture_result(tctx, TORTURE_FAIL, __location__": No prefix for ATTID=0x%08X", attid); + return false; + } + + } + + talloc_free(mem_ctx); + + return true; +} + +/** + * Tests dsdb_schema_pfm_attid_from_oid() using full prefixMap. + * In this test we know exactly which ATTID and prefixMap->ID + * should be returned- dsdb_schema_pfm_attid_from_oid() should succeed. + */ +static bool torture_drs_unit_pfm_attid_from_oid_full_map(struct torture_context *tctx, + struct drsut_prefixmap_data *priv) +{ + WERROR werr; + uint32_t i, count; + uint32_t attid; + char *err_msg; + + count = ARRAY_SIZE(_prefixmap_test_data); + for (i = 0; i < count; i++) { + werr = dsdb_schema_pfm_attid_from_oid(priv->pfm_full, + _prefixmap_test_data[i].oid, + &attid); + /* prepare error message */ + err_msg = talloc_asprintf(priv, "dsdb_schema_pfm_attid_from_oid() failed with %s", + _prefixmap_test_data[i].oid); + torture_assert(tctx, err_msg, "Unexpected: Have no memory!"); + /* verify result and returned ATTID */ + torture_assert_werr_ok(tctx, werr, err_msg); + torture_assert_int_equal(tctx, attid, _prefixmap_test_data[i].attid, err_msg); + /* reclaim memory for prepared error message */ + talloc_free(err_msg); + } + + return true; +} + +/** + * Tests dsdb_schema_pfm_attid_from_oid() using base (initial) prefixMap. + * dsdb_schema_pfm_attid_from_oid() should fail when testing with OID + * that are not already in the prefixMap. + */ +static bool torture_drs_unit_pfm_attid_from_oid_base_map(struct torture_context *tctx, + struct drsut_prefixmap_data *priv) +{ + WERROR werr; + uint32_t i; + uint32_t attid; + char *err_msg; + struct dsdb_schema_prefixmap *pfm = NULL; + struct dsdb_schema_prefixmap pfm_prev; + TALLOC_CTX *mem_ctx; + + mem_ctx = talloc_new(priv); + torture_assert(tctx, mem_ctx, "Unexpected: Have no memory!"); + + /* create new prefix map */ + werr = dsdb_schema_pfm_new(mem_ctx, &pfm); + torture_assert_werr_ok(tctx, werr, "dsdb_schema_pfm_new() failed!"); + + /* keep initial pfm around for testing */ + pfm_prev = *pfm; + pfm_prev.prefixes = talloc_reference(mem_ctx, pfm->prefixes); + + /* get some ATTIDs and check result */ + for (i = 0; i < ARRAY_SIZE(_prefixmap_test_data); i++) { + werr = dsdb_schema_pfm_attid_from_oid(pfm, _prefixmap_test_data[i].oid, &attid); + + /* prepare error message */ + err_msg = talloc_asprintf(mem_ctx, + "dsdb_schema_pfm_attid_from_oid() failed for %s", + _prefixmap_test_data[i].oid); + torture_assert(tctx, err_msg, "Unexpected: Have no memory!"); + + + /* verify pfm hasn't been altered */ + if (_prefixmap_test_data[i].exists) { + /* should succeed and return valid ATTID */ + torture_assert_werr_ok(tctx, werr, err_msg); + /* verify ATTID */ + torture_assert_int_equal(tctx, + attid, _prefixmap_test_data[i].attid, + err_msg); + } else { + /* should fail */ + torture_assert_werr_equal(tctx, werr, WERR_NOT_FOUND, err_msg); + } + + /* prefixMap should never be changed */ + if (!_torture_drs_pfm_compare_same(tctx, &pfm_prev, pfm, true)) { + torture_fail(tctx, "schema->prefixmap has changed"); + } + + /* reclaim memory for prepared error message */ + talloc_free(err_msg); + } + + talloc_free(mem_ctx); + + return true; +} + +/** + * Tests dsdb_schema_pfm_oid_from_attid() using full prefixMap. + */ +static bool torture_drs_unit_pfm_oid_from_attid(struct torture_context *tctx, struct drsut_prefixmap_data *priv) +{ + WERROR werr; + uint32_t i, count; + char *err_msg; + const char *oid; + + count = ARRAY_SIZE(_prefixmap_test_data); + for (i = 0; i < count; i++) { + oid = NULL; + werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, _prefixmap_test_data[i].attid, + priv, &oid); + /* prepare error message */ + err_msg = talloc_asprintf(priv, "dsdb_schema_pfm_oid_from_attid() failed with 0x%08X", + _prefixmap_test_data[i].attid); + torture_assert(tctx, err_msg, "Unexpected: Have no memory!"); + /* verify result and returned ATTID */ + torture_assert_werr_ok(tctx, werr, err_msg); + torture_assert(tctx, oid, "dsdb_schema_pfm_oid_from_attid() returned NULL OID!!!"); + torture_assert_str_equal(tctx, oid, _prefixmap_test_data[i].oid, err_msg); + /* reclaim memory for prepared error message */ + talloc_free(err_msg); + /* free memory for OID */ + talloc_free(discard_const(oid)); + } + + return true; +} + +/** + * Tests dsdb_schema_pfm_oid_from_attid() for handling + * correctly different type of attid values. + * See: MS-ADTS, 3.1.1.2.6 ATTRTYP + */ +static bool torture_drs_unit_pfm_oid_from_attid_check_attid(struct torture_context *tctx, + struct drsut_prefixmap_data *priv) +{ + WERROR werr; + const char *oid; + + /* Test with valid prefixMap attid */ + werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0x00010001, tctx, &oid); + torture_assert_werr_ok(tctx, werr, "Testing prefixMap type attid = 0x00010001"); + + /* Test with valid attid but invalid index */ + werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0x01110001, tctx, &oid); + torture_assert_werr_equal(tctx, werr, WERR_DS_NO_ATTRIBUTE_OR_VALUE, + "Testing invalid-index attid = 0x01110001"); + + /* Test with attid in msDS-IntId range */ + werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0x80000000, tctx, &oid); + torture_assert_werr_equal(tctx, werr, WERR_INVALID_PARAMETER, + "Testing msDS-IntId type attid = 0x80000000"); + werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0xBFFFFFFF, tctx, &oid); + torture_assert_werr_equal(tctx, werr, WERR_INVALID_PARAMETER, + "Testing msDS-IntId type attid = 0xBFFFFFFF"); + + /* Test with attid in RESERVED range */ + werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0xC0000000, tctx, &oid); + torture_assert_werr_equal(tctx, werr, WERR_INVALID_PARAMETER, + "Testing RESERVED type attid = 0xC0000000"); + werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0xFFFEFFFF, tctx, &oid); + torture_assert_werr_equal(tctx, werr, WERR_INVALID_PARAMETER, + "Testing RESERVED type attid = 0xFFFEFFFF"); + + /* Test with attid in INTERNAL range */ + werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0xFFFF0000, tctx, &oid); + torture_assert_werr_equal(tctx, werr, WERR_INVALID_PARAMETER, + "Testing INTERNAL type attid = 0xFFFF0000"); + werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0xFFFFFFFF, tctx, &oid); + torture_assert_werr_equal(tctx, werr, WERR_INVALID_PARAMETER, + "Testing INTERNAL type attid = 0xFFFFFFFF"); + + return true; +} + +/** + * Test Schema prefixMap conversions to/from drsuapi prefixMap + * representation. + */ +static bool torture_drs_unit_pfm_to_from_drsuapi(struct torture_context *tctx, struct drsut_prefixmap_data *priv) +{ + WERROR werr; + struct dsdb_schema_info *schema_info; + DATA_BLOB schema_info_blob; + struct dsdb_schema_prefixmap *pfm; + struct drsuapi_DsReplicaOIDMapping_Ctr *ctr; + TALLOC_CTX *mem_ctx; + + mem_ctx = talloc_new(tctx); + torture_assert(tctx, mem_ctx, "Unexpected: Have no memory!"); + + /* convert Schema_prefixMap to drsuapi_prefixMap */ + werr = dsdb_drsuapi_pfm_from_schema_pfm(priv->pfm_full, priv->schi_default, mem_ctx, &ctr); + torture_assert_werr_ok(tctx, werr, "dsdb_drsuapi_pfm_from_schema_pfm() failed"); + torture_assert(tctx, ctr && ctr->mappings, "drsuapi_prefixMap not constructed correctly"); + torture_assert_int_equal(tctx, ctr->num_mappings, priv->pfm_full->length + 1, + "drs_mappings count does not match"); + /* look for schema_info entry - it should be the last one */ + schema_info_blob = data_blob_const(ctr->mappings[ctr->num_mappings - 1].oid.binary_oid, + ctr->mappings[ctr->num_mappings - 1].oid.length); + werr = dsdb_schema_info_from_blob(&schema_info_blob, tctx, &schema_info); + torture_assert_werr_ok(tctx, werr, "dsdb_schema_info_from_blob failed"); + torture_assert_int_equal(tctx, schema_info->revision, priv->schi_default->revision, + "schema_info (revision) not stored correctly or not last entry"); + torture_assert(tctx, GUID_equal(&schema_info->invocation_id, &priv->schi_default->invocation_id), + "schema_info (invocation_id) not stored correctly or not last entry"); + + /* compare schema_prefixMap and drsuapi_prefixMap */ + werr = dsdb_schema_pfm_contains_drsuapi_pfm(priv->pfm_full, ctr); + torture_assert_werr_ok(tctx, werr, "dsdb_schema_pfm_contains_drsuapi_pfm() failed"); + + /* convert back drsuapi_prefixMap to schema_prefixMap */ + werr = dsdb_schema_pfm_from_drsuapi_pfm(ctr, true, mem_ctx, &pfm, &schema_info); + torture_assert_werr_ok(tctx, werr, "dsdb_schema_pfm_from_drsuapi_pfm() failed"); + torture_assert_int_equal(tctx, schema_info->revision, priv->schi_default->revision, + "Fetched schema_info is different (revision)"); + torture_assert(tctx, GUID_equal(&schema_info->invocation_id, &priv->schi_default->invocation_id), + "Fetched schema_info is different (invocation_id)"); + + /* compare against the original */ + if (!_torture_drs_pfm_compare_same(tctx, priv->pfm_full, pfm, true)) { + talloc_free(mem_ctx); + return false; + } + + /* test conversion with partial drsuapi_prefixMap */ + ctr->num_mappings--; + werr = dsdb_schema_pfm_from_drsuapi_pfm(ctr, false, mem_ctx, &pfm, NULL); + torture_assert_werr_ok(tctx, werr, "dsdb_schema_pfm_from_drsuapi_pfm() failed"); + /* compare against the original */ + if (!_torture_drs_pfm_compare_same(tctx, priv->pfm_full, pfm, false)) { + talloc_free(mem_ctx); + return false; + } + + talloc_free(mem_ctx); + return true; +} + + +/** + * Test Schema prefixMap conversions to/from ldb_val + * blob representation. + */ +static bool torture_drs_unit_pfm_to_from_ldb_val(struct torture_context *tctx, struct drsut_prefixmap_data *priv) +{ + WERROR werr; + struct dsdb_schema *schema; + struct ldb_val pfm_ldb_val; + struct ldb_val schema_info_ldb_val; + TALLOC_CTX *mem_ctx; + + mem_ctx = talloc_new(tctx); + torture_assert(tctx, mem_ctx, "Unexpected: Have no memory!"); + + schema = dsdb_new_schema(mem_ctx); + torture_assert(tctx, schema, "Unexpected: failed to allocate schema object"); + + /* set priv->pfm_full as prefixMap for new schema object */ + schema->prefixmap = priv->pfm_full; + schema->schema_info = priv->schi_default; + + /* convert schema_prefixMap to ldb_val blob */ + werr = dsdb_get_oid_mappings_ldb(schema, mem_ctx, &pfm_ldb_val, &schema_info_ldb_val); + torture_assert_werr_ok(tctx, werr, "dsdb_get_oid_mappings_ldb() failed"); + torture_assert(tctx, pfm_ldb_val.data && pfm_ldb_val.length, + "pfm_ldb_val not constructed correctly"); + torture_assert(tctx, schema_info_ldb_val.data && schema_info_ldb_val.length, + "schema_info_ldb_val not constructed correctly"); + + /* convert pfm_ldb_val back to schema_prefixMap */ + schema->prefixmap = NULL; + schema->schema_info = NULL; + werr = dsdb_load_oid_mappings_ldb(schema, &pfm_ldb_val, &schema_info_ldb_val); + torture_assert_werr_ok(tctx, werr, "dsdb_load_oid_mappings_ldb() failed"); + /* compare against the original */ + if (!_torture_drs_pfm_compare_same(tctx, schema->prefixmap, priv->pfm_full, false)) { + talloc_free(mem_ctx); + return false; + } + torture_assert_int_equal(tctx, schema->schema_info->revision, priv->schi_default->revision, + "Fetched schema_info is different (revision)"); + torture_assert(tctx, GUID_equal(&schema->schema_info->invocation_id, &priv->schi_default->invocation_id), + "Fetched schema_info is different (invocation_id)"); + + talloc_free(mem_ctx); + return true; +} + +/** + * Test read/write in ldb implementation + */ +static bool torture_drs_unit_pfm_read_write_ldb(struct torture_context *tctx, struct drsut_prefixmap_data *priv) +{ + WERROR werr; + struct dsdb_schema *schema; + struct dsdb_schema_prefixmap *pfm; + TALLOC_CTX *mem_ctx; + + mem_ctx = talloc_new(tctx); + torture_assert(tctx, mem_ctx, "Unexpected: Have no memory!"); + + /* makeup a dsdb_schema to test with */ + schema = dsdb_new_schema(mem_ctx); + torture_assert(tctx, schema, "Unexpected: failed to allocate schema object"); + /* set priv->pfm_full as prefixMap for new schema object */ + schema->prefixmap = priv->pfm_full; + schema->schema_info = priv->schi_default; + + /* write prfixMap to ldb */ + werr = dsdb_write_prefixes_from_schema_to_ldb(mem_ctx, priv->ldb_ctx, schema); + torture_assert_werr_ok(tctx, werr, "dsdb_write_prefixes_from_schema_to_ldb() failed"); + + /* read from ldb what we have written */ + werr = dsdb_read_prefixes_from_ldb(priv->ldb_ctx, mem_ctx, &pfm); + torture_assert_werr_ok(tctx, werr, "dsdb_read_prefixes_from_ldb() failed"); + + /* compare data written/read */ + if (!_torture_drs_pfm_compare_same(tctx, schema->prefixmap, priv->pfm_full, false)) { + torture_fail(tctx, "prefixMap read/write in LDB is not consistent"); + } + + talloc_free(mem_ctx); + + return true; +} + +/** + * Test dsdb_create_prefix_mapping + */ +static bool torture_drs_unit_dsdb_create_prefix_mapping(struct torture_context *tctx, struct drsut_prefixmap_data *priv) +{ + WERROR werr; + uint32_t i; + struct dsdb_schema *schema; + TALLOC_CTX *mem_ctx; + struct dsdb_schema_prefixmap *pfm_ldb = NULL; + + mem_ctx = talloc_new(tctx); + torture_assert(tctx, mem_ctx, "Unexpected: Have no memory!"); + + /* makeup a dsdb_schema to test with */ + schema = dsdb_new_schema(mem_ctx); + torture_assert(tctx, schema, "Unexpected: failed to allocate schema object"); + /* set priv->pfm_full as prefixMap for new schema object */ + schema->schema_info = priv->schi_default; + werr = _drsut_prefixmap_new(_prefixmap_test_new_data, ARRAY_SIZE(_prefixmap_test_new_data), + schema, &schema->prefixmap); + torture_assert_werr_ok(tctx, werr, "_drsut_prefixmap_new() failed"); + /* write prfixMap to ldb */ + werr = dsdb_write_prefixes_from_schema_to_ldb(mem_ctx, priv->ldb_ctx, schema); + torture_assert_werr_ok(tctx, werr, "dsdb_write_prefixes_from_schema_to_ldb() failed"); + + /* read from ldb what we have written */ + werr = dsdb_read_prefixes_from_ldb(priv->ldb_ctx, mem_ctx, &pfm_ldb); + torture_assert_werr_ok(tctx, werr, "dsdb_read_prefixes_from_ldb() failed"); + /* compare data written/read */ + if (!_torture_drs_pfm_compare_same(tctx, schema->prefixmap, pfm_ldb, true)) { + torture_fail(tctx, "pfm in LDB is different"); + } + TALLOC_FREE(pfm_ldb); + + for (i = 0; i < ARRAY_SIZE(_prefixmap_test_data); i++) { + struct dsdb_schema_prefixmap *pfm_prev; + struct dsdb_schema_prefixmap *pfm_new; + + pfm_prev = schema->prefixmap; + + pfm_new = dsdb_schema_pfm_copy_shallow(schema, pfm_prev); + torture_assert(tctx, pfm_new != NULL, "dsdb_schema_pfm_copy_shallow() failed"); + + if (!_prefixmap_test_data[i].exists) { + uint32_t attid; + + werr = dsdb_schema_pfm_make_attid(pfm_new, + _prefixmap_test_data[i].oid, + &attid); + torture_assert_werr_ok(tctx, werr, "dsdb_schema_pfm_make_attid() failed"); + } + + /* call dsdb_create_prefix_mapping() and check result accordingly */ + werr = dsdb_create_prefix_mapping(priv->ldb_ctx, schema, _prefixmap_test_data[i].oid); + torture_assert_werr_ok(tctx, werr, "dsdb_create_prefix_mapping() failed"); + + /* + * The prefix should not change, only on reload + */ + torture_assert(tctx, pfm_prev == schema->prefixmap, + "schema->prefixmap has been reallocated!"); + if (!_torture_drs_pfm_compare_same(tctx, pfm_prev, schema->prefixmap, true)) { + torture_fail(tctx, "schema->prefixmap has changed"); + } + + /* read from ldb what we have written */ + werr = dsdb_read_prefixes_from_ldb(priv->ldb_ctx, mem_ctx, &pfm_ldb); + torture_assert_werr_ok(tctx, werr, "dsdb_read_prefixes_from_ldb() failed"); + /* compare data written/read */ + if (!_torture_drs_pfm_compare_same(tctx, pfm_new, pfm_ldb, true)) { + torture_fail(tctx, talloc_asprintf(tctx, "%u: pfm in LDB is different", i)); + } + /* free mem for pfm read from LDB */ + TALLOC_FREE(pfm_ldb); + + /* prepare for the next round */ + schema->prefixmap = pfm_new; + } + + talloc_free(mem_ctx); + + return true; +} + +/** + * Prepare temporary LDB and opens it + */ +static bool torture_drs_unit_ldb_setup(struct torture_context *tctx, struct drsut_prefixmap_data *priv) +{ + int ldb_err; + char *ldb_url; + bool bret = true; + TALLOC_CTX* mem_ctx; + char *tempdir; + NTSTATUS status; + + mem_ctx = talloc_new(priv); + + status = torture_temp_dir(tctx, "drs_", &tempdir); + torture_assert_ntstatus_ok(tctx, status, "creating temp dir"); + + ldb_url = talloc_asprintf(priv, "%s/drs_test.ldb", tempdir); + + /* create LDB */ + priv->ldb_ctx = ldb_init(priv, tctx->ev); + ldb_err = ldb_connect(priv->ldb_ctx, ldb_url, 0, NULL); + torture_assert_int_equal_goto(tctx, ldb_err, LDB_SUCCESS, bret, DONE, "ldb_connect() failed"); + + /* set some schemaNamingContext */ + ldb_err = ldb_set_opaque(priv->ldb_ctx, + "schemaNamingContext", + ldb_dn_new(priv->ldb_ctx, priv->ldb_ctx, "CN=Schema,CN=Config")); + torture_assert_int_equal_goto(tctx, ldb_err, LDB_SUCCESS, bret, DONE, "ldb_set_opaque() failed"); + + /* add prefixMap attribute so tested layer could work properly */ + { + struct ldb_message *msg = ldb_msg_new(mem_ctx); + msg->dn = ldb_get_schema_basedn(priv->ldb_ctx); + ldb_err = ldb_msg_add_string(msg, "prefixMap", "prefixMap"); + torture_assert_int_equal_goto(tctx, ldb_err, LDB_SUCCESS, bret, DONE, + "ldb_msg_add_string() failed"); + + ldb_err = ldb_add(priv->ldb_ctx, msg); + torture_assert_int_equal_goto(tctx, ldb_err, LDB_SUCCESS, bret, DONE, "ldb_add() failed"); + } + +DONE: + talloc_free(mem_ctx); + return bret; +} + +/* + * Setup/Teardown for test case + */ +static bool torture_drs_unit_prefixmap_setup(struct torture_context *tctx, struct drsut_prefixmap_data **_priv) +{ + WERROR werr; + DATA_BLOB blob; + struct drsut_prefixmap_data *priv; + + priv = *_priv = talloc_zero(tctx, struct drsut_prefixmap_data); + torture_assert(tctx, priv != NULL, "Not enough memory"); + + werr = _drsut_prefixmap_new(_prefixmap_test_new_data, ARRAY_SIZE(_prefixmap_test_new_data), + tctx, &priv->pfm_new); + torture_assert_werr_ok(tctx, werr, "failed to create pfm_new"); + + werr = _drsut_prefixmap_new(_prefixmap_full_map_data, ARRAY_SIZE(_prefixmap_full_map_data), + tctx, &priv->pfm_full); + torture_assert_werr_ok(tctx, werr, "failed to create pfm_test"); + + torture_assert(tctx, drsut_schemainfo_new(tctx, &priv->schi_default), + "drsut_schemainfo_new() failed"); + + werr = dsdb_blob_from_schema_info(priv->schi_default, priv, &blob); + torture_assert_werr_ok(tctx, werr, "dsdb_blob_from_schema_info() failed"); + + /* create temporary LDB and populate with data */ + if (!torture_drs_unit_ldb_setup(tctx, priv)) { + return false; + } + + return true; +} + +static bool torture_drs_unit_prefixmap_teardown(struct torture_context *tctx, struct drsut_prefixmap_data *priv) +{ + talloc_free(priv); + + return true; +} + +/** + * Test case initialization for + * drs.unit.prefixMap + */ +struct torture_tcase * torture_drs_unit_prefixmap(struct torture_suite *suite) +{ + typedef bool (*pfn_setup)(struct torture_context *, void **); + typedef bool (*pfn_teardown)(struct torture_context *, void *); + typedef bool (*pfn_run)(struct torture_context *, void *); + + struct torture_tcase * tc = torture_suite_add_tcase(suite, "prefixMap"); + + torture_tcase_set_fixture(tc, + (pfn_setup)torture_drs_unit_prefixmap_setup, + (pfn_teardown)torture_drs_unit_prefixmap_teardown); + + tc->description = talloc_strdup(tc, "Unit tests for DRSUAPI::prefixMap implementation"); + + torture_tcase_add_simple_test(tc, "new", (pfn_run)torture_drs_unit_pfm_new); + + torture_tcase_add_simple_test(tc, "make_attid_full_map", (pfn_run)torture_drs_unit_pfm_make_attid_full_map); + torture_tcase_add_simple_test(tc, "make_attid_small_map", (pfn_run)torture_drs_unit_pfm_make_attid_small_map); + + torture_tcase_add_simple_test(tc, "attid_from_oid_full_map", + (pfn_run)torture_drs_unit_pfm_attid_from_oid_full_map); + torture_tcase_add_simple_test(tc, "attid_from_oid_empty_map", + (pfn_run)torture_drs_unit_pfm_attid_from_oid_base_map); + + torture_tcase_add_simple_test(tc, "oid_from_attid_full_map", (pfn_run)torture_drs_unit_pfm_oid_from_attid); + torture_tcase_add_simple_test(tc, "oid_from_attid_check_attid", + (pfn_run)torture_drs_unit_pfm_oid_from_attid_check_attid); + + torture_tcase_add_simple_test(tc, "pfm_to_from_drsuapi", (pfn_run)torture_drs_unit_pfm_to_from_drsuapi); + + torture_tcase_add_simple_test(tc, "pfm_to_from_ldb_val", (pfn_run)torture_drs_unit_pfm_to_from_ldb_val); + + torture_tcase_add_simple_test(tc, "pfm_read_write_ldb", (pfn_run)torture_drs_unit_pfm_read_write_ldb); + + torture_tcase_add_simple_test(tc, "dsdb_create_prefix_mapping", (pfn_run)torture_drs_unit_dsdb_create_prefix_mapping); + + return tc; +} diff --git a/source4/torture/drs/unit/schemainfo_tests.c b/source4/torture/drs/unit/schemainfo_tests.c new file mode 100644 index 0000000..4b4cca6 --- /dev/null +++ b/source4/torture/drs/unit/schemainfo_tests.c @@ -0,0 +1,740 @@ +/* + Unix SMB/CIFS implementation. + + DRSUAPI schemaInfo unit tests + + Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2010 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "system/filesys.h" +#include "torture/smbtorture.h" +#include "dsdb/samdb/samdb.h" +#include "dsdb/samdb/ldb_modules/util.h" +#include "ldb_wrap.h" +#include <ldb_module.h> +#include "torture/rpc/drsuapi.h" +#include "librpc/ndr/libndr.h" +#include "param/param.h" +#include "torture/drs/proto.h" +#include "torture/drs/proto.h" + + +/** + * schemaInfo to init ldb context with + * Rev: 0 + * GUID: 00000000-0000-0000-0000-000000000000 + */ +#define SCHEMA_INFO_INIT_STR "FF0000000000000000000000000000000000000000" + +/** + * Default schema_info string to be used for testing + * Rev: 01 + * GUID: 071c82fd-45c7-4351-a3db-51f75a630a7f + */ +#define SCHEMA_INFO_DEFAULT_STR "FF00000001FD821C07C7455143A3DB51F75A630A7F" + +/** + * Schema info data to test with + */ +struct schemainfo_data { + DATA_BLOB ndr_blob; + struct dsdb_schema_info schi; + WERROR werr_expected; + bool test_both_ways; +}; + +/** + * Schema info test data in human-readable format (... kind of) + */ +static const struct { + const char *schema_info_str; + uint32_t revision; + const char *guid_str; + WERROR werr_expected; + bool test_both_ways; +} _schemainfo_test_data[] = { + { + .schema_info_str = "FF0000000000000000000000000000000000000000", + .revision = 0, + .guid_str = "00000000-0000-0000-0000-000000000000", + .werr_expected = WERR_OK, + .test_both_ways = true + }, + { + .schema_info_str = "FF00000001FD821C07C7455143A3DB51F75A630A7F", + .revision = 1, + .guid_str = "071c82fd-45c7-4351-a3db-51f75a630a7f", + .werr_expected = WERR_OK, + .test_both_ways = true + }, + { + .schema_info_str = "FFFFFFFFFFFD821C07C7455143A3DB51F75A630A7F", + .revision = 0xFFFFFFFF, + .guid_str = "071c82fd-45c7-4351-a3db-51f75a630a7f", + .werr_expected = WERR_OK, + .test_both_ways = true + }, + { /* len == 21 */ + .schema_info_str = "FF00000001FD821C07C7455143A3DB51F75A630A7F00", + .revision = 1, + .guid_str = "071c82fd-45c7-4351-a3db-51f75a630a7f", + .werr_expected = WERR_INVALID_PARAMETER, + .test_both_ways = false + }, + { /* marker == FF */ + .schema_info_str = "AA00000001FD821C07C7455143A3DB51F75A630A7F", + .revision = 1, + .guid_str = "071c82fd-45c7-4351-a3db-51f75a630a7f", + .werr_expected = WERR_INVALID_PARAMETER, + .test_both_ways = false + } +}; + +/** + * Private data to be shared among all test in Test case + */ +struct drsut_schemainfo_data { + struct ldb_context *ldb; + struct ldb_module *ldb_module; + struct dsdb_schema *schema; + + /* Initial schemaInfo set in ldb to test with */ + struct dsdb_schema_info *schema_info; + + uint32_t test_data_count; + struct schemainfo_data *test_data; +}; + +/** + * torture macro to assert for equal dsdb_schema_info's + */ +#define torture_assert_schema_info_equal(torture_ctx,got,expected,cmt)\ + do { const struct dsdb_schema_info *__got = (got), *__expected = (expected); \ + if (__got->revision != __expected->revision) { \ + torture_result(torture_ctx, TORTURE_FAIL, \ + __location__": "#got".revision %d did not match "#expected".revision %d: %s", \ + (int)__got->revision, (int)__expected->revision, cmt); \ + return false; \ + } \ + if (!GUID_equal(&__got->invocation_id, &__expected->invocation_id)) { \ + torture_result(torture_ctx, TORTURE_FAIL, \ + __location__": "#got".invocation_id did not match "#expected".invocation_id: %s", cmt); \ + return false; \ + } \ + } while(0) + +/* + * forward declaration for internal functions + */ +static bool _drsut_ldb_schema_info_reset(struct torture_context *tctx, + struct ldb_context *ldb, + const char *schema_info_str, + bool in_setup); + + +/** + * Creates dsdb_schema_info object based on NDR data + * passed as hex string + */ +static bool _drsut_schemainfo_new(struct torture_context *tctx, + const char *schema_info_str, struct dsdb_schema_info **_si) +{ + WERROR werr; + DATA_BLOB blob; + + blob = strhex_to_data_blob(tctx, schema_info_str); + if (!blob.data) { + torture_comment(tctx, "Not enough memory!\n"); + return false; + } + + werr = dsdb_schema_info_from_blob(&blob, tctx, _si); + if (!W_ERROR_IS_OK(werr)) { + torture_comment(tctx, + "Failed to create dsdb_schema_info object for %s: %s", + schema_info_str, + win_errstr(werr)); + return false; + } + + data_blob_free(&blob); + + return true; +} + +/** + * Creates dsdb_schema_info object based on predefined data + * Function is public as it is intended to be used by other + * tests (e.g. prefixMap tests) + */ +bool drsut_schemainfo_new(struct torture_context *tctx, struct dsdb_schema_info **_si) +{ + return _drsut_schemainfo_new(tctx, SCHEMA_INFO_DEFAULT_STR, _si); +} + + +/* + * Tests dsdb_schema_info_new() and dsdb_schema_info_blob_new() + */ +static bool test_dsdb_schema_info_new(struct torture_context *tctx, + struct drsut_schemainfo_data *priv) +{ + WERROR werr; + DATA_BLOB ndr_blob; + DATA_BLOB ndr_blob_expected; + struct dsdb_schema_info *schi; + TALLOC_CTX *mem_ctx; + + mem_ctx = talloc_new(priv); + torture_assert(tctx, mem_ctx, "Not enough memory!"); + ndr_blob_expected = strhex_to_data_blob(mem_ctx, SCHEMA_INFO_INIT_STR); + torture_assert(tctx, ndr_blob_expected.data, "Not enough memory!"); + + werr = dsdb_schema_info_new(mem_ctx, &schi); + torture_assert_werr_ok(tctx, werr, "dsdb_schema_info_new() failed"); + torture_assert_int_equal(tctx, schi->revision, 0, + "dsdb_schema_info_new() creates schemaInfo with invalid revision"); + torture_assert(tctx, GUID_all_zero(&schi->invocation_id), + "dsdb_schema_info_new() creates schemaInfo with not ZERO GUID"); + + werr = dsdb_schema_info_blob_new(mem_ctx, &ndr_blob); + torture_assert_werr_ok(tctx, werr, "dsdb_schema_info_blob_new() failed"); + torture_assert_data_blob_equal(tctx, ndr_blob, ndr_blob_expected, + "dsdb_schema_info_blob_new() returned invalid blob"); + + talloc_free(mem_ctx); + return true; +} + +/* + * Tests dsdb_schema_info_from_blob() + */ +static bool test_dsdb_schema_info_from_blob(struct torture_context *tctx, + struct drsut_schemainfo_data *priv) +{ + uint32_t i; + WERROR werr; + char *msg; + struct dsdb_schema_info *schema_info; + TALLOC_CTX *mem_ctx; + + mem_ctx = talloc_new(priv); + torture_assert(tctx, mem_ctx, "Not enough memory!"); + + for (i = 0; i < priv->test_data_count; i++) { + struct schemainfo_data *data = &priv->test_data[i]; + + msg = talloc_asprintf(tctx, "dsdb_schema_info_from_blob() [%d]-[%s]", + i, _schemainfo_test_data[i].schema_info_str); + + werr = dsdb_schema_info_from_blob(&data->ndr_blob, mem_ctx, &schema_info); + torture_assert_werr_equal(tctx, werr, data->werr_expected, msg); + + /* test returned data */ + if (W_ERROR_IS_OK(werr)) { + torture_assert_schema_info_equal(tctx, + schema_info, &data->schi, + "after dsdb_schema_info_from_blob() call"); + } + } + + talloc_free(mem_ctx); + + return true; +} + +/* + * Tests dsdb_blob_from_schema_info() + */ +static bool test_dsdb_blob_from_schema_info(struct torture_context *tctx, + struct drsut_schemainfo_data *priv) +{ + uint32_t i; + WERROR werr; + char *msg; + DATA_BLOB ndr_blob; + TALLOC_CTX *mem_ctx; + + mem_ctx = talloc_new(priv); + torture_assert(tctx, mem_ctx, "Not enough memory!"); + + for (i = 0; i < priv->test_data_count; i++) { + struct schemainfo_data *data = &priv->test_data[i]; + + /* not all test are valid reverse type of conversion */ + if (!data->test_both_ways) { + continue; + } + + msg = talloc_asprintf(tctx, "dsdb_blob_from_schema_info() [%d]-[%s]", + i, _schemainfo_test_data[i].schema_info_str); + + werr = dsdb_blob_from_schema_info(&data->schi, mem_ctx, &ndr_blob); + torture_assert_werr_equal(tctx, werr, data->werr_expected, msg); + + /* test returned data */ + if (W_ERROR_IS_OK(werr)) { + torture_assert_data_blob_equal(tctx, + ndr_blob, data->ndr_blob, + "dsdb_blob_from_schema_info()"); + } + } + + talloc_free(mem_ctx); + + return true; +} + +static bool test_dsdb_schema_info_cmp(struct torture_context *tctx, + struct drsut_schemainfo_data *priv) +{ + DATA_BLOB blob; + struct drsuapi_DsReplicaOIDMapping_Ctr *ctr; + struct dsdb_schema_info schema_info; + + ctr = talloc_zero(priv, struct drsuapi_DsReplicaOIDMapping_Ctr); + torture_assert(tctx, ctr, "Not enough memory!"); + + /* not enough elements */ + torture_assert_werr_equal(tctx, + dsdb_schema_info_cmp(priv->schema, ctr), + WERR_INVALID_PARAMETER, + "dsdb_schema_info_cmp(): unexpected result"); + + /* an empty element for schemaInfo */ + ctr->num_mappings = 1; + ctr->mappings = talloc_zero_array(ctr, struct drsuapi_DsReplicaOIDMapping, 1); + torture_assert(tctx, ctr->mappings, "Not enough memory!"); + torture_assert_werr_equal(tctx, + dsdb_schema_info_cmp(priv->schema, ctr), + WERR_INVALID_PARAMETER, + "dsdb_schema_info_cmp(): unexpected result"); + + /* test with invalid schemaInfo - length != 21 */ + blob = strhex_to_data_blob(ctr, "FF00000001FD821C07C7455143A3DB51F75A630A7F00"); + torture_assert(tctx, blob.data, "Not enough memory!"); + ctr->mappings[0].oid.length = blob.length; + ctr->mappings[0].oid.binary_oid = blob.data; + torture_assert_werr_equal(tctx, + dsdb_schema_info_cmp(priv->schema, ctr), + WERR_INVALID_PARAMETER, + "dsdb_schema_info_cmp(): unexpected result"); + + /* test with invalid schemaInfo - marker != 0xFF */ + blob = strhex_to_data_blob(ctr, "AA00000001FD821C07C7455143A3DB51F75A630A7F"); + torture_assert(tctx, blob.data, "Not enough memory!"); + ctr->mappings[0].oid.length = blob.length; + ctr->mappings[0].oid.binary_oid = blob.data; + torture_assert_werr_equal(tctx, + dsdb_schema_info_cmp(priv->schema, ctr), + WERR_INVALID_PARAMETER, + "dsdb_schema_info_cmp(): unexpected result"); + + /* test with valid schemaInfo, but older one should be ok */ + blob = strhex_to_data_blob(ctr, "FF0000000000000000000000000000000000000000"); + torture_assert(tctx, blob.data, "Not enough memory!"); + ctr->mappings[0].oid.length = blob.length; + ctr->mappings[0].oid.binary_oid = blob.data; + torture_assert_werr_equal(tctx, + dsdb_schema_info_cmp(priv->schema, ctr), + WERR_OK, + "dsdb_schema_info_cmp(): unexpected result"); + + /* test with correct schemaInfo, but invalid ATTID */ + schema_info = *priv->schema->schema_info; + torture_assert_werr_ok(tctx, + dsdb_blob_from_schema_info(&schema_info, tctx, &blob), + "dsdb_blob_from_schema_info() failed"); + ctr->mappings[0].id_prefix = 1; + ctr->mappings[0].oid.length = blob.length; + ctr->mappings[0].oid.binary_oid = blob.data; + torture_assert_werr_equal(tctx, + dsdb_schema_info_cmp(priv->schema, ctr), + WERR_INVALID_PARAMETER, + "dsdb_schema_info_cmp(): unexpected result"); + + /* test with valid schemaInfo */ + ctr->mappings[0].id_prefix = 0; + torture_assert_werr_ok(tctx, + dsdb_schema_info_cmp(priv->schema, ctr), + "dsdb_schema_info_cmp(): unexpected result"); + + /* test with valid schemaInfo, but older revision */ + schema_info = *priv->schema->schema_info; + schema_info.revision -= 1; + torture_assert_werr_ok(tctx, + dsdb_blob_from_schema_info(&schema_info, tctx, &blob), + "dsdb_blob_from_schema_info() failed"); + ctr->mappings[0].oid.length = blob.length; + ctr->mappings[0].oid.binary_oid = blob.data; + torture_assert_werr_equal(tctx, + dsdb_schema_info_cmp(priv->schema, ctr), + WERR_OK, + "dsdb_schema_info_cmp(): unexpected result"); + + /* test with valid schemaInfo, but newer revision */ + schema_info = *priv->schema->schema_info; + schema_info.revision += 1; + torture_assert_werr_ok(tctx, + dsdb_blob_from_schema_info(&schema_info, tctx, &blob), + "dsdb_blob_from_schema_info() failed"); + ctr->mappings[0].oid.length = blob.length; + ctr->mappings[0].oid.binary_oid = blob.data; + torture_assert_werr_equal(tctx, + dsdb_schema_info_cmp(priv->schema, ctr), + WERR_DS_DRA_SCHEMA_MISMATCH, + "dsdb_schema_info_cmp(): unexpected result"); + + /* test with valid schemaInfo, but newer revision and other invocationId */ + schema_info = *priv->schema->schema_info; + schema_info.revision += 1; + schema_info.invocation_id.time_mid += 1; + torture_assert_werr_ok(tctx, + dsdb_blob_from_schema_info(&schema_info, tctx, &blob), + "dsdb_blob_from_schema_info() failed"); + ctr->mappings[0].oid.length = blob.length; + ctr->mappings[0].oid.binary_oid = blob.data; + torture_assert_werr_equal(tctx, + dsdb_schema_info_cmp(priv->schema, ctr), + WERR_DS_DRA_SCHEMA_MISMATCH, + "dsdb_schema_info_cmp(): unexpected result"); + + /* test with valid schemaInfo, but older revision and other invocationId */ + schema_info = *priv->schema->schema_info; + schema_info.revision -= 1; + schema_info.invocation_id.time_mid += 1; + torture_assert_werr_ok(tctx, + dsdb_blob_from_schema_info(&schema_info, tctx, &blob), + "dsdb_blob_from_schema_info() failed"); + ctr->mappings[0].oid.length = blob.length; + ctr->mappings[0].oid.binary_oid = blob.data; + torture_assert_werr_equal(tctx, + dsdb_schema_info_cmp(priv->schema, ctr), + WERR_OK, + "dsdb_schema_info_cmp(): unexpected result"); + + /* test with valid schemaInfo, but same revision and other invocationId */ + schema_info = *priv->schema->schema_info; + schema_info.invocation_id.time_mid += 1; + torture_assert_werr_ok(tctx, + dsdb_blob_from_schema_info(&schema_info, tctx, &blob), + "dsdb_blob_from_schema_info() failed"); + ctr->mappings[0].oid.length = blob.length; + ctr->mappings[0].oid.binary_oid = blob.data; + torture_assert_werr_equal(tctx, + dsdb_schema_info_cmp(priv->schema, ctr), + WERR_DS_DRA_SCHEMA_CONFLICT, + "dsdb_schema_info_cmp(): unexpected result"); + + talloc_free(ctr); + return true; +} + +/* + * Tests dsdb_module_schema_info_blob_read() + * and dsdb_module_schema_info_blob_write() + */ +static bool test_dsdb_module_schema_info_blob_rw(struct torture_context *tctx, + struct drsut_schemainfo_data *priv) +{ + int ldb_err; + DATA_BLOB blob_write; + DATA_BLOB blob_read; + + /* reset schmeInfo to know value */ + torture_assert(tctx, + _drsut_ldb_schema_info_reset(tctx, priv->ldb, SCHEMA_INFO_INIT_STR, false), + "_drsut_ldb_schema_info_reset() failed"); + + /* write tests' default schemaInfo */ + blob_write = strhex_to_data_blob(priv, SCHEMA_INFO_DEFAULT_STR); + torture_assert(tctx, blob_write.data, "Not enough memory!"); + + ldb_err = dsdb_module_schema_info_blob_write(priv->ldb_module, + DSDB_FLAG_TOP_MODULE, + &blob_write, NULL); + torture_assert_int_equal(tctx, ldb_err, LDB_SUCCESS, "dsdb_module_schema_info_blob_write() failed"); + + ldb_err = dsdb_module_schema_info_blob_read(priv->ldb_module, DSDB_FLAG_TOP_MODULE, + priv, &blob_read, NULL); + torture_assert_int_equal(tctx, ldb_err, LDB_SUCCESS, "dsdb_module_schema_info_blob_read() failed"); + + /* check if we get what we wrote */ + torture_assert_data_blob_equal(tctx, blob_read, blob_write, + "Write/Read of schemeInfo blob failed"); + + return true; +} + +/* + * Tests dsdb_schema_update_schema_info() + */ +static bool test_dsdb_module_schema_info_update(struct torture_context *tctx, + struct drsut_schemainfo_data *priv) +{ + int ldb_err; + WERROR werr; + DATA_BLOB blob; + struct dsdb_schema_info *schema_info; + + /* reset schmeInfo to know value */ + torture_assert(tctx, + _drsut_ldb_schema_info_reset(tctx, priv->ldb, SCHEMA_INFO_INIT_STR, false), + "_drsut_ldb_schema_info_reset() failed"); + + ldb_err = dsdb_module_schema_info_update(priv->ldb_module, + priv->schema, + DSDB_FLAG_TOP_MODULE | DSDB_FLAG_AS_SYSTEM, NULL); + torture_assert_int_equal(tctx, ldb_err, LDB_SUCCESS, "dsdb_module_schema_info_update() failed"); + + /* get updated schemaInfo */ + ldb_err = dsdb_module_schema_info_blob_read(priv->ldb_module, DSDB_FLAG_TOP_MODULE, + priv, &blob, NULL); + torture_assert_int_equal(tctx, ldb_err, LDB_SUCCESS, "dsdb_module_schema_info_blob_read() failed"); + + werr = dsdb_schema_info_from_blob(&blob, priv, &schema_info); + torture_assert_werr_ok(tctx, werr, "dsdb_schema_info_from_blob() failed"); + + /* check against default schema_info */ + torture_assert_schema_info_equal(tctx, schema_info, priv->schema_info, + "schemaInfo attribute no updated correctly"); + + return true; +} + + +/** + * Reset schemaInfo record to know value + */ +static bool _drsut_ldb_schema_info_reset(struct torture_context *tctx, + struct ldb_context *ldb, + const char *schema_info_str, + bool in_setup) +{ + bool bret = true; + int ldb_err; + DATA_BLOB blob; + struct ldb_message *msg; + TALLOC_CTX *mem_ctx = talloc_new(tctx); + + blob = strhex_to_data_blob(mem_ctx, schema_info_str); + torture_assert_goto(tctx, blob.data, bret, DONE, "Not enough memory!"); + + msg = ldb_msg_new(mem_ctx); + torture_assert_goto(tctx, msg, bret, DONE, "Not enough memory!"); + + msg->dn = ldb_get_schema_basedn(ldb); + ldb_err = ldb_msg_add_value(msg, "schemaInfo", &blob, NULL); + torture_assert_int_equal_goto(tctx, ldb_err, LDB_SUCCESS, bret, DONE, + "ldb_msg_add_value() failed"); + + if (in_setup) { + ldb_err = ldb_add(ldb, msg); + } else { + ldb_err = dsdb_replace(ldb, msg, DSDB_MODIFY_PERMISSIVE); + } + torture_assert_int_equal_goto(tctx, ldb_err, LDB_SUCCESS, bret, DONE, + "dsdb_replace() failed"); + +DONE: + talloc_free(mem_ctx); + return bret; +} + +/** + * Prepare temporary LDB and opens it + */ +static bool _drsut_ldb_setup(struct torture_context *tctx, struct drsut_schemainfo_data *priv) +{ + int ldb_err; + char *ldb_url; + bool bret = true; + char *tempdir = NULL; + NTSTATUS status; + TALLOC_CTX* mem_ctx; + + mem_ctx = talloc_new(priv); + torture_assert(tctx, mem_ctx, "Not enough memory!"); + + status = torture_temp_dir(tctx, "drs_", &tempdir); + torture_assert_ntstatus_ok_goto(tctx, status, bret, DONE, "creating temp dir"); + + ldb_url = talloc_asprintf(priv, "%s/drs_schemainfo.ldb", tempdir); + torture_assert_goto(tctx, ldb_url, bret, DONE, "Not enough memory!"); + + /* create LDB */ + priv->ldb = ldb_wrap_connect(priv, tctx->ev, tctx->lp_ctx, + ldb_url, NULL, NULL, 0); + torture_assert_goto(tctx, priv->ldb, bret, DONE, "ldb_wrap_connect() failed"); + + /* set some schemaNamingContext */ + ldb_err = ldb_set_opaque(priv->ldb, + "schemaNamingContext", + ldb_dn_new(priv->ldb, priv->ldb, "CN=Schema,CN=Config")); + torture_assert_int_equal_goto(tctx, ldb_err, LDB_SUCCESS, bret, DONE, + "ldb_set_opaque() failed"); + + /* add schemaInfo attribute so tested layer could work properly */ + torture_assert_goto(tctx, + _drsut_ldb_schema_info_reset(tctx, priv->ldb, SCHEMA_INFO_INIT_STR, true), + bret, DONE, + "_drsut_ldb_schema_info_reset() failed"); + +DONE: + talloc_free(tempdir); + talloc_free(mem_ctx); + return bret; +} + +/* + * Setup/Teardown for test case + */ +static bool torture_drs_unit_schemainfo_setup(struct torture_context *tctx, + struct drsut_schemainfo_data **_priv) +{ + size_t i; + int ldb_err; + NTSTATUS status; + DATA_BLOB ndr_blob; + struct GUID guid; + struct drsut_schemainfo_data *priv; + + priv = talloc_zero(tctx, struct drsut_schemainfo_data); + torture_assert(tctx, priv, "Not enough memory!"); + + /* returned allocated pointer here + * teardown() will be called even in case of failure, + * so we'll get a changes to clean up */ + *_priv = priv; + + /* create initial schemaInfo */ + torture_assert(tctx, + _drsut_schemainfo_new(tctx, SCHEMA_INFO_DEFAULT_STR, &priv->schema_info), + "Failed to create schema_info test object"); + + /* create data to test with */ + priv->test_data_count = ARRAY_SIZE(_schemainfo_test_data); + priv->test_data = talloc_array(tctx, struct schemainfo_data, priv->test_data_count); + + for (i = 0; i < ARRAY_SIZE(_schemainfo_test_data); i++) { + struct schemainfo_data *data = &priv->test_data[i]; + + ndr_blob = strhex_to_data_blob(priv, + _schemainfo_test_data[i].schema_info_str); + torture_assert(tctx, ndr_blob.data, "Not enough memory!"); + + status = GUID_from_string(_schemainfo_test_data[i].guid_str, &guid); + torture_assert_ntstatus_ok(tctx, status, + talloc_asprintf(tctx, + "GUID_from_string() failed for %s", + _schemainfo_test_data[i].guid_str)); + + data->ndr_blob = ndr_blob; + data->schi.invocation_id = guid; + data->schi.revision = _schemainfo_test_data[i].revision; + data->werr_expected = _schemainfo_test_data[i].werr_expected; + data->test_both_ways = _schemainfo_test_data[i].test_both_ways; + + } + + /* create temporary LDB and populate with data */ + if (!_drsut_ldb_setup(tctx, priv)) { + return false; + } + + /* create ldb_module mockup object */ + priv->ldb_module = ldb_module_new(priv, priv->ldb, "schemaInfo_test_module", NULL); + torture_assert(tctx, priv->ldb_module, "Not enough memory!"); + + /* create schema mockup object */ + priv->schema = dsdb_new_schema(priv); + + /* set schema_info in dsdb_schema for testing */ + torture_assert(tctx, + _drsut_schemainfo_new(tctx, SCHEMA_INFO_DEFAULT_STR, &priv->schema->schema_info), + "Failed to create schema_info test object"); + + /* pre-cache invocationId for samdb_ntds_invocation_id() + * to work with our mock ldb */ + ldb_err = ldb_set_opaque(priv->ldb, "cache.invocation_id", + &priv->schema_info->invocation_id); + torture_assert_int_equal(tctx, ldb_err, LDB_SUCCESS, "ldb_set_opaque() failed"); + + /* Perform all tests in transactions so that + * underlying modify calls not to fail */ + ldb_err = ldb_transaction_start(priv->ldb); + torture_assert_int_equal(tctx, + ldb_err, + LDB_SUCCESS, + "ldb_transaction_start() failed"); + + return true; +} + +static bool torture_drs_unit_schemainfo_teardown(struct torture_context *tctx, + struct drsut_schemainfo_data *priv) +{ + int ldb_err; + + /* commit pending transaction so we will + * be able to check what LDB state is */ + ldb_err = ldb_transaction_commit(priv->ldb); + if (ldb_err != LDB_SUCCESS) { + torture_comment(tctx, "ldb_transaction_commit() - %s (%s)", + ldb_strerror(ldb_err), + ldb_errstring(priv->ldb)); + } + + talloc_free(priv); + + return true; +} + +/** + * Test case initialization for + * drs.unit.schemaInfo + */ +struct torture_tcase * torture_drs_unit_schemainfo(struct torture_suite *suite) +{ + typedef bool (*pfn_setup)(struct torture_context *, void **); + typedef bool (*pfn_teardown)(struct torture_context *, void *); + typedef bool (*pfn_run)(struct torture_context *, void *); + + struct torture_tcase * tc = torture_suite_add_tcase(suite, "schemaInfo"); + + torture_tcase_set_fixture(tc, + (pfn_setup)torture_drs_unit_schemainfo_setup, + (pfn_teardown)torture_drs_unit_schemainfo_teardown); + + tc->description = talloc_strdup(tc, "Unit tests for DRSUAPI::schemaInfo implementation"); + + torture_tcase_add_simple_test(tc, "dsdb_schema_info_new", + (pfn_run)test_dsdb_schema_info_new); + torture_tcase_add_simple_test(tc, "dsdb_schema_info_from_blob", + (pfn_run)test_dsdb_schema_info_from_blob); + torture_tcase_add_simple_test(tc, "dsdb_blob_from_schema_info", + (pfn_run)test_dsdb_blob_from_schema_info); + torture_tcase_add_simple_test(tc, "dsdb_schema_info_cmp", + (pfn_run)test_dsdb_schema_info_cmp); + torture_tcase_add_simple_test(tc, "dsdb_module_schema_info_blob read|write", + (pfn_run)test_dsdb_module_schema_info_blob_rw); + torture_tcase_add_simple_test(tc, "dsdb_module_schema_info_update", + (pfn_run)test_dsdb_module_schema_info_update); + + + return tc; +} |