s3:registry: use delete_reg_subkey() in reg_deletekey()
[kai/samba.git] / source3 / registry / reg_api.c
index 25cf101aaf5ff1e83580d6df545caaecc3e6d497..3dc3bae6feba9a45d6eaf37c4f2dd6089f980051 100644 (file)
@@ -94,15 +94,16 @@ static WERROR fill_value_cache(struct registry_key *key)
 
 static WERROR fill_subkey_cache(struct registry_key *key)
 {
+       WERROR werr;
+
        if (key->subkeys != NULL) {
                if (!reg_subkeys_need_update(key->key, key->subkeys)) {
                        return WERR_OK;
                }
        }
 
-       if (!(key->subkeys = TALLOC_ZERO_P(key, REGSUBKEY_CTR))) {
-               return WERR_NOMEM;
-       }
+       werr = regsubkey_ctr_init(key, &(key->subkeys));
+       W_ERROR_NOT_OK_RETURN(werr);
 
        if (fetch_reg_keys(key->key, key->subkeys) == -1) {
                TALLOC_FREE(key->subkeys);
@@ -127,7 +128,7 @@ static WERROR regkey_open_onelevel(TALLOC_CTX *mem_ctx,
        WERROR          result = WERR_OK;
        struct registry_key *regkey;
        REGISTRY_KEY *key;
-       REGSUBKEY_CTR   *subkeys = NULL;
+       struct regsubkey_ctr    *subkeys = NULL;
 
        DEBUG(7,("regkey_open_onelevel: name = [%s]\n", name));
 
@@ -183,9 +184,9 @@ static WERROR regkey_open_onelevel(TALLOC_CTX *mem_ctx,
        
        /* Look up the table of registry I/O operations */
 
-       if ( !(key->hook = reghook_cache_find( key->name )) ) {
-               DEBUG(0,("reg_open_onelevel: Failed to assign "
-                        "REGISTRY_HOOK to [%s]\n", key->name ));
+       if ( !(key->ops = reghook_cache_find( key->name )) ) {
+               DEBUG(0,("reg_open_onelevel: Failed to assign "
+                        "REGISTRY_OPS to [%s]\n", key->name ));
                result = WERR_BADFILE;
                goto done;
        }
@@ -193,8 +194,8 @@ static WERROR regkey_open_onelevel(TALLOC_CTX *mem_ctx,
        /* check if the path really exists; failed is indicated by -1 */
        /* if the subkey count failed, bail out */
 
-       if ( !(subkeys = TALLOC_ZERO_P( key, REGSUBKEY_CTR )) ) {
-               result = WERR_NOMEM;
+       result = regsubkey_ctr_init(key, &subkeys);
+       if (!W_ERROR_IS_OK(result)) {
                goto done;
        }
 
@@ -308,11 +309,13 @@ WERROR reg_enumkey(TALLOC_CTX *mem_ctx, struct registry_key *key,
                return err;
        }
 
-       if (idx >= key->subkeys->num_subkeys) {
+       if (idx >= regsubkey_ctr_numkeys(key->subkeys)) {
                return WERR_NO_MORE_ITEMS;
        }
 
-       if (!(*name = talloc_strdup(mem_ctx, key->subkeys->subkeys[idx]))) {
+       if (!(*name = talloc_strdup(mem_ctx,
+                       regsubkey_ctr_specific_key(key->subkeys, idx))))
+       {
                return WERR_NOMEM;
        }
 
@@ -406,11 +409,12 @@ WERROR reg_queryinfokey(struct registry_key *key, uint32_t *num_subkeys,
        }
 
        max_len = 0;
-       for (i=0; i<key->subkeys->num_subkeys; i++) {
-               max_len = MAX(max_len, strlen(key->subkeys->subkeys[i]));
+       for (i=0; i< regsubkey_ctr_numkeys(key->subkeys); i++) {
+               max_len = MAX(max_len,
+                       strlen(regsubkey_ctr_specific_key(key->subkeys, i)));
        }
 
-       *num_subkeys = key->subkeys->num_subkeys;
+       *num_subkeys = regsubkey_ctr_numkeys(key->subkeys);
        *max_subkeylen = max_len;
        *max_subkeysize = 0;    /* Class length? */
 
@@ -436,7 +440,7 @@ WERROR reg_queryinfokey(struct registry_key *key, uint32_t *num_subkeys,
                return err;
        }
 
-       *secdescsize = ndr_size_security_descriptor(secdesc, 0);
+       *secdescsize = ndr_size_security_descriptor(secdesc, NULL, 0);
        TALLOC_FREE(mem_ctx);
 
        *last_changed_time = 0;
@@ -520,14 +524,8 @@ WERROR reg_createkey(TALLOC_CTX *ctx, struct registry_key *parent,
        err = fill_subkey_cache(create_parent);
        if (!W_ERROR_IS_OK(err)) goto done;
 
-       err = regsubkey_ctr_addkey(create_parent->subkeys, path);
-       if (!W_ERROR_IS_OK(err)) goto done;
-
-       if (!store_reg_keys(create_parent->key, create_parent->subkeys)) {
-               TALLOC_FREE(create_parent->subkeys);
-               err = WERR_REG_IO_FAILURE;
-               goto done;
-       }
+       err = create_reg_subkey(key->key, path);
+       W_ERROR_NOT_OK_GOTO_DONE(err);
 
        /*
         * Now open the newly created key
@@ -546,40 +544,36 @@ WERROR reg_createkey(TALLOC_CTX *ctx, struct registry_key *parent,
 WERROR reg_deletekey(struct registry_key *parent, const char *path)
 {
        WERROR err;
-       TALLOC_CTX *mem_ctx;
        char *name, *end;
-       int num_subkeys;
        struct registry_key *tmp_key, *key;
+       TALLOC_CTX *mem_ctx = talloc_stackframe();
 
-       if (!(mem_ctx = talloc_init("reg_createkey"))) return WERR_NOMEM;
-
-       if (!(name = talloc_strdup(mem_ctx, path))) {
+       name = talloc_strdup(mem_ctx, path);
+       if (name == NULL) {
                err = WERR_NOMEM;
-               goto error;
+               goto done;
        }
 
        /* check if the key has subkeys */
        err = reg_openkey(mem_ctx, parent, name, REG_KEY_READ, &key);
-       if (!W_ERROR_IS_OK(err)) {
-               goto error;
-       }
-       if (!W_ERROR_IS_OK(err = fill_subkey_cache(key))) {
-               goto error;
-       }
-       if (key->subkeys->num_subkeys > 0) {
+       W_ERROR_NOT_OK_GOTO_DONE(err);
+
+       err = fill_subkey_cache(key);
+       W_ERROR_NOT_OK_GOTO_DONE(err);
+
+       if (regsubkey_ctr_numkeys(key->subkeys) > 0) {
                err = WERR_ACCESS_DENIED;
-               goto error;
+               goto done;
        }
 
        /* no subkeys - proceed with delete */
-       if ((end = strrchr(name, '\\')) != NULL) {
+       end = strrchr(name, '\\');
+       if (end != NULL) {
                *end = '\0';
 
                err = reg_openkey(mem_ctx, parent, name,
                                  SEC_RIGHTS_CREATE_SUBKEY, &tmp_key);
-               if (!W_ERROR_IS_OK(err)) {
-                       goto error;
-               }
+               W_ERROR_NOT_OK_GOTO_DONE(err);
 
                parent = tmp_key;
                name = end+1;
@@ -587,31 +581,12 @@ WERROR reg_deletekey(struct registry_key *parent, const char *path)
 
        if (name[0] == '\0') {
                err = WERR_INVALID_PARAM;
-               goto error;
-       }
-
-       if (!W_ERROR_IS_OK(err = fill_subkey_cache(parent))) {
-               goto error;
-       }
-
-       num_subkeys = parent->subkeys->num_subkeys;
-
-       if (regsubkey_ctr_delkey(parent->subkeys, name) == num_subkeys) {
-               err = WERR_BADFILE;
-               goto error;
-       }
-
-       if (!store_reg_keys(parent->key, parent->subkeys)) {
-               TALLOC_FREE(parent->subkeys);
-               err = WERR_REG_IO_FAILURE;
-               goto error;
+               goto done;
        }
 
-       regkey_set_secdesc(key->key, NULL);
-
-       err = WERR_OK;
+       err = delete_reg_subkey(parent->key, name);
 
- error:
+done:
        TALLOC_FREE(mem_ctx);
        return err;
 }
@@ -653,6 +628,19 @@ WERROR reg_setvalue(struct registry_key *key, const char *name,
        return WERR_OK;
 }
 
+static WERROR reg_value_exists(struct registry_key *key, const char *name)
+{
+       int i;
+
+       for (i=0; i<key->values->num_values; i++) {
+               if (strequal(key->values->values[i]->valuename, name)) {
+                       return WERR_OK;
+               }
+       }
+
+       return WERR_BADFILE;
+}
+
 WERROR reg_deletevalue(struct registry_key *key, const char *name)
 {
        WERROR err;
@@ -665,6 +653,11 @@ WERROR reg_deletevalue(struct registry_key *key, const char *name)
                return err;
        }
 
+       err = reg_value_exists(key, name);
+       if (!W_ERROR_IS_OK(err)) {
+               return err;
+       }
+
        regval_ctr_delvalue(key->values, name);
 
        if (!store_reg_values(key->key, key->values)) {
@@ -708,16 +701,16 @@ static WERROR reg_load_tree(REGF_FILE *regfile, const char *topkeypath,
        REGF_NK_REC *subkey;
        REGISTRY_KEY registry_key;
        REGVAL_CTR *values;
-       REGSUBKEY_CTR *subkeys;
+       struct regsubkey_ctr *subkeys;
        int i;
        char *path = NULL;
        WERROR result = WERR_OK;
 
        /* initialize the REGISTRY_KEY structure */
 
-       registry_key.hook = reghook_cache_find(topkeypath);
-       if (!registry_key.hook) {
-               DEBUG(0, ("reg_load_tree: Failed to assigned a REGISTRY_HOOK "
+       registry_key.ops = reghook_cache_find(topkeypath);
+       if (!registry_key.ops) {
+               DEBUG(0, ("reg_load_tree: Failed to assign  REGISTRY_OPS "
                          "to [%s]\n", topkeypath));
                return WERR_BADFILE;
        }
@@ -730,10 +723,8 @@ static WERROR reg_load_tree(REGF_FILE *regfile, const char *topkeypath,
 
        /* now start parsing the values and subkeys */
 
-       subkeys = TALLOC_ZERO_P(regfile->mem_ctx, REGSUBKEY_CTR);
-       if (subkeys == NULL) {
-               return WERR_NOMEM;
-       }
+       result = regsubkey_ctr_init(regfile->mem_ctx, &subkeys);
+       W_ERROR_NOT_OK_RETURN(result);
 
        values = TALLOC_ZERO_P(subkeys, REGVAL_CTR);
        if (values == NULL) {
@@ -749,11 +740,15 @@ static WERROR reg_load_tree(REGF_FILE *regfile, const char *topkeypath,
                                    (key->values[i].data_size & ~VK_DATA_IN_OFFSET));
        }
 
-       /* copy subkeys into the REGSUBKEY_CTR */
+       /* copy subkeys into the struct regsubkey_ctr */
 
        key->subkey_index = 0;
        while ((subkey = regfio_fetch_subkey( regfile, key ))) {
-               regsubkey_ctr_addkey(subkeys, subkey->keyname);
+               result = regsubkey_ctr_addkey(subkeys, subkey->keyname);
+               if (!W_ERROR_IS_OK(result)) {
+                       TALLOC_FREE(subkeys);
+                       return result;
+               }
        }
 
        /* write this key and values out */
@@ -839,7 +834,7 @@ static WERROR reg_write_tree(REGF_FILE *regfile, const char *keypath,
 {
        REGF_NK_REC *key;
        REGVAL_CTR *values;
-       REGSUBKEY_CTR *subkeys;
+       struct regsubkey_ctr *subkeys;
        int i, num_subkeys;
        char *key_tmp = NULL;
        char *keyname, *parentpath;
@@ -880,17 +875,15 @@ static WERROR reg_write_tree(REGF_FILE *regfile, const char *keypath,
                return WERR_NOMEM;
        }
 
-       registry_key.hook = reghook_cache_find(registry_key.name);
-       if (registry_key.hook == NULL) {
+       registry_key.ops = reghook_cache_find(registry_key.name);
+       if (registry_key.ops == NULL) {
                return WERR_BADFILE;
        }
 
        /* lookup the values and subkeys */
 
-       subkeys = TALLOC_ZERO_P(regfile->mem_ctx, REGSUBKEY_CTR);
-       if (subkeys == NULL) {
-               return WERR_NOMEM;
-       }
+       result = regsubkey_ctr_init(regfile->mem_ctx, &subkeys);
+       W_ERROR_NOT_OK_RETURN(result);
 
        values = TALLOC_ZERO_P(subkeys, REGVAL_CTR);
        if (values == NULL) {
@@ -939,54 +932,6 @@ done:
        return result;
 }
 
-static const struct generic_mapping reg_generic_map =
-       { REG_KEY_READ, REG_KEY_WRITE, REG_KEY_EXECUTE, REG_KEY_ALL };
-
-static WERROR make_default_reg_sd(TALLOC_CTX *ctx, SEC_DESC **psd)
-{
-       DOM_SID adm_sid, owner_sid;
-       SEC_ACE ace[2];         /* at most 2 entries */
-       SEC_ACCESS mask;
-       SEC_ACL *psa = NULL;
-       size_t sd_size;
-
-       /* set the owner to BUILTIN\Administrator */
-
-       sid_copy(&owner_sid, &global_sid_Builtin);
-       sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN );
-       
-
-       /* basic access for Everyone */
-
-       init_sec_access(&mask, reg_generic_map.generic_execute
-                              | reg_generic_map.generic_read);
-       init_sec_ace(&ace[0], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED,
-                    mask, 0);
-
-       /* add Full Access 'BUILTIN\Administrators' */
-
-       init_sec_access(&mask, reg_generic_map.generic_all);
-       sid_copy(&adm_sid, &global_sid_Builtin);
-       sid_append_rid(&adm_sid, BUILTIN_ALIAS_RID_ADMINS);
-       init_sec_ace(&ace[1], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
-
-       /* create the security descriptor */
-
-       psa = make_sec_acl(ctx, NT4_ACL_REVISION, 2, ace);
-       if (psa == NULL) {
-               return WERR_NOMEM;
-       }
-
-       *psd = make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1,
-                            SEC_DESC_SELF_RELATIVE, &owner_sid, NULL,
-                            NULL, psa, &sd_size);
-       if (*psd == NULL) {
-               return WERR_NOMEM;
-       }
-
-       return WERR_OK;
-}
-
 static WERROR backup_registry_key(REGISTRY_KEY *krecord, const char *fname)
 {
        REGF_FILE *regfile;
@@ -1143,7 +1088,7 @@ static WERROR reg_deletekey_recursive_internal(TALLOC_CTX *ctx,
        if (!W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, werr)) {
                DEBUG(1, ("reg_deletekey_recursive_internal: "
                          "Error enumerating subkeys: %s\n",
-                         dos_errstr(werr)));
+                         win_errstr(werr)));
                goto done;
        }
 
@@ -1159,18 +1104,57 @@ done:
        return werr;
 }
 
+static WERROR reg_deletekey_recursive_trans(TALLOC_CTX *ctx,
+                                           struct registry_key *parent,
+                                           const char *path,
+                                           bool del_key)
+{
+       WERROR werr;
+
+       werr = regdb_transaction_start();
+       if (!W_ERROR_IS_OK(werr)) {
+               DEBUG(0, ("reg_deletekey_recursive_trans: "
+                         "error starting transaction: %s\n",
+                         win_errstr(werr)));
+               return werr;
+       }
+
+       werr = reg_deletekey_recursive_internal(ctx, parent, path, del_key);
+
+       if (!W_ERROR_IS_OK(werr)) {
+               DEBUG(1, (__location__ " failed to delete key '%s' from key "
+                         "'%s': %s\n", path, parent->key->name,
+                         win_errstr(werr)));
+               werr = regdb_transaction_cancel();
+               if (!W_ERROR_IS_OK(werr)) {
+                       DEBUG(0, ("reg_deletekey_recursive_trans: "
+                                 "error cancelling transaction: %s\n",
+                                 win_errstr(werr)));
+               }
+       } else {
+               werr = regdb_transaction_commit();
+               if (!W_ERROR_IS_OK(werr)) {
+                       DEBUG(0, ("reg_deletekey_recursive_trans: "
+                                 "error committing transaction: %s\n",
+                                 win_errstr(werr)));
+               }
+       }
+
+       return werr;
+}
+
 WERROR reg_deletekey_recursive(TALLOC_CTX *ctx,
                               struct registry_key *parent,
                               const char *path)
 {
-       return reg_deletekey_recursive_internal(ctx, parent, path, true);
+       return reg_deletekey_recursive_trans(ctx, parent, path, true);
 }
 
 WERROR reg_deletesubkeys_recursive(TALLOC_CTX *ctx,
                                   struct registry_key *parent,
                                   const char *path)
 {
-       return reg_deletekey_recursive_internal(ctx, parent, path, false);
+       return reg_deletekey_recursive_trans(ctx, parent, path, false);
 }
 
 #if 0