registry: Implement recursive deletes for ldb-backed registry.
[samba.git] / source / lib / registry / ldb.c
index 0c8a55396ee553e15e072f67d3cdb5ab5dab38c3..31b78d82463aaf9e6eb72112b5e943b6b15778dd 100644 (file)
@@ -440,33 +440,6 @@ static WERROR ldb_add_key(TALLOC_CTX *mem_ctx, const struct hive_key *parent,
        return WERR_OK;
 }
 
-static WERROR ldb_del_key(const struct hive_key *key, const char *name)
-{
-       int ret;
-       struct ldb_key_data *parentkd = talloc_get_type(key, struct ldb_key_data);
-       struct ldb_dn *ldap_path;
-       TALLOC_CTX *mem_ctx = talloc_init("ldb_del_key");
-
-       ldap_path = reg_path_to_ldb(mem_ctx, key, name, NULL);
-
-       ret = ldb_delete(parentkd->ldb, ldap_path);
-
-       talloc_free(mem_ctx);
-
-       if (ret == LDB_ERR_NO_SUCH_OBJECT) {
-               return WERR_BADFILE;
-       } else if (ret != LDB_SUCCESS) {
-               DEBUG(1, ("ldb_del_key: %s\n", ldb_errstring(parentkd->ldb)));
-               return WERR_FOOBAR;
-       }
-
-       /* reset cache */
-       talloc_free(parentkd->subkeys);
-       parentkd->subkeys = NULL;
-
-       return WERR_OK;
-}
-
 static WERROR ldb_del_value (struct hive_key *key, const char *child)
 {
        int ret;
@@ -499,6 +472,122 @@ static WERROR ldb_del_value (struct hive_key *key, const char *child)
        return WERR_OK;
 }
 
+static WERROR ldb_del_key(const struct hive_key *key, const char *name)
+{
+       int i, ret;
+       struct ldb_key_data *parentkd = talloc_get_type(key, struct ldb_key_data);
+       struct ldb_dn *ldap_path;
+       TALLOC_CTX *mem_ctx = talloc_init("ldb_del_key");
+       struct ldb_context *c = parentkd->ldb;
+       struct ldb_result *res_keys;
+       struct ldb_result *res_vals;
+       WERROR werr;
+       struct hive_key *hk;
+
+       /* Verify key exists by opening it */
+       werr = ldb_open_key(mem_ctx, key, name, &hk);
+       if (!W_ERROR_IS_OK(werr)) {
+               talloc_free(mem_ctx);
+               return werr;
+       }
+
+       ldap_path = reg_path_to_ldb(mem_ctx, key, name, NULL);
+       if (!ldap_path) {
+               talloc_free(mem_ctx);
+               return WERR_FOOBAR;
+       }
+
+       /* Search for subkeys */
+       ret = ldb_search(c, ldap_path, LDB_SCOPE_ONELEVEL,
+                        "(key=*)", NULL, &res_keys);
+
+       if (ret != LDB_SUCCESS) {
+               DEBUG(0, ("Error getting subkeys for '%s': %s\n",
+                     ldb_dn_get_linearized(ldap_path), ldb_errstring(c)));
+               talloc_free(mem_ctx);
+               return WERR_FOOBAR;
+       }
+
+       /* Search for values */
+       ret = ldb_search(c, ldap_path, LDB_SCOPE_ONELEVEL,
+                        "(value=*)", NULL, &res_vals);
+
+       if (ret != LDB_SUCCESS) {
+               DEBUG(0, ("Error getting values for '%s': %s\n",
+                     ldb_dn_get_linearized(ldap_path), ldb_errstring(c)));
+               talloc_free(mem_ctx);
+               return WERR_FOOBAR;
+       }
+
+       /* Start an explicit transaction */
+       ret = ldb_transaction_start(c);
+
+       if (ret != LDB_SUCCESS) {
+               DEBUG(0, ("ldb_transaction_start: %s\n", ldb_errstring(c)));
+               talloc_free(mem_ctx);
+               return WERR_FOOBAR;
+       }
+
+       if (res_keys->count || res_vals->count)
+       {
+               /* Delete any subkeys */
+               for (i = 0; i < res_keys->count; i++)
+               {
+                       werr = ldb_del_key(hk, ldb_msg_find_attr_as_string(
+                                                       res_keys->msgs[i],
+                                                       "key", NULL));
+                       if (!W_ERROR_IS_OK(werr)) {
+                               ret = ldb_transaction_cancel(c);
+                               talloc_free(mem_ctx);
+                               return werr;
+                       }
+               }
+
+               /* Delete any values */
+               for (i = 0; i < res_vals->count; i++)
+               {
+                       werr = ldb_del_value(hk, ldb_msg_find_attr_as_string(
+                                                       res_vals->msgs[i],
+                                                       "value", NULL));
+                       if (!W_ERROR_IS_OK(werr)) {
+                               ret = ldb_transaction_cancel(c);
+                               talloc_free(mem_ctx);
+                               return werr;
+                       }
+               }
+       }
+
+       /* Delete the key itself */
+       ret = ldb_delete(c, ldap_path);
+
+       if (ret != LDB_SUCCESS)
+       {
+               DEBUG(1, ("ldb_del_key: %s\n", ldb_errstring(c)));
+               ret = ldb_transaction_cancel(c);
+               talloc_free(mem_ctx);
+               return WERR_FOOBAR;
+       }
+
+       /* Commit the transaction */
+       ret = ldb_transaction_commit(c);
+
+       if (ret != LDB_SUCCESS)
+       {
+               DEBUG(0, ("ldb_transaction_commit: %s\n", ldb_errstring(c)));
+               ret = ldb_transaction_cancel(c);
+               talloc_free(mem_ctx);
+               return WERR_FOOBAR;
+       }
+
+       talloc_free(mem_ctx);
+
+       /* reset cache */
+       talloc_free(parentkd->subkeys);
+       parentkd->subkeys = NULL;
+
+       return WERR_OK;
+}
+
 static WERROR ldb_set_value(struct hive_key *parent,
                            const char *name, uint32_t type,
                            const DATA_BLOB data)