Merge branch 'v4-0-test' into id10ts-registry
[samba.git] / source4 / lib / registry / ldb.c
index 0c8a55396ee553e15e072f67d3cdb5ab5dab38c3..a764ca6235322885b4d4049f4a0cfb2d66f41d72 100644 (file)
@@ -36,7 +36,9 @@ struct ldb_key_data
        int subkey_count, value_count;
 };
 
-static void reg_ldb_unpack_value(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
+static void reg_ldb_unpack_value(TALLOC_CTX *mem_ctx, 
+                                struct smb_iconv_convenience *iconv_convenience,
+                                struct ldb_message *msg,
                                 const char **name, uint32_t *type,
                                 DATA_BLOB *data)
 {
@@ -57,7 +59,7 @@ static void reg_ldb_unpack_value(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
        {
        case REG_SZ:
        case REG_EXPAND_SZ:
-               data->length = convert_string_talloc(mem_ctx, lp_iconv_convenience(global_loadparm), CH_UTF8, CH_UTF16,
+               data->length = convert_string_talloc(mem_ctx, iconv_convenience, CH_UTF8, CH_UTF16,
                                                     val->data, val->length,
                                                     (void **)&data->data);
                break;
@@ -281,7 +283,7 @@ static WERROR ldb_get_value_by_id(TALLOC_CTX *mem_ctx, struct hive_key *k,
        if (idx >= kd->value_count)
                return WERR_NO_MORE_ITEMS;
 
-       reg_ldb_unpack_value(mem_ctx, kd->values[idx],
+       reg_ldb_unpack_value(mem_ctx, lp_iconv_convenience(global_loadparm), kd->values[idx],
                             name, data_type, data);
 
        return WERR_OK;
@@ -310,7 +312,7 @@ static WERROR ldb_get_value(TALLOC_CTX *mem_ctx, struct hive_key *k,
        if (res->count == 0)
                return WERR_BADFILE;
 
-       reg_ldb_unpack_value(mem_ctx, res->msgs[0], NULL, data_type, data);
+       reg_ldb_unpack_value(mem_ctx, lp_iconv_convenience(global_loadparm), res->msgs[0], NULL, data_type, data);
 
        return WERR_OK;
 }
@@ -440,33 +442,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 +474,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)
@@ -607,7 +698,9 @@ static WERROR ldb_get_key_info(TALLOC_CTX *mem_ctx,
 
                        if (max_valbufsize != NULL) {
                                DATA_BLOB data;
-                               reg_ldb_unpack_value(mem_ctx, kd->values[i], NULL, 
+                               reg_ldb_unpack_value(mem_ctx, 
+                                                    lp_iconv_convenience(global_loadparm),
+                                                    kd->values[i], NULL, 
                                                     NULL, &data);
                                *max_valbufsize = MAX(*max_valbufsize, data.length);
                                talloc_free(data.data);