diff options
Diffstat (limited to 'source4/lib')
-rw-r--r-- | source4/lib/ldb/include/ldb.h | 22 | ||||
-rw-r--r-- | source4/lib/ldb/ldb.i | 84 | ||||
-rw-r--r-- | source4/lib/ldb/ldb_wrap.c | 158 | ||||
-rw-r--r-- | source4/lib/registry/dir.c | 60 | ||||
-rw-r--r-- | source4/lib/registry/ldb.c | 143 | ||||
-rw-r--r-- | source4/lib/registry/regf.c | 53 | ||||
-rw-r--r-- | source4/lib/registry/tests/hive.c | 37 |
7 files changed, 349 insertions, 208 deletions
diff --git a/source4/lib/ldb/include/ldb.h b/source4/lib/ldb/include/ldb.h index 2e54920c17..2e13a774b9 100644 --- a/source4/lib/ldb/include/ldb.h +++ b/source4/lib/ldb/include/ldb.h @@ -290,7 +290,7 @@ char *ldb_filter_from_tree(TALLOC_CTX *mem_ctx, struct ldb_parse_tree *tree); 2254 (Section 4). This function also escapes any non-printable characters. - \param ctx the memory context to allocate the return string in. + \param mem_ctx the memory context to allocate the return string in. \param val the (potentially) binary data to be encoded \return the encoded data as a null terminated string @@ -886,7 +886,7 @@ int ldb_search_default_callback(struct ldb_context *ldb, void *context, struct l \param attrs the search attributes for the query (pass NULL if none required) \param controls an array of controls \param context the callback function context - \param the callback function to handle the async replies + \param callback the callback function to handle the async replies \return result code (LDB_SUCCESS on success, or a failure code) */ @@ -911,7 +911,7 @@ int ldb_build_search_req(struct ldb_request **ret_req, \param message contains the entry to be added \param controls an array of controls \param context the callback function context - \param the callback function to handle the async replies + \param callback the callback function to handle the async replies \return result code (LDB_SUCCESS on success, or a failure code) */ @@ -933,7 +933,7 @@ int ldb_build_add_req(struct ldb_request **ret_req, \param message contains the entry to be modified \param controls an array of controls \param context the callback function context - \param the callback function to handle the async replies + \param callback the callback function to handle the async replies \return result code (LDB_SUCCESS on success, or a failure code) */ @@ -955,7 +955,7 @@ int ldb_build_mod_req(struct ldb_request **ret_req, \param dn the DN to be deleted \param controls an array of controls \param context the callback function context - \param the callback function to handle the async replies + \param callback the callback function to handle the async replies \return result code (LDB_SUCCESS on success, or a failure code) */ @@ -978,7 +978,7 @@ int ldb_build_del_req(struct ldb_request **ret_req, \param newdn the new DN \param controls an array of controls \param context the callback function context - \param the callback function to handle the async replies + \param callback the callback function to handle the async replies \return result code (LDB_SUCCESS on success, or a failure code) */ @@ -997,7 +997,7 @@ int ldb_build_rename_req(struct ldb_request **ret_req, \param req the request struct where to add the control \param oid the object identifier of the control as string - \param ciritical whether the control should be critical or not + \param critical whether the control should be critical or not \param data a talloc pointer to the control specific data \return result code (LDB_SUCCESS on success, or a failure code) @@ -1137,7 +1137,7 @@ int ldb_extended_default_callback(struct ldb_context *ldb, void *context, struct it needs to be NULL or a valid talloc pointer! talloc_get_type() will be used on it \param controls an array of controls \param context the callback function context - \param the callback function to handle the async replies + \param callback the callback function to handle the async replies \return result code (LDB_SUCCESS on success, or a failure code) */ @@ -1226,6 +1226,7 @@ int ldb_valid_attr_name(const char *s); /* ldif manipulation functions */ + /** Write an LDIF message @@ -1418,8 +1419,8 @@ bool ldb_dn_is_null(struct ldb_dn *dn); This function compares to attribute names. Note that this is a case-insensitive comparison. - \param attr1 the first attribute name to compare - \param attr2 the second attribute name to compare + \param a the first attribute name to compare + \param b the second attribute name to compare \return 0 if the attribute names are the same, or only differ in case; non-zero if there are any differences @@ -1562,6 +1563,7 @@ int ldb_msg_check_string_attribute(const struct ldb_message *msg, This function performs basic sanity / integrity checks on an ldb_message. + \param ldb context in which to perform the checks \param msg the message to check \return LDB_SUCCESS if the message is OK, or a non-zero error code diff --git a/source4/lib/ldb/ldb.i b/source4/lib/ldb/ldb.i index 336100c4f0..da4c52f778 100644 --- a/source4/lib/ldb/ldb.i +++ b/source4/lib/ldb/ldb.i @@ -547,6 +547,43 @@ PyObject *PyExc_LdbError; talloc_free($1); }; +%typemap(in,numinputs=1) ldb_msg *add_msg { + int dict_pos, msg_pos; + PyObject *key, *value; + ldb_msg_element *msgel; + + if (PyDict_Check($input)) { + $1 = ldb_msg_new(NULL); + $1->elements = talloc_zero_array($1, struct ldb_message_element, PyDict_Size($input)); + msg_pos = dict_pos = 0; + while (PyDict_Next($input, &dict_pos, &key, &value)) { + if (!strcmp(PyString_AsString(key), "dn")) { + /* using argp0 (magic SWIG value) here is a hack */ + if (ldb_dn_from_pyobject($1, value, argp1, &$1->dn) != 0) { + SWIG_exception(SWIG_TypeError, "unable to import dn object"); + } + } else { + msgel = ldb_msg_element_from_pyobject($1->elements, value, 0, PyString_AsString(key)); + if (msgel == NULL) { + SWIG_exception(SWIG_TypeError, "unable to import element"); + } + memcpy(&$1->elements[msg_pos], msgel, sizeof(*msgel)); + msg_pos++; + } + } + + if ($1->dn == NULL) { + SWIG_exception(SWIG_TypeError, "no dn set"); + } + + $1->num_elements = msg_pos; + } else { + if (SWIG_ConvertPtr($input, (void **)&$1, SWIGTYPE_p_ldb_message, 0) != 0) { + SWIG_exception(SWIG_TypeError, "unable to convert ldb message"); + } + } +} + /* Top-level ldb operations */ typedef struct ldb_context { %extend { @@ -604,53 +641,6 @@ typedef struct ldb_context { struct ldb_control **parse_control_strings(TALLOC_CTX *mem_ctx, const char * const*control_strings); ldb_error add(ldb_msg *add_msg); - ldb_error add(PyObject *py_msg) - { - ldb_error ret; - int dict_pos, msg_pos; - PyObject *key, *value; - ldb_msg_element *msgel; - ldb_msg *msg = NULL; - - if (PyDict_Check(py_msg)) { - msg = ldb_msg_new(NULL); - msg->elements = talloc_zero_array(msg, struct ldb_message_element, PyDict_Size(py_msg)); - msg_pos = dict_pos = 0; - while (PyDict_Next(py_msg, &dict_pos, &key, &value)) { - if (!strcmp(PyString_AsString(key), "dn")) { - if (ldb_dn_from_pyobject(msg, value, $self, &msg->dn) != 0) { - return LDB_ERR_OTHER; - } - } else { - msgel = ldb_msg_element_from_pyobject(msg->elements, value, 0, PyString_AsString(key)); - if (msgel == NULL) { - SWIG_exception(SWIG_TypeError, "unable to import element"); - return LDB_ERR_OTHER; - } - memcpy(&msg->elements[msg_pos], msgel, sizeof(*msgel)); - msg_pos++; - } - } - - if (msg->dn == NULL) { - SWIG_exception(SWIG_TypeError, "no dn set"); - return LDB_ERR_OTHER; - } - - msg->num_elements = msg_pos; - } else { - if (SWIG_ConvertPtr(py_msg, (void **)&msg, SWIGTYPE_p_ldb_message, 0) != 0) - return LDB_ERR_OTHER; - } - - ret = ldb_add($self, msg); - - talloc_free(msg); - return ret; - - fail: - return LDB_ERR_OTHER; - } ldb_error modify(ldb_msg *message); ldb_dn *get_config_basedn(); ldb_dn *get_root_basedn(); diff --git a/source4/lib/ldb/ldb_wrap.c b/source4/lib/ldb/ldb_wrap.c index 51022e5930..7886778b3a 100644 --- a/source4/lib/ldb/ldb_wrap.c +++ b/source4/lib/ldb/ldb_wrap.c @@ -3113,52 +3113,6 @@ SWIGINTERN ldb_error ldb_search_ex(ldb *self,TALLOC_CTX *mem_ctx,ldb_dn *base,en *OUT = res; return ret; } -SWIGINTERN ldb_error ldb_add__SWIG_1(ldb *self,PyObject *py_msg){ - ldb_error ret; - int dict_pos, msg_pos; - PyObject *key, *value; - ldb_msg_element *msgel; - ldb_msg *msg = NULL; - - if (PyDict_Check(py_msg)) { - msg = ldb_msg_new(NULL); - msg->elements = talloc_zero_array(msg, struct ldb_message_element, PyDict_Size(py_msg)); - msg_pos = dict_pos = 0; - while (PyDict_Next(py_msg, &dict_pos, &key, &value)) { - if (!strcmp(PyString_AsString(key), "dn")) { - if (ldb_dn_from_pyobject(msg, value, self, &msg->dn) != 0) { - return 80; - } - } else { - msgel = ldb_msg_element_from_pyobject(msg->elements, value, 0, PyString_AsString(key)); - if (msgel == NULL) { - SWIG_exception(SWIG_TypeError, "unable to import element"); - return 80; - } - memcpy(&msg->elements[msg_pos], msgel, sizeof(*msgel)); - msg_pos++; - } - } - - if (msg->dn == NULL) { - SWIG_exception(SWIG_TypeError, "no dn set"); - return 80; - } - - msg->num_elements = msg_pos; - } else { - if (SWIG_ConvertPtr(py_msg, (void **)&msg, SWIGTYPE_p_ldb_message, 0) != 0) - return 80; - } - - ret = ldb_add(self, msg); - - talloc_free(msg); - return ret; - - fail: - return 80; - } SWIGINTERN PyObject *ldb_schema_format_value(ldb *self,char const *element_name,PyObject *val){ const struct ldb_schema_attribute *a; struct ldb_val old_val; @@ -4733,27 +4687,61 @@ fail: } -SWIGINTERN PyObject *_wrap_Ldb_add__SWIG_0(PyObject *SWIGUNUSEDPARM(self), int nobjs, PyObject **swig_obj) { +SWIGINTERN PyObject *_wrap_Ldb_add(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { PyObject *resultobj = 0; ldb *arg1 = (ldb *) 0 ; ldb_msg *arg2 = (ldb_msg *) 0 ; ldb_error result; void *argp1 = 0 ; int res1 = 0 ; - void *argp2 = 0 ; - int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "add_msg", NULL + }; - if ((nobjs < 2) || (nobjs > 2)) SWIG_fail; - res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Ldb_add",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); if (!SWIG_IsOK(res1)) { SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_add" "', argument " "1"" of type '" "ldb *""'"); } arg1 = (ldb *)(argp1); - res2 = SWIG_ConvertPtr(swig_obj[1], &argp2,SWIGTYPE_p_ldb_message, 0 | 0 ); - if (!SWIG_IsOK(res2)) { - SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Ldb_add" "', argument " "2"" of type '" "ldb_msg *""'"); + { + int dict_pos, msg_pos; + PyObject *key, *value; + ldb_msg_element *msgel; + + if (PyDict_Check(obj1)) { + arg2 = ldb_msg_new(NULL); + arg2->elements = talloc_zero_array(arg2, struct ldb_message_element, PyDict_Size(obj1)); + msg_pos = dict_pos = 0; + while (PyDict_Next(obj1, &dict_pos, &key, &value)) { + if (!strcmp(PyString_AsString(key), "dn")) { + /* using argp0 (magic SWIG value) here is a hack */ + if (ldb_dn_from_pyobject(arg2, value, argp1, &arg2->dn) != 0) { + SWIG_exception(SWIG_TypeError, "unable to import dn object"); + } + } else { + msgel = ldb_msg_element_from_pyobject(arg2->elements, value, 0, PyString_AsString(key)); + if (msgel == NULL) { + SWIG_exception(SWIG_TypeError, "unable to import element"); + } + memcpy(&arg2->elements[msg_pos], msgel, sizeof(*msgel)); + msg_pos++; + } + } + + if (arg2->dn == NULL) { + SWIG_exception(SWIG_TypeError, "no dn set"); + } + + arg2->num_elements = msg_pos; + } else { + if (SWIG_ConvertPtr(obj1, (void **)&arg2, SWIGTYPE_p_ldb_message, 0) != 0) { + SWIG_exception(SWIG_TypeError, "unable to convert ldb message"); + } + } } - arg2 = (ldb_msg *)(argp2); if (arg1 == NULL) SWIG_exception(SWIG_ValueError, "ldb context must be non-NULL"); @@ -4772,64 +4760,6 @@ fail: } -SWIGINTERN PyObject *_wrap_Ldb_add__SWIG_1(PyObject *SWIGUNUSEDPARM(self), int nobjs, PyObject **swig_obj) { - PyObject *resultobj = 0; - ldb *arg1 = (ldb *) 0 ; - PyObject *arg2 = (PyObject *) 0 ; - ldb_error result; - void *argp1 = 0 ; - int res1 = 0 ; - - if ((nobjs < 2) || (nobjs > 2)) SWIG_fail; - res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Ldb_add" "', argument " "1"" of type '" "ldb *""'"); - } - arg1 = (ldb *)(argp1); - arg2 = swig_obj[1]; - if (arg1 == NULL) - SWIG_exception(SWIG_ValueError, - "ldb context must be non-NULL"); - result = ldb_add__SWIG_1(arg1,arg2); - if (result != 0) { - PyErr_SetObject(PyExc_LdbError, Py_BuildValue((char *)"(i,s)", result, ldb_strerror(result))); - SWIG_fail; - } - resultobj = Py_None; - return resultobj; -fail: - return NULL; -} - - -SWIGINTERN PyObject *_wrap_Ldb_add(PyObject *self, PyObject *args) { - int argc; - PyObject *argv[3]; - - if (!(argc = SWIG_Python_UnpackTuple(args,"Ldb_add",0,2,argv))) SWIG_fail; - --argc; - if (argc == 2) { - int _v = 0; - { - void *vptr = 0; - int res = SWIG_ConvertPtr(argv[1], &vptr, SWIGTYPE_p_ldb_message, 0); - _v = SWIG_CheckState(res); - } - if (!_v) goto check_1; - return _wrap_Ldb_add__SWIG_0(self, argc, argv); - } -check_1: - - if (argc == 2) { - return _wrap_Ldb_add__SWIG_1(self, argc, argv); - } - -fail: - SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Ldb_add'.\n Possible C/C++ prototypes are:\n"" add(ldb *,ldb_msg *)\n"" add(ldb *,PyObject *)\n"); - return NULL; -} - - SWIGINTERN PyObject *_wrap_Ldb_modify(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { PyObject *resultobj = 0; ldb *arg1 = (ldb *) 0 ; @@ -5729,7 +5659,7 @@ static PyMethodDef SwigMethods[] = { { (char *)"Ldb_delete", (PyCFunction) _wrap_Ldb_delete, METH_VARARGS | METH_KEYWORDS, NULL}, { (char *)"Ldb_rename", (PyCFunction) _wrap_Ldb_rename, METH_VARARGS | METH_KEYWORDS, NULL}, { (char *)"Ldb_parse_control_strings", (PyCFunction) _wrap_Ldb_parse_control_strings, METH_VARARGS | METH_KEYWORDS, NULL}, - { (char *)"Ldb_add", _wrap_Ldb_add, METH_VARARGS, NULL}, + { (char *)"Ldb_add", (PyCFunction) _wrap_Ldb_add, METH_VARARGS | METH_KEYWORDS, NULL}, { (char *)"Ldb_modify", (PyCFunction) _wrap_Ldb_modify, METH_VARARGS | METH_KEYWORDS, NULL}, { (char *)"Ldb_get_config_basedn", (PyCFunction)_wrap_Ldb_get_config_basedn, METH_O, NULL}, { (char *)"Ldb_get_root_basedn", (PyCFunction)_wrap_Ldb_get_root_basedn, METH_O, NULL}, diff --git a/source4/lib/registry/dir.c b/source4/lib/registry/dir.c index 27cae8c490..dc3717e886 100644 --- a/source4/lib/registry/dir.c +++ b/source4/lib/registry/dir.c @@ -55,18 +55,66 @@ static WERROR reg_dir_add_key(TALLOC_CTX *mem_ctx, return WERR_GENERAL_FAILURE; } +static WERROR reg_dir_delete_recursive(const char *name) +{ + DIR *d; + struct dirent *e; + WERROR werr; + + d = opendir(name); + if (d == NULL) { + DEBUG(3,("Unable to open '%s': %s\n", name, + strerror(errno))); + return WERR_BADFILE; + } + + while((e = readdir(d))) { + char *path; + struct stat stbuf; + + if (ISDOT(e->d_name) || ISDOTDOT(e->d_name)) + continue; + + path = talloc_asprintf(name, "%s/%s", name, e->d_name); + if (!path) + return WERR_NOMEM; + + stat(path, &stbuf); + + if (!S_ISDIR(stbuf.st_mode)) { + if (unlink(path) < 0) { + talloc_free(path); + closedir(d); + return WERR_GENERAL_FAILURE; + } + } else { + werr = reg_dir_delete_recursive(path); + if (!W_ERROR_IS_OK(werr)) { + talloc_free(path); + closedir(d); + return werr; + } + } + + talloc_free(path); + } + closedir(d); + + if (rmdir(name) == 0) + return WERR_OK; + else if (errno == ENOENT) + return WERR_BADFILE; + else + return WERR_GENERAL_FAILURE; +} + static WERROR reg_dir_del_key(const struct hive_key *k, const char *name) { struct dir_key *dk = talloc_get_type(k, struct dir_key); char *child = talloc_asprintf(NULL, "%s/%s", dk->path, name); WERROR ret; - if (rmdir(child) == 0) - ret = WERR_OK; - else if (errno == ENOENT) - ret = WERR_BADFILE; - else - ret = WERR_GENERAL_FAILURE; + ret = reg_dir_delete_recursive(child); talloc_free(child); diff --git a/source4/lib/registry/ldb.c b/source4/lib/registry/ldb.c index dfd368ea80..a764ca6235 100644 --- a/source4/lib/registry/ldb.c +++ b/source4/lib/registry/ldb.c @@ -442,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; @@ -501,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) diff --git a/source4/lib/registry/regf.c b/source4/lib/registry/regf.c index cf3e564c0e..a192f3be4d 100644 --- a/source4/lib/registry/regf.c +++ b/source4/lib/registry/regf.c @@ -1618,10 +1618,55 @@ static WERROR regf_del_key(const struct hive_key *parent, const char *name) return WERR_BADFILE; } - if (key->nk->subkeys_offset != -1 || - key->nk->values_offset != -1) { - DEBUG(0, ("Key '%s' is not empty.\n", name)); - return WERR_FILE_EXISTS; + if (key->nk->subkeys_offset != -1) { + char *sk_name; + struct hive_key *sk = (struct hive_key *)key; + int i = key->nk->num_subkeys; + while (i--) { + /* Get subkey information. */ + error = regf_get_subkey_by_index(parent_nk, sk, 0, + (const char **)&sk_name, + NULL, NULL); + if (!W_ERROR_IS_OK(error)) { + DEBUG(0, ("Can't retrieve subkey by index.\n")); + return error; + } + + /* Delete subkey. */ + error = regf_del_key(sk, sk_name); + if (!W_ERROR_IS_OK(error)) { + DEBUG(0, ("Can't delete key '%s'.\n", sk_name)); + return error; + } + + talloc_free(sk_name); + } + } + + if (key->nk->values_offset != -1) { + char *val_name; + struct hive_key *sk = (struct hive_key *)key; + DATA_BLOB data; + int i = key->nk->num_values; + while (i--) { + /* Get value information. */ + error = regf_get_value(parent_nk, sk, 0, + (const char **)&val_name, + NULL, &data); + if (!W_ERROR_IS_OK(error)) { + DEBUG(0, ("Can't retrieve value by index.\n")); + return error; + } + + /* Delete value. */ + error = regf_del_value(sk, val_name); + if (!W_ERROR_IS_OK(error)) { + DEBUG(0, ("Can't delete value '%s'.\n", val_name)); + return error; + } + + talloc_free(val_name); + } } /* Delete it from the subkey list. */ diff --git a/source4/lib/registry/tests/hive.c b/source4/lib/registry/tests/hive.c index 1dcb464d80..1e56f125c5 100644 --- a/source4/lib/registry/tests/hive.c +++ b/source4/lib/registry/tests/hive.c @@ -111,6 +111,38 @@ static bool test_add_subkey(struct torture_context *tctx, return true; } +static bool test_del_recursive(struct torture_context *tctx, + const void *test_data) +{ + WERROR error; + struct hive_key *subkey; + struct hive_key *subkey2; + const struct hive_key *root = (const struct hive_key *)test_data; + TALLOC_CTX *mem_ctx = tctx; + uint32_t data = 42; + + /* Create a new key under the root */ + error = hive_key_add_name(mem_ctx, root, "Parent Key", NULL, + NULL, &subkey); + torture_assert_werr_ok(tctx, error, "hive_key_add_name"); + + /* Create a new key under "Parent Key" */ + error = hive_key_add_name(mem_ctx, subkey, "Child Key", NULL, + NULL, &subkey2); + torture_assert_werr_ok(tctx, error, "hive_key_add_name"); + + /* Create a new value under "Child Key" */ + error = hive_key_set_value(subkey2, "Answer Recursive", REG_DWORD, + data_blob_talloc(mem_ctx, &data, sizeof(data))); + torture_assert_werr_ok(tctx, error, "hive_key_set_value"); + + /* Deleting "Parent Key" will also delete "Child Key" and the value. */ + error = hive_key_del(root, "Parent Key"); + torture_assert_werr_ok(tctx, error, "hive_key_del"); + + return true; +} + static bool test_flush_key(struct torture_context *tctx, void *test_data) { struct hive_key *root = (struct hive_key *)test_data; @@ -273,6 +305,11 @@ static void tcase_add_tests(struct torture_tcase *tcase) test_add_subkey); torture_tcase_add_simple_test(tcase, "flush_key", test_flush_key); + /* test_del_recursive() test must run before test_keyinfo_root(). + test_keyinfo_root() checks the number of subkeys, which verifies + the recursive delete worked properly. */ + torture_tcase_add_simple_test_const(tcase, "del_recursive", + test_del_recursive); torture_tcase_add_simple_test_const(tcase, "get_info", test_keyinfo_root); torture_tcase_add_simple_test(tcase, "get_info_nums", |