Finish removal of iconv_convenience in public API's.
[samba.git] / source4 / torture / drs / unit / prefixmap_tests.c
index 16d8298ef25619b31b051f77d7e26e3e2c7dd869..a4521eb675d360252a46c65ce53a5ef6d793c3fd 100644 (file)
 */
 
 #include "includes.h"
+#include "system/filesys.h"
 #include "torture/smbtorture.h"
-#include "torture/rpc/drsuapi.h"
 #include "dsdb/samdb/samdb.h"
+#include "torture/rpc/drsuapi.h"
+#include "torture/drs/proto.h"
+#include "param/param.h"
 
 
 /**
 struct drsut_prefixmap_data {
        struct dsdb_schema_prefixmap *pfm_new;
        struct dsdb_schema_prefixmap *pfm_full;
+
+       /* default schemaInfo value to test with */
+       const char *schi_default_str;
+       struct dsdb_schema_info *schi_default;
+
+       struct ldb_context *ldb_ctx;
 };
 
 /**
@@ -182,23 +191,41 @@ static WERROR _drsut_prefixmap_new(const struct drsut_pfm_oid_data *_pfm_init_da
 
 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)
+                                         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;
+       }
 
-       torture_assert_int_equal(tctx, pfm_left->length, pfm_right->length,
-                                "prefixMaps differ in size");
        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];
 
-               torture_assert(tctx, entry_left->id == entry_right->id,
-                               talloc_asprintf(tctx, "Different IDs for index=%d", i));
-               torture_assert_data_blob_equal(tctx, entry_left->bin_oid, entry_right->bin_oid,
-                                               talloc_asprintf(tctx, "Different bin_oid for index=%d", 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;
 }
 
 /*
@@ -221,7 +248,7 @@ static bool torture_drs_unit_pfm_new(struct torture_context *tctx, struct drsut_
        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);
+       bret = _torture_drs_pfm_compare_same(tctx, priv->pfm_new, pfm, false);
 
        talloc_free(mem_ctx);
 
@@ -355,23 +382,366 @@ static bool torture_drs_unit_pfm_oid_from_attid(struct torture_context *tctx, st
        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, 0x00000000, tctx, &oid);
+       torture_assert_werr_ok(tctx, werr, "Testing prefixMap type attid = 0x0000000");
+
+       /* 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;
+       const char *schema_info;
+       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_str, 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 = hex_encode_talloc(mem_ctx,
+                                       ctr->mappings[ctr->num_mappings - 1].oid.binary_oid,
+                                       ctr->mappings[ctr->num_mappings - 1].oid.length);
+       torture_assert_str_equal(tctx,
+                                schema_info,
+                                priv->schi_default_str,
+                                "schema_info 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_str_equal(tctx, schema_info, priv->schi_default_str, "Fetched schema_info is different");
+
+       /* 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;
+       const char *schema_info;
+       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_str;
+
+       /* 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");
+       /* look for schema_info entry - it should be the last one */
+       schema_info = hex_encode_talloc(mem_ctx,
+                                       schema_info_ldb_val.data,
+                                       schema_info_ldb_val.length);
+       torture_assert_str_equal(tctx,
+                                schema_info,
+                                priv->schi_default_str,
+                                "schema_info not stored correctly or not last entry");
+
+       /* 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;
+       }
+
+       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_str;
+
+       /* 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 rdsdb_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;
+       const struct {
+               const char      *oid;
+               uint32_t        attid;
+               bool            exists; /* if this prefix already exists or should be added */
+       } _test_data[] = {
+               {.oid="2.5.4.0",                .attid=0x00000000, true},
+               {.oid="2.5.4.42",               .attid=0x0000002a, true},
+               {.oid="1.2.840.113556.1.2.1",   .attid=0x00020001, true},
+               {.oid="1.2.840.113556.1.2.13",  .attid=0x0002000d, true},
+               {.oid="1.2.840.113556.1.2.281", .attid=0x00020119, true},
+               {.oid="1.2.840.113556.1.4.125", .attid=0x0009007d, true},
+               {.oid="1.2.840.113556.1.4.146", .attid=0x00090092, true},
+               {.oid="1.2.250.1",              .attid=0x1b860001, false},
+               {.oid="1.2.250.16386",          .attid=0x1c788002, false},
+               {.oid="1.2.250.2097154",        .attid=0x1c7b8002, false},
+       };
+
+       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_str;
+       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");
+
+       for (i = 0; i < ARRAY_SIZE(_test_data); i++) {
+               struct dsdb_schema_prefixmap *pfm_ldb;
+               struct dsdb_schema_prefixmap *pfm_prev;
+
+               /* add ref to prefixMap so we can use it later */
+               pfm_prev = talloc_reference(schema, schema->prefixmap);
+
+               /* call dsdb_create_prefix_mapping() and check result accordingly */
+               werr = dsdb_create_prefix_mapping(priv->ldb_ctx, schema, _test_data[i].oid);
+               torture_assert_werr_ok(tctx, werr, "dsdb_create_prefix_mapping() failed");
+
+               /* verify pfm has been altered or not if needed */
+               if (_test_data[i].exists) {
+                       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");
+                       }
+               } else {
+                       torture_assert(tctx, pfm_prev != schema->prefixmap,
+                                      "schema->prefixmap should be reallocated!");
+                       if (_torture_drs_pfm_compare_same(tctx, pfm_prev, schema->prefixmap, true)) {
+                               torture_fail(tctx, "schema->prefixmap should be 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, schema->prefixmap, pfm_ldb, true)) {
+                       torture_fail(tctx, "schema->prefixmap and pfm in LDB are different");
+               }
+               /* free mem for pfm read from LDB */
+               talloc_free(pfm_ldb);
+
+               /* release prefixMap pointer */
+               talloc_unlink(schema, pfm_prev);
+       }
+
+       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_empty() 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)
+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 = talloc_zero(tctx, struct drsut_prefixmap_data);
-       torture_assert(tctx, *priv != NULL, "Not enough memory");
+       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);
+       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);
+       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");
+
+       priv->schi_default_str = data_blob_hex_string_upper(priv, &blob);
+
+       /* create temporary LDB and populate with data */
+       if (!torture_drs_unit_ldb_setup(tctx, priv)) {
+               return false;
+       }
+
        return true;
 }
 
@@ -405,6 +775,16 @@ struct torture_tcase * torture_drs_unit_prefixmap(struct torture_suite *suite)
        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, "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;
 }