dsdb_create_prefix_mapping() implementation checks for existing prefix maping in...
authorAnatoliy Atanasov <anatoliy.atanasov@postpath.com>
Mon, 21 Jul 2008 14:04:49 +0000 (17:04 +0300)
committerAndrew Bartlett <abartlet@samba.org>
Thu, 24 Jul 2008 01:54:38 +0000 (11:54 +1000)
if one not found it creates a mapping for it and updates the prefixMap schema attribute in ldb.
(This used to be commit bbe895db7144b192981fad9ab6bbd3ebacb8d299)

source4/dsdb/schema/schema_init.c

index 71d952b944bbaa926fd4aaab9fccb3a89246cc8c..2ec5ad34b138e15dd9db073070ff7aa8922aaa10 100644 (file)
@@ -267,19 +267,146 @@ WERROR dsdb_verify_oid_mappings_drsuapi(const struct dsdb_schema *schema, const
 }
 
 WERROR dsdb_map_oid2int(const struct dsdb_schema *schema, const char *in, uint32_t *out)
+{
+       return dsdb_find_prefix_for_oid(schema->num_prefixes, schema->prefixes, in, out);
+}
+
+
+WERROR dsdb_map_int2oid(const struct dsdb_schema *schema, uint32_t in, TALLOC_CTX *mem_ctx, const char **out)
 {
        uint32_t i;
 
        for (i=0; i < schema->num_prefixes; i++) {
+               const char *val;
+               if (schema->prefixes[i].id != (in & 0xFFFF0000)) {
+                       continue;
+               }
+
+               val = talloc_asprintf(mem_ctx, "%s%u",
+                                     schema->prefixes[i].oid,
+                                     in & 0xFFFF);
+               W_ERROR_HAVE_NO_MEMORY(val);
+
+               *out = val;
+               return WERR_OK;
+       }
+
+       return WERR_DS_NO_MSDS_INTID;
+}
+
+/*
+ * this function is called from within a ldb transaction from the schema_fsmo module
+ */
+WERROR dsdb_create_prefix_mapping(struct ldb_context *ldb, struct dsdb_schema *schema, const char *full_oid)
+{
+       WERROR status;
+       uint32_t num_prefixes;
+       struct dsdb_schema_oid_prefix *prefixes;
+       struct ldb_val ndr_blob;
+       TALLOC_CTX *mem_ctx;
+       uint32_t out;
+
+       mem_ctx = talloc_new(ldb);
+       W_ERROR_HAVE_NO_MEMORY(mem_ctx);
+
+       /* Read prefixes from disk*/
+       status = dsdb_read_prefixes_from_ldb( mem_ctx, ldb, &num_prefixes, &prefixes ); 
+       if (!W_ERROR_IS_OK(status)) {
+               DEBUG(0,("dsdb_create_prefix_mapping: dsdb_read_prefixes_from_ldb failed\n"));
+               talloc_free(mem_ctx);
+               return status;
+       }
+
+       /* Check if there is a prefix for the oid in the prefixes array*/
+       status = dsdb_find_prefix_for_oid( num_prefixes, prefixes, full_oid, &out ); 
+       if (W_ERROR_IS_OK(status)) {
+               /* prefix found*/
+               talloc_free(mem_ctx);
+               return status;
+       }
+       /* Update prefix map in ldb*/
+       /* Update the prefixes */
+       status = dsdb_prefix_map_update(mem_ctx, &num_prefixes, &prefixes, full_oid);
+       if (!W_ERROR_IS_OK(status)) {
+               DEBUG(0,("dsdb_create_prefix_mapping: dsdb_prefix_map_update failed\n"));
+               talloc_free(mem_ctx);
+               return status;
+       }
+       /* Convert prefixes in ndr blob*/
+       status = dsdb_write_prefixes_to_ndr( mem_ctx, ldb, num_prefixes, prefixes, &ndr_blob );
+       if (!W_ERROR_IS_OK(status)) {
+               DEBUG(0,("dsdb_create_prefix_mapping: dsdb_write_prefixes_to_ndr failed\n"));
+               talloc_free(mem_ctx);
+               return status;
+       }
+
+       /* Update prefixMap in ldb*/
+       status = dsdb_write_prefixes_to_ldb( mem_ctx, ldb, &ndr_blob );
+       if (!W_ERROR_IS_OK(status)) {
+               DEBUG(0,("dsdb_create_prefix_mapping: dsdb_write_prefixes_to_ldb failed\n"));
+               talloc_free(mem_ctx);
+               return status;
+       }
+
+       talloc_free(mem_ctx);
+       return status;
+}
+
+WERROR dsdb_prefix_map_update(TALLOC_CTX *mem_ctx, uint32_t *num_prefixes, struct dsdb_schema_oid_prefix **prefixes, const char *oid)
+{
+       uint32_t new_num_prefixes, index_new_prefix, new_entry_id;
+       const char* lastDotOffset;
+       size_t size;
+       
+       new_num_prefixes = *num_prefixes + 1;
+       index_new_prefix = *num_prefixes;
+       new_entry_id = (*num_prefixes)<<16;
+
+       /* Extract the prefix from the oid*/
+       lastDotOffset = strrchr(oid, '.');
+       if (lastDotOffset == NULL) {
+               DEBUG(0,("dsdb_prefix_map_update: failed to find the last dot\n"));
+               return WERR_NOT_FOUND;
+       }
+
+       /* Calculate the size of the remainig string that should be the prefix of it */
+       size = strlen(oid) - strlen(lastDotOffset);
+       if (size <= 0) {
+               DEBUG(0,("dsdb_prefix_map_update: size of the remaining string invalid\n"));
+               return WERR_FOOBAR;
+       }
+       /* Add one because we need to copy the dot */
+       size += 1;
+
+       /* Create a spot in the prefixMap for one more prefix*/
+       (*prefixes) = talloc_realloc(mem_ctx, *prefixes, struct dsdb_schema_oid_prefix, new_num_prefixes);
+       W_ERROR_HAVE_NO_MEMORY(*prefixes);
+
+       /* Add the new prefix entry*/
+       (*prefixes)[index_new_prefix].id = new_entry_id;
+       (*prefixes)[index_new_prefix].oid = talloc_strndup(mem_ctx, oid, size);
+       (*prefixes)[index_new_prefix].oid_len = strlen((*prefixes)[index_new_prefix].oid);
+
+       /* Increase num_prefixes because new prefix has been added */
+       ++(*num_prefixes);
+
+       return WERR_OK;
+}
+
+WERROR dsdb_find_prefix_for_oid(uint32_t num_prefixes, const struct dsdb_schema_oid_prefix *prefixes, const char *in, uint32_t *out)
+{
+       uint32_t i;
+
+       for (i=0; i < num_prefixes; i++) {
                const char *val_str;
                char *end_str;
                unsigned val;
 
-               if (strncmp(schema->prefixes[i].oid, in, schema->prefixes[i].oid_len) != 0) {
+               if (strncmp(prefixes[i].oid, in, prefixes[i].oid_len) != 0) {
                        continue;
                }
 
-               val_str = in + schema->prefixes[i].oid_len;
+               val_str = in + prefixes[i].oid_len;
                end_str = NULL;
                errno = 0;
 
@@ -305,58 +432,152 @@ WERROR dsdb_map_oid2int(const struct dsdb_schema *schema, const char *in, uint32
                        return WERR_INVALID_PARAM;
                }
 
-               *out = schema->prefixes[i].id | val;
+               *out = prefixes[i].id | val;
                return WERR_OK;
        }
 
        return WERR_DS_NO_MSDS_INTID;
 }
 
-WERROR dsdb_map_int2oid(const struct dsdb_schema *schema, uint32_t in, TALLOC_CTX *mem_ctx, const char **out)
+WERROR dsdb_write_prefixes_to_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, struct ldb_val *ndr_blob)
 {
+       struct ldb_message msg;
+       struct ldb_dn *schema_dn;
+       struct ldb_message_element el;
+       int ret;
+       
+       schema_dn = samdb_schema_dn(ldb);
+       if (!schema_dn) {
+               DEBUG(0,("dsdb_write_prefixes_to_ldb: no schema dn present\n"));        
+               return WERR_FOOBAR;
+       }
+       el.num_values = 1;
+       el.values = ndr_blob;
+       el.flags = LDB_FLAG_MOD_REPLACE;
+       el.name = talloc_strdup(mem_ctx, "prefixMap");
+       msg.dn = ldb_dn_copy(mem_ctx, schema_dn);
+       msg.num_elements = 1;
+       msg.elements = &el;
+       ret = ldb_modify( ldb, &msg );
+       if (ret != 0) {
+               DEBUG(0,("dsdb_write_prefixes_to_ldb: ldb_modify failed\n"));   
+               return WERR_FOOBAR;
+       }
+       return WERR_OK;
+}
+
+WERROR dsdb_read_prefixes_from_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, uint32_t* num_prefixes, struct dsdb_schema_oid_prefix **prefixes)
+{
+       struct prefixMapBlob *blob;
+       enum ndr_err_code ndr_err;
        uint32_t i;
+       const struct ldb_val *prefix_val;
+       struct ldb_dn *schema_dn;
+       struct ldb_result *schema_res;
+       int ret;    
+       static const char *schema_attrs[] = {
+               "prefixMap",
+               NULL
+       };
 
-       for (i=0; i < schema->num_prefixes; i++) {
-               const char *val;
-               if (schema->prefixes[i].id != (in & 0xFFFF0000)) {
-                       continue;
-               }
+       schema_dn = samdb_schema_dn(ldb);
+       if (!schema_dn) {
+               DEBUG(0,("dsdb_read_prefixes_from_ldb: no schema dn present\n"));
+               return WERR_FOOBAR;
+       }
 
-               val = talloc_asprintf(mem_ctx, "%s%u",
-                                     schema->prefixes[i].oid,
-                                     in & 0xFFFF);
-               W_ERROR_HAVE_NO_MEMORY(val);
+       ret = ldb_search(ldb, schema_dn, LDB_SCOPE_BASE,NULL, schema_attrs,&schema_res);
+       if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+               DEBUG(0,("dsdb_read_prefixes_from_ldb: no prefix map present\n"));
+               return WERR_FOOBAR;
+       } else if (ret != LDB_SUCCESS) {
+               DEBUG(0,("dsdb_read_prefixes_from_ldb: failed to search the schema head\n"));
+               return WERR_FOOBAR;
+       }
 
-               *out = val;
-               return WERR_OK;
+       prefix_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "prefixMap");
+       if (!prefix_val) {
+               DEBUG(0,("dsdb_read_prefixes_from_ldb: no prefixMap attribute found\n"));
+               return WERR_FOOBAR;
        }
 
-       return WERR_DS_NO_MSDS_INTID;
+       blob = talloc(mem_ctx, struct prefixMapBlob);
+       W_ERROR_HAVE_NO_MEMORY(blob);
+
+       ndr_err = ndr_pull_struct_blob(prefix_val, blob, 
+                                          lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), 
+                                          blob,
+                                          (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               DEBUG(0,("dsdb_read_prefixes_from_ldb: ndr_pull_struct_blob failed\n"));
+               talloc_free(blob);
+               return WERR_FOOBAR;
+       }
+
+       if (blob->version != PREFIX_MAP_VERSION_DSDB) {
+               DEBUG(0,("dsdb_read_prefixes_from_ldb: blob->version incorect\n"));
+               talloc_free(blob);
+               return WERR_FOOBAR;
+       }
+       
+       *num_prefixes = blob->ctr.dsdb.num_mappings;
+       *prefixes = talloc_array(mem_ctx, struct dsdb_schema_oid_prefix, *num_prefixes);
+       if(!(*prefixes)) {
+               talloc_free(blob);
+               return WERR_NOMEM;
+       }
+       for (i=0; i < blob->ctr.dsdb.num_mappings; i++) {
+               (*prefixes)[i].id = blob->ctr.dsdb.mappings[i].id_prefix<<16;
+               (*prefixes)[i].oid = talloc_strdup(mem_ctx, blob->ctr.dsdb.mappings[i].oid.oid);
+               (*prefixes)[i].oid = talloc_asprintf_append((*prefixes)[i].oid, "."); 
+               (*prefixes)[i].oid_len = strlen(blob->ctr.dsdb.mappings[i].oid.oid);
+       }
+
+       talloc_free(blob);
+       return WERR_OK;
 }
 
-/*
- * this function is called from within a ldb transaction from the schema_fsmo module
- */
-WERROR dsdb_create_prefix_mapping(struct ldb_context *ldb, struct dsdb_schema *schema, const char *full_oid)
+
+WERROR dsdb_write_prefixes_to_ndr(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, uint32_t num_prefixes, const struct dsdb_schema_oid_prefix *prefixes, struct ldb_val *out)
 {
-       /*
-        * TODO:
-        *      - (maybe) read the old prefixMap attribute and parse it
-        *
-        *      - recheck the prefix doesn't exist (because the ldb
-        *        has maybe a more uptodate value than schem->prefixes
-        *
-        *      - calculate a new mapping for the oid prefix of full_oid
-        *      - store the new prefixMap attribute
-        *
-        *      - (maybe) update schema->prefixes
-        *      or
-        *      - better find a way to indicate a schema reload,
-        *        so that other processes also notice the schema change
-        */
-       return WERR_NOT_SUPPORTED;
+       struct prefixMapBlob *blob;
+       enum ndr_err_code ndr_err;
+       uint32_t i;
+
+       blob = talloc_zero(mem_ctx, struct prefixMapBlob);
+       W_ERROR_HAVE_NO_MEMORY(blob);
+
+       blob->version = PREFIX_MAP_VERSION_DSDB;
+       blob->ctr.dsdb.num_mappings = num_prefixes;
+       blob->ctr.dsdb.mappings = talloc_realloc(blob,
+                                                                                       blob->ctr.dsdb.mappings,
+                                                                                       struct drsuapi_DsReplicaOIDMapping,
+                                                                                       blob->ctr.dsdb.num_mappings);
+       if (!blob->ctr.dsdb.mappings) {
+               return WERR_NOMEM;
+       }
+
+       for (i=0; i < num_prefixes; i++) {
+               blob->ctr.dsdb.mappings[i].id_prefix = prefixes[i].id>>16;
+               blob->ctr.dsdb.mappings[i].oid.oid = talloc_strdup(blob->ctr.dsdb.mappings, prefixes[i].oid);
+       }
+
+       ndr_err = ndr_push_struct_blob(out, ldb,
+                                          lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
+                                          blob,
+                                          (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               return WERR_FOOBAR;
+       }
+       
+       return WERR_OK;
 }
 
+
 #define GET_STRING_LDB(msg, attr, mem_ctx, p, elem, strict) do { \
        (p)->elem = samdb_result_string(msg, attr, NULL);\
        if (strict && (p)->elem == NULL) { \