dsdb: Audit group membership changes
[nivanova/samba-autobuild/.git] / source4 / dsdb / samdb / ldb_modules / samba_dsdb.c
index 26c583ef58a16fd6d8ce6704352d9b73f50eb79e..fa58f19db29a44447298ffae3479a7567550d58a 100644 (file)
@@ -228,14 +228,32 @@ static int set_ldap_credentials(struct ldb_context *ldb, bool use_external)
        return LDB_SUCCESS;
 }
 
+static bool check_required_features(struct ldb_message_element *el)
+{
+       if (el != NULL) {
+               int k;
+               DATA_BLOB esf = data_blob_string_const(
+                       SAMBA_ENCRYPTED_SECRETS_FEATURE);
+               DATA_BLOB lmdbl1 = data_blob_string_const(
+                       SAMBA_LMDB_LEVEL_ONE_FEATURE);
+               for (k = 0; k < el->num_values; k++) {
+                       if ((data_blob_cmp(&esf, &el->values[k]) != 0) &&
+                           (data_blob_cmp(&lmdbl1, &el->values[k]) != 0)) {
+                               return false;
+                       }
+               }
+       }
+       return true;
+}
+
 static int samba_dsdb_init(struct ldb_module *module)
 {
        struct ldb_context *ldb = ldb_module_get_ctx(module);
-       int ret, len, i;
+       int ret, lock_ret, len, i, j;
        TALLOC_CTX *tmp_ctx = talloc_new(module);
        struct ldb_result *res;
        struct ldb_message *rootdse_msg = NULL, *partition_msg;
-       struct ldb_dn *samba_dsdb_dn, *partition_dn;
+       struct ldb_dn *samba_dsdb_dn, *partition_dn, *indexlist_dn;
        struct ldb_module *backend_module, *module_chain;
        const char **final_module_list, **reverse_module_list;
        /*
@@ -261,10 +279,12 @@ static int samba_dsdb_init(struct ldb_module *module)
        */
        static const char *modules_list1[] = {"resolve_oids",
                                             "rootdse",
+                                            "dsdb_notification",
                                             "schema_load",
                                             "lazy_commit",
                                             "dirsync",
                                             "paged_results",
+                                            "vlv",
                                             "ranged_results",
                                             "anr",
                                             "server_sort",
@@ -272,13 +292,14 @@ static int samba_dsdb_init(struct ldb_module *module)
                                             "extended_dn_store",
                                             NULL };
        /* extended_dn_in or extended_dn_in_openldap goes here */
-       static const char *modules_list1a[] = {"objectclass",
+       static const char *modules_list1a[] = {"audit_log",
+                                            "objectclass",
+                                            "tombstone_reanimate",
                                             "descriptor",
                                             "acl",
                                             "aclread",
                                             "samldb",
                                             "password_hash",
-                                            "operational",
                                             "instancetype",
                                             "objectclass_attrs",
                                             NULL };
@@ -292,6 +313,10 @@ static int samba_dsdb_init(struct ldb_module *module)
                "rdn_name",
                "subtree_delete",
                "repl_meta_data",
+               "group_audit_log",
+               "encrypted_secrets",
+               "operational",
+               "unique_object_sids",
                "subtree_rename",
                "linked_attributes",
                NULL};
@@ -310,15 +335,20 @@ static int samba_dsdb_init(struct ldb_module *module)
 
        const char **backend_modules;
        static const char *fedora_ds_backend_modules[] = {
-               "nsuniqueid", "paged_searches", "simple_dn", NULL };
+               "dsdb_flags_ignore", "nsuniqueid", "paged_searches", "simple_dn", NULL };
        static const char *openldap_backend_modules[] = {
-               "entryuuid", "simple_dn", NULL };
+               "dsdb_flags_ignore", "entryuuid", "simple_dn", NULL };
 
-       static const char *samba_dsdb_attrs[] = { "backendType", NULL };
+       static const char *samba_dsdb_attrs[] = { "backendType",
+                                                 SAMBA_COMPATIBLE_FEATURES_ATTR,
+                                                 SAMBA_REQUIRED_FEATURES_ATTR, NULL };
+       static const char *indexlist_attrs[] = { SAMBA_FEATURES_SUPPORTED_FLAG, NULL };
        static const char *partition_attrs[] = { "ldapBackend", NULL };
        const char *backendType, *backendUrl;
        bool use_sasl_external = false;
 
+       const char *current_supportedFeatures[] = {SAMBA_SORTED_LINKS_FEATURE};
+
        if (!tmp_ctx) {
                return ldb_oom(ldb);
        }
@@ -335,6 +365,12 @@ static int samba_dsdb_init(struct ldb_module *module)
                return ldb_oom(ldb);
        }
 
+       indexlist_dn = ldb_dn_new(tmp_ctx, ldb, "@INDEXLIST");
+       if (!samba_dsdb_dn) {
+               talloc_free(tmp_ctx);
+               return ldb_oom(ldb);
+       }
+
        partition_dn = ldb_dn_new(tmp_ctx, ldb, DSDB_PARTITION_DN);
        if (!partition_dn) {
                talloc_free(tmp_ctx);
@@ -354,7 +390,118 @@ static int samba_dsdb_init(struct ldb_module *module)
        if (ret == LDB_ERR_NO_SUCH_OBJECT) {
                backendType = "ldb";
        } else if (ret == LDB_SUCCESS) {
+               struct ldb_message_element *requiredFeatures;
+               struct ldb_message_element *old_compatibleFeatures;
+
                backendType = ldb_msg_find_attr_as_string(res->msgs[0], "backendType", "ldb");
+
+               requiredFeatures = ldb_msg_find_element(res->msgs[0], SAMBA_REQUIRED_FEATURES_ATTR);
+               if (!check_required_features(requiredFeatures)) {
+                       ldb_set_errstring(
+                               ldb,
+                               "This Samba database was created with "
+                               "a newer Samba version and is marked "
+                               "with extra requiredFeatures in "
+                               "@SAMBA_DSDB. This database can not "
+                               "safely be read by this Samba version");
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+
+               old_compatibleFeatures = ldb_msg_find_element(res->msgs[0],
+                                                             SAMBA_COMPATIBLE_FEATURES_ATTR);
+
+               if (old_compatibleFeatures) {
+                       struct ldb_message *features_msg;
+                       struct ldb_message_element *features_el;
+                       int samba_options_supported = 0;
+                       ret = dsdb_module_search_dn(module, tmp_ctx, &res,
+                                                   indexlist_dn,
+                                                   indexlist_attrs,
+                                                   DSDB_FLAG_NEXT_MODULE, NULL);
+                       if (ret == LDB_SUCCESS) {
+                               samba_options_supported
+                                       = ldb_msg_find_attr_as_int(res->msgs[0],
+                                                                  SAMBA_FEATURES_SUPPORTED_FLAG,
+                                                                  0);
+
+                       } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+                               /*
+                                * If we don't have @INDEXLIST yet, then we
+                                * are so early in set-up that we know this is
+                                * a blank DB, so no need to wripe out old
+                                * features
+                                */
+                               samba_options_supported = 1;
+                       }
+
+                       features_msg = ldb_msg_new(res);
+                       if (features_msg == NULL) {
+                               return ldb_module_operr(module);
+                       }
+                       features_msg->dn = samba_dsdb_dn;
+
+                       ldb_msg_add_empty(features_msg, SAMBA_COMPATIBLE_FEATURES_ATTR,
+                                         LDB_FLAG_MOD_DELETE, &features_el);
+
+                       if (samba_options_supported == 1) {
+                               for (i = 0;
+                                    old_compatibleFeatures && i < old_compatibleFeatures->num_values;
+                                    i++) {
+                                       for (j = 0;
+                                            j < ARRAY_SIZE(current_supportedFeatures); j++) {
+                                               if (strcmp((char *)old_compatibleFeatures->values[i].data,
+                                                          current_supportedFeatures[j]) == 0) {
+                                                       break;
+                                               }
+                                       }
+                                       if (j == ARRAY_SIZE(current_supportedFeatures)) {
+                                               /*
+                                                * Add to list of features to remove
+                                                * (rather than all features)
+                                                */
+                                               ret = ldb_msg_add_value(features_msg, SAMBA_COMPATIBLE_FEATURES_ATTR,
+                                                                       &old_compatibleFeatures->values[i],
+                                                                       NULL);
+                                               if (ret != LDB_SUCCESS) {
+                                                       return ret;
+                                               }
+                                       }
+                               }
+
+                               if (features_el->num_values > 0) {
+                                       /* Delete by list */
+                                       ret = ldb_next_start_trans(module);
+                                       if (ret != LDB_SUCCESS) {
+                                               return ret;
+                                       }
+                                       ret = dsdb_module_modify(module, features_msg, DSDB_FLAG_NEXT_MODULE, NULL);
+                                       if (ret != LDB_SUCCESS) {
+                                               ldb_next_del_trans(module);
+                                               return ret;
+                                       }
+                                       ret = ldb_next_end_trans(module);
+                                       if (ret != LDB_SUCCESS) {
+                                               return ret;
+                                       }
+                               }
+                       } else {
+                               /* Delete all */
+                               ret = ldb_next_start_trans(module);
+                               if (ret != LDB_SUCCESS) {
+                                       return ret;
+                               }
+                               ret = dsdb_module_modify(module, features_msg, DSDB_FLAG_NEXT_MODULE, NULL);
+                               if (ret != LDB_SUCCESS) {
+                                       ldb_next_del_trans(module);
+                                       return ret;
+                               }
+                               ret = ldb_next_end_trans(module);
+                               if (ret != LDB_SUCCESS) {
+                                       return ret;
+                               }
+                       }
+               }
+
        } else {
                talloc_free(tmp_ctx);
                return ret;
@@ -482,7 +629,20 @@ static int samba_dsdb_init(struct ldb_module *module)
        /* Set this as the 'next' module, so that we effectivly append it to module chain */
        ldb_module_set_next(module, module_chain);
 
-       return ldb_next_init(module);
+       ret = ldb_next_read_lock(module);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       ret = ldb_next_init(module);
+
+       lock_ret = ldb_next_read_unlock(module);
+
+       if (lock_ret != LDB_SUCCESS) {
+               return lock_ret;
+       }
+
+       return ret;
 }
 
 static const struct ldb_module_ops ldb_samba_dsdb_module_ops = {
@@ -490,8 +650,108 @@ static const struct ldb_module_ops ldb_samba_dsdb_module_ops = {
        .init_context      = samba_dsdb_init,
 };
 
+static struct ldb_message *dsdb_flags_ignore_fixup(TALLOC_CTX *mem_ctx,
+                                               const struct ldb_message *_msg)
+{
+       struct ldb_message *msg = NULL;
+       unsigned int i;
+
+       /* we have to copy the message as the caller might have it as a const */
+       msg = ldb_msg_copy_shallow(mem_ctx, _msg);
+       if (msg == NULL) {
+               return NULL;
+       }
+
+       for (i=0; i < msg->num_elements;) {
+               struct ldb_message_element *e = &msg->elements[i];
+
+               if (!(e->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
+                       i++;
+                       continue;
+               }
+
+               e->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
+
+               if (e->num_values != 0) {
+                       i++;
+                       continue;
+               }
+
+               ldb_msg_remove_element(msg, e);
+       }
+
+       return msg;
+}
+
+static int dsdb_flags_ignore_add(struct ldb_module *module, struct ldb_request *req)
+{
+       struct ldb_context *ldb = ldb_module_get_ctx(module);
+       struct ldb_request *down_req = NULL;
+       struct ldb_message *msg = NULL;
+       int ret;
+
+       msg = dsdb_flags_ignore_fixup(req, req->op.add.message);
+       if (msg == NULL) {
+               return ldb_module_oom(module);
+       }
+
+       ret = ldb_build_add_req(&down_req, ldb, req,
+                               msg,
+                               req->controls,
+                               req, dsdb_next_callback,
+                               req);
+       LDB_REQ_SET_LOCATION(down_req);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       /* go on with the call chain */
+       return ldb_next_request(module, down_req);
+}
+
+static int dsdb_flags_ignore_modify(struct ldb_module *module, struct ldb_request *req)
+{
+       struct ldb_context *ldb = ldb_module_get_ctx(module);
+       struct ldb_request *down_req = NULL;
+       struct ldb_message *msg = NULL;
+       int ret;
+
+       msg = dsdb_flags_ignore_fixup(req, req->op.mod.message);
+       if (msg == NULL) {
+               return ldb_module_oom(module);
+       }
+
+       ret = ldb_build_mod_req(&down_req, ldb, req,
+                               msg,
+                               req->controls,
+                               req, dsdb_next_callback,
+                               req);
+       LDB_REQ_SET_LOCATION(down_req);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       /* go on with the call chain */
+       return ldb_next_request(module, down_req);
+}
+
+static const struct ldb_module_ops ldb_dsdb_flags_ignore_module_ops = {
+       .name   = "dsdb_flags_ignore",
+       .add    = dsdb_flags_ignore_add,
+       .modify = dsdb_flags_ignore_modify,
+};
+
 int ldb_samba_dsdb_module_init(const char *version)
 {
+       int ret;
        LDB_MODULE_CHECK_VERSION(version);
-       return ldb_register_module(&ldb_samba_dsdb_module_ops);
+       ret = ldb_register_module(&ldb_samba_dsdb_module_ops);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+       ret = ldb_register_module(&ldb_dsdb_flags_ignore_module_ops);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+       return LDB_SUCCESS;
 }