diff options
26 files changed, 906 insertions, 411 deletions
diff --git a/source4/Makefile b/source4/Makefile index 65f8c2de29..859d168a6f 100644 --- a/source4/Makefile +++ b/source4/Makefile @@ -22,6 +22,13 @@ HOSTLD_FLAGS = $(LDFLAGS) $(SYS_LDFLAGS) $(srcdir)/version.h: $(srcdir)/VERSION @$(SHELL) script/mkversion.sh VERSION $(srcdir)/version.h $(srcdir)/ +.DEFAULT_GOAL := all + +ifneq ($(automatic_deps),yes) +ALL_PREDEP = proto +.NOTPARALLEL: +endif + regen_version:: @$(SHELL) script/mkversion.sh VERSION $(srcdir)/version.h $(srcdir)/ diff --git a/source4/build/smb_build/makefile.pm b/source4/build/smb_build/makefile.pm index 9aa4e409bd..b889a84718 100644 --- a/source4/build/smb_build/makefile.pm +++ b/source4/build/smb_build/makefile.pm @@ -350,8 +350,7 @@ sub CFlags($$) my $cflags = join(' ', @cflags); - my $ext = "o"; - $self->output("\$($key->{NAME}_OBJ_LIST) \$(patsubst %.ho,%.d,\$($key->{NAME}_OBJ_LIST:.o=.d)): CFLAGS+=$cflags\n"); + $self->output("\$(patsubst %.ho,%.d,\$(key->{NAME}_OBJ_LIST:.o=.d)) \$($key->{NAME}_OBJ_LIST): CFLAGS+= $cflags\n"); } 1; diff --git a/source4/cluster/ctdb/opendb_ctdb.c b/source4/cluster/ctdb/opendb_ctdb.c index 3d67162d6d..e84f2364d4 100644 --- a/source4/cluster/ctdb/opendb_ctdb.c +++ b/source4/cluster/ctdb/opendb_ctdb.c @@ -543,6 +543,25 @@ static NTSTATUS odb_ctdb_rename(struct odb_lock *lck, const char *path) } /* + get the path of an open file +*/ +static NTSTATUS odb_ctdb_get_path(struct odb_lock *lck, const char **path) +{ + struct opendb_file file; + NTSTATUS status; + + *path = NULL; + + status = odb_pull_record(lck, &file); + /* we don't ignore NT_STATUS_OBJECT_NAME_NOT_FOUND here */ + NT_STATUS_NOT_OK_RETURN(status); + + *path = file.path; + + return NT_STATUS_OK; +} + +/* update delete on close flag on an open file */ static NTSTATUS odb_ctdb_set_delete_on_close(struct odb_lock *lck, bool del_on_close) @@ -653,6 +672,7 @@ static const struct opendb_ops opendb_ctdb_ops = { .odb_close_file = odb_ctdb_close_file, .odb_remove_pending = odb_ctdb_remove_pending, .odb_rename = odb_ctdb_rename, + .odb_get_path = odb_ctdb_get_path, .odb_set_delete_on_close = odb_ctdb_set_delete_on_close, .odb_get_delete_on_close = odb_ctdb_get_delete_on_close, .odb_can_open = odb_ctdb_can_open, 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", diff --git a/source4/librpc/config.mk b/source4/librpc/config.mk index 8a5e1478f6..7abc693960 100644 --- a/source4/librpc/config.mk +++ b/source4/librpc/config.mk @@ -298,8 +298,8 @@ include librpc/idl-deps librpc/gen_ndr/tables.c: $(IDL_NDR_PARSE_H_FILES) @echo Generating $@ - @$(PERL) $(srcdir)/librpc/tables.pl --output=$@ $(IDL_NDR_PARSE_H_FILES) > librpc/gen_ndr/tables.x - mv librpc/gen_ndr/tables.x $@ + @$(PERL) $(srcdir)/librpc/tables.pl --output=$@ $^ > librpc/gen_ndr/tables.x + @mv librpc/gen_ndr/tables.x $@ [SUBSYSTEM::NDR_TABLE] OBJ_FILES = ndr/ndr_table.o gen_ndr/tables.o diff --git a/source4/ntvfs/common/opendb.c b/source4/ntvfs/common/opendb.c index d8cb67686b..6c1a9c070a 100644 --- a/source4/ntvfs/common/opendb.c +++ b/source4/ntvfs/common/opendb.c @@ -143,6 +143,14 @@ _PUBLIC_ NTSTATUS odb_rename(struct odb_lock *lck, const char *path) } /* + get back the path of an open file +*/ +_PUBLIC_ NTSTATUS odb_get_path(struct odb_lock *lck, const char **path) +{ + return ops->odb_get_path(lck, path); +} + +/* update delete on close flag on an open file */ _PUBLIC_ NTSTATUS odb_set_delete_on_close(struct odb_lock *lck, bool del_on_close) diff --git a/source4/ntvfs/common/opendb.h b/source4/ntvfs/common/opendb.h index 33f2e1c88d..69a7f718ba 100644 --- a/source4/ntvfs/common/opendb.h +++ b/source4/ntvfs/common/opendb.h @@ -36,6 +36,7 @@ struct opendb_ops { const char **delete_path); NTSTATUS (*odb_remove_pending)(struct odb_lock *lck, void *private); NTSTATUS (*odb_rename)(struct odb_lock *lck, const char *path); + NTSTATUS (*odb_get_path)(struct odb_lock *lck, const char **path); NTSTATUS (*odb_set_delete_on_close)(struct odb_lock *lck, bool del_on_close); NTSTATUS (*odb_get_delete_on_close)(struct odb_context *odb, DATA_BLOB *key, bool *del_on_close); diff --git a/source4/ntvfs/common/opendb_tdb.c b/source4/ntvfs/common/opendb_tdb.c index 37c1c0850b..47b35f594c 100644 --- a/source4/ntvfs/common/opendb_tdb.c +++ b/source4/ntvfs/common/opendb_tdb.c @@ -714,6 +714,25 @@ static NTSTATUS odb_tdb_rename(struct odb_lock *lck, const char *path) } /* + get the path of an open file +*/ +static NTSTATUS odb_tdb_get_path(struct odb_lock *lck, const char **path) +{ + struct opendb_file file; + NTSTATUS status; + + *path = NULL; + + status = odb_pull_record(lck, &file); + /* we don't ignore NT_STATUS_OBJECT_NAME_NOT_FOUND here */ + NT_STATUS_NOT_OK_RETURN(status); + + *path = file.path; + + return NT_STATUS_OK; +} + +/* update delete on close flag on an open file */ static NTSTATUS odb_tdb_set_delete_on_close(struct odb_lock *lck, bool del_on_close) @@ -802,6 +821,7 @@ static const struct opendb_ops opendb_tdb_ops = { .odb_close_file = odb_tdb_close_file, .odb_remove_pending = odb_tdb_remove_pending, .odb_rename = odb_tdb_rename, + .odb_get_path = odb_tdb_get_path, .odb_set_delete_on_close = odb_tdb_set_delete_on_close, .odb_get_delete_on_close = odb_tdb_get_delete_on_close, .odb_can_open = odb_tdb_can_open, diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c index 740a0a9d13..adf4c1ac18 100644 --- a/source4/ntvfs/posix/pvfs_open.c +++ b/source4/ntvfs/posix/pvfs_open.c @@ -144,8 +144,8 @@ static NTSTATUS pvfs_open_setup_eas_acl(struct pvfs_state *pvfs, form the lock context used for opendb locking. Note that we must zero here to take account of possible padding on some architectures */ -static NTSTATUS pvfs_locking_key(struct pvfs_filename *name, - TALLOC_CTX *mem_ctx, DATA_BLOB *key) +NTSTATUS pvfs_locking_key(struct pvfs_filename *name, + TALLOC_CTX *mem_ctx, DATA_BLOB *key) { struct { dev_t device; diff --git a/source4/ntvfs/posix/pvfs_qfileinfo.c b/source4/ntvfs/posix/pvfs_qfileinfo.c index 6ed729541f..6bc21e5e3e 100644 --- a/source4/ntvfs/posix/pvfs_qfileinfo.c +++ b/source4/ntvfs/posix/pvfs_qfileinfo.c @@ -368,7 +368,7 @@ NTSTATUS pvfs_qfileinfo(struct ntvfs_module_context *ntvfs, } /* update the file information */ - status = pvfs_resolve_name_fd(pvfs, h->fd, h->name); + status = pvfs_resolve_name_handle(pvfs, h); if (!NT_STATUS_IS_OK(status)) { return status; } diff --git a/source4/ntvfs/posix/pvfs_rename.c b/source4/ntvfs/posix/pvfs_rename.c index 185e35f800..29b2d03005 100644 --- a/source4/ntvfs/posix/pvfs_rename.c +++ b/source4/ntvfs/posix/pvfs_rename.c @@ -28,16 +28,22 @@ /* do a file rename, and send any notify triggers */ -NTSTATUS pvfs_do_rename(struct pvfs_state *pvfs, const struct pvfs_filename *name1, +NTSTATUS pvfs_do_rename(struct pvfs_state *pvfs, + struct odb_lock *lck, + const struct pvfs_filename *name1, const char *name2) { const char *r1, *r2; uint32_t mask; + NTSTATUS status; if (rename(name1->full_name, name2) == -1) { return pvfs_map_errno(pvfs, errno); } + status = odb_rename(lck, name2); + NT_STATUS_NOT_OK_RETURN(status); + if (name1->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) { mask = FILE_NOTIFY_CHANGE_DIR_NAME; } else { @@ -315,11 +321,7 @@ static NTSTATUS pvfs_rename_one(struct pvfs_state *pvfs, return NT_STATUS_NO_MEMORY; } - status = pvfs_do_rename(pvfs, name1, fname2); - - if (NT_STATUS_IS_OK(status)) { - status = odb_rename(lck, fname2); - } + status = pvfs_do_rename(pvfs, lck, name1, fname2); failed: talloc_free(mem_ctx); @@ -448,9 +450,9 @@ static NTSTATUS pvfs_rename_mv(struct ntvfs_module_context *ntvfs, return status; } - status = pvfs_do_rename(pvfs, name1, name2->full_name); - if (NT_STATUS_IS_OK(status)) { - status = odb_rename(lck, name2->full_name); + status = pvfs_do_rename(pvfs, lck, name1, name2->full_name); + if (!NT_STATUS_IS_OK(status)) { + return status; } return NT_STATUS_OK; @@ -532,10 +534,7 @@ static NTSTATUS pvfs_rename_nt(struct ntvfs_module_context *ntvfs, case RENAME_FLAG_RENAME: status = pvfs_access_check_parent(pvfs, req, name2, SEC_DIR_ADD_FILE); NT_STATUS_NOT_OK_RETURN(status); - status = pvfs_do_rename(pvfs, name1, name2->full_name); - if (NT_STATUS_IS_OK(status)) { - status = odb_rename(lck, name2->full_name); - } + status = pvfs_do_rename(pvfs, lck, name1, name2->full_name); NT_STATUS_NOT_OK_RETURN(status); break; diff --git a/source4/ntvfs/posix/pvfs_resolve.c b/source4/ntvfs/posix/pvfs_resolve.c index 2bfc47beff..325bc74f8f 100644 --- a/source4/ntvfs/posix/pvfs_resolve.c +++ b/source4/ntvfs/posix/pvfs_resolve.c @@ -265,8 +265,15 @@ static NTSTATUS pvfs_unix_path(struct pvfs_state *pvfs, const char *cifs_name, of a name */ return NT_STATUS_ILLEGAL_CHARACTER; } - if (p > p_start && p[1] == 0) { - *p = 0; + if (p > p_start && (p[1] == '\\' || p[1] == '\0')) { + /* see if it is definately a "\\" or + * a trailing "\". If it is then fail here, + * and let the next layer up try again after + * pvfs_reduce_name() if it wants to. This is + * much more efficient on average than always + * scanning for these separately + */ + return NT_STATUS_OBJECT_PATH_SYNTAX_BAD; } else { *p = '/'; } @@ -399,7 +406,7 @@ static NTSTATUS pvfs_reduce_name(TALLOC_CTX *mem_ctx, if (ISDOTDOT(components[i])) { if (i < 1) return NT_STATUS_OBJECT_PATH_SYNTAX_BAD; memmove(&components[i-1], &components[i+1], - sizeof(char *)*(num_components-(i+1))); + sizeof(char *)*(num_components-i)); i -= 2; continue; } @@ -616,6 +623,86 @@ NTSTATUS pvfs_resolve_name_fd(struct pvfs_state *pvfs, int fd, return pvfs_fill_dos_info(pvfs, name, fd); } +/* + fill in the pvfs_filename info for an open file, given the current + info for a (possibly) non-open file. This is used by places that need + to update the pvfs_filename stat information, and the path + after a possible rename on a different handle. +*/ +NTSTATUS pvfs_resolve_name_handle(struct pvfs_state *pvfs, + struct pvfs_file_handle *h) +{ + NTSTATUS status; + + if (h->have_opendb_entry) { + struct odb_lock *lck; + const char *name = NULL; + + lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key); + if (lck == NULL) { + DEBUG(0,("%s: failed to lock file '%s' in opendb\n", + __FUNCTION__, h->name->full_name)); + /* we were supposed to do a blocking lock, so something + is badly wrong! */ + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + status = odb_get_path(lck, &name); + if (NT_STATUS_IS_OK(status)) { + /* + * This relies an the fact that + * renames of open files are only + * allowed by setpathinfo() and setfileinfo() + * and there're only renames within the same + * directory supported + */ + if (strcmp(h->name->full_name, name) != 0) { + const char *orig_dir; + const char *new_file; + const char *new_orig; + char *delim; + + delim = strrchr(name, '/'); + if (!delim) { + talloc_free(lck); + return NT_STATUS_INTERNAL_ERROR; + } + + new_file = delim + 1; + delim = strrchr(h->name->original_name, '\\'); + if (delim) { + delim[0] = '\0'; + orig_dir = h->name->original_name; + new_orig = talloc_asprintf(h->name, "%s\\%s", + orig_dir, new_file); + if (!new_orig) { + talloc_free(lck); + return NT_STATUS_NO_MEMORY; + } + } else { + new_orig = talloc_strdup(h->name, new_file); + if (!new_orig) { + talloc_free(lck); + return NT_STATUS_NO_MEMORY; + } + } + + talloc_free(h->name->original_name); + talloc_free(h->name->full_name); + h->name->full_name = talloc_steal(h->name, name); + h->name->original_name = new_orig; + } + } + + talloc_free(lck); + } + + status = pvfs_resolve_name_fd(pvfs, h->fd, h->name); + NT_STATUS_NOT_OK_RETURN(status); + + return NT_STATUS_OK; +} + /* resolve the parent of a given name diff --git a/source4/ntvfs/posix/pvfs_setfileinfo.c b/source4/ntvfs/posix/pvfs_setfileinfo.c index da1e31e639..ad47fe90c9 100644 --- a/source4/ntvfs/posix/pvfs_setfileinfo.c +++ b/source4/ntvfs/posix/pvfs_setfileinfo.c @@ -82,11 +82,13 @@ static uint32_t pvfs_setfileinfo_access(union smb_setfileinfo *info) static NTSTATUS pvfs_setfileinfo_rename(struct pvfs_state *pvfs, struct ntvfs_request *req, struct pvfs_filename *name, + DATA_BLOB *odb_locking_key, union smb_setfileinfo *info) { NTSTATUS status; struct pvfs_filename *name2; char *new_name, *p; + struct odb_lock *lck = NULL; /* renames are only allowed within a directory */ if (strchr_m(info->rename_information.in.new_name, '\\') && @@ -94,11 +96,6 @@ static NTSTATUS pvfs_setfileinfo_rename(struct pvfs_state *pvfs, return NT_STATUS_NOT_SUPPORTED; } - if (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) { - /* don't allow this for now */ - return NT_STATUS_FILE_IS_A_DIRECTORY; - } - /* don't allow stream renames for now */ if (name->stream_name) { return NT_STATUS_INVALID_PARAMETER; @@ -168,7 +165,15 @@ static NTSTATUS pvfs_setfileinfo_rename(struct pvfs_state *pvfs, return status; } - status = pvfs_do_rename(pvfs, name, name2->full_name); + lck = odb_lock(req, pvfs->odb_context, odb_locking_key); + if (lck == NULL) { + DEBUG(0,("Unable to lock opendb for can_stat\n")); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + status = pvfs_do_rename(pvfs, lck, name, name2->full_name); + talloc_free(lck); + NT_STATUS_NOT_OK_RETURN(status); if (NT_STATUS_IS_OK(status)) { name->full_name = talloc_steal(name, name2->full_name); name->original_name = talloc_steal(name, name2->original_name); @@ -289,7 +294,7 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs, } /* update the file information */ - status = pvfs_resolve_name_fd(pvfs, h->fd, h->name); + status = pvfs_resolve_name_handle(pvfs, h); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -391,7 +396,8 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs, case RAW_SFILEINFO_RENAME_INFORMATION: case RAW_SFILEINFO_RENAME_INFORMATION_SMB2: - return pvfs_setfileinfo_rename(pvfs, req, h->name, + return pvfs_setfileinfo_rename(pvfs, req, h->name, + &h->odb_locking_key, info); case RAW_SFILEINFO_SEC_DESC: @@ -565,6 +571,7 @@ NTSTATUS pvfs_setpathinfo(struct ntvfs_module_context *ntvfs, uint32_t access_needed; uint32_t change_mask = 0; struct odb_lock *lck = NULL; + DATA_BLOB odb_locking_key; /* resolve the cifs name to a posix name */ status = pvfs_resolve_name(pvfs, req, info->generic.in.file.path, @@ -696,8 +703,12 @@ NTSTATUS pvfs_setpathinfo(struct ntvfs_module_context *ntvfs, case RAW_SFILEINFO_RENAME_INFORMATION: case RAW_SFILEINFO_RENAME_INFORMATION_SMB2: - return pvfs_setfileinfo_rename(pvfs, req, name, - info); + status = pvfs_locking_key(name, name, &odb_locking_key); + NT_STATUS_NOT_OK_RETURN(status); + status = pvfs_setfileinfo_rename(pvfs, req, name, + &odb_locking_key, info); + NT_STATUS_NOT_OK_RETURN(status); + return NT_STATUS_OK; case RAW_SFILEINFO_DISPOSITION_INFO: case RAW_SFILEINFO_DISPOSITION_INFORMATION: diff --git a/source4/samba4-knownfail b/source4/samba4-knownfail index aaa11774ae..66565ca6fc 100644 --- a/source4/samba4-knownfail +++ b/source4/samba4-knownfail @@ -3,9 +3,7 @@ local.iconv.*.next_codepoint() base.delaywrite.finfo update on close base.delete.*.deltest20a base.delete.*.deltest20b -raw.oplock.*BATCH19 -raw.oplock.*BATCH20 -rpc.winreg +rpc.winreg.*security local.registry.*.security # Not implemented yet rpc.wkssvc rpc.handles.*.lsarpc-shared @@ -35,5 +33,4 @@ rpc.netlogon.*.GetTrustPasswords base.charset.*.Testing partial surrogate .*net.api.delshare.* # DelShare isn't implemented yet rap.*netservergetinfo -samba4.blackbox.provision.py.reprovision # Fails with entry already exists local.torture.provision diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index b041165800..8d5f4250c9 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -127,7 +127,7 @@ class Ldb(ldb.Ldb): try: self.delete(msg.dn) except ldb.LdbError, (LDB_ERR_NO_SUCH_OBJECT, _): - # Ignor eno such object errors + # Ignore no such object errors pass res = self.search(basedn, ldb.SCOPE_SUBTREE, "(&(|(objectclass=*)(distinguishedName=*))(!(distinguishedName=@BASEINFO)))", ["distinguishedName"]) @@ -151,7 +151,14 @@ class Ldb(ldb.Ldb): previous_remaining = current_remaining current_remaining = len(res2) for msg in res2: - self.delete(msg.dn) + try: + self.delete(msg.dn) + # Ignore no such object errors + except ldb.LdbError, (LDB_ERR_NO_SUCH_OBJECT, _): + pass + # Ignore not allowed on non leaf errors + except ldb.LdbError, (LDB_ERR_NOT_ALLOWED_ON_NON_LEAF, _): + pass def load_ldif_file_add(self, ldif_path): """Load a LDIF file. diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 55935b0037..ea2feb981b 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -279,8 +279,6 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, Alternatively, provision() may call this, and then populate the database. - :param erase: Remove the existing data present in the database. - :note: This will wipe the Sam Database! :note: This function always removes the local SAM LDB file. The erase @@ -289,10 +287,15 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, """ assert session_info is not None - if os.path.exists(samdb_path): + samdb = SamDB(samdb_path, session_info=session_info, + credentials=credentials, lp=lp) + + # Wipes the database + try: + samdb.erase() + except: os.unlink(samdb_path) - # Also wipes the database samdb = SamDB(samdb_path, session_info=session_info, credentials=credentials, lp=lp) @@ -547,7 +550,7 @@ def setup_self_join(samdb, configdn, schemadn, domaindn, def setup_samdb(path, setup_path, session_info, credentials, lp, schemadn, configdn, domaindn, dnsdomain, realm, - netbiosname, message, hostname, rootdn, erase, + netbiosname, message, hostname, rootdn, domainsid, aci, domainguid, policyguid, domainname, fill, adminpass, krbtgtpass, machinepass, hostguid, invocationid, dnspass, @@ -560,6 +563,8 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, assert serverrole in ("domain controller", "member server") + erase = (fill != FILL_DRS) + # Also wipes the database setup_samdb_partitions(path, setup_path, schemadn=schemadn, configdn=configdn, domaindn=domaindn, message=message, lp=lp, @@ -726,7 +731,7 @@ def provision(lp, setup_dir, message, paths, session_info, hostguid=None, adminpass=None, krbtgtpass=None, domainguid=None, policyguid=None, invocationid=None, machinepass=None, dnspass=None, root=None, nobody=None, nogroup=None, users=None, - wheel=None, backup=None, aci=None, serverrole=None, erase=False, + wheel=None, backup=None, aci=None, serverrole=None, ldap_backend=None, ldap_backend_type=None, sitename=DEFAULTSITE): """Provision samba4 @@ -830,7 +835,7 @@ def provision(lp, setup_dir, message, paths, session_info, message("Setting up smb.conf") if serverrole == "domain controller": smbconfsuffix = "dc" - elif serverrole == "member": + elif serverrole == "member server": smbconfsuffix = "member" setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix), paths.smbconf, { @@ -873,7 +878,7 @@ def provision(lp, setup_dir, message, paths, session_info, configdn=configdn, domaindn=domaindn, dnsdomain=dnsdomain, netbiosname=netbiosname, realm=realm, message=message, hostname=hostname, - rootdn=rootdn, erase=erase, domainsid=domainsid, + rootdn=rootdn, domainsid=domainsid, aci=aci, domainguid=domainguid, policyguid=policyguid, domainname=domain, fill=samdb_fill, adminpass=adminpass, krbtgtpass=krbtgtpass, diff --git a/source4/selftest/target/Samba4.pm b/source4/selftest/target/Samba4.pm index e0be8048a0..48fda17599 100644 --- a/source4/selftest/target/Samba4.pm +++ b/source4/selftest/target/Samba4.pm @@ -389,25 +389,26 @@ yoZeAErTALjyZYZEPcECQQDlUi0N8DFxQ/lOwWyR3Hailft+mPqoPCa8QHlQZnlG EOF #generated with - #hxtool issue-certificate --self-signed --issue-ca --ca-private-key=FILE:$KEYFILE \ - # --subject="CN=CA,$BASEDN" --certificate="FILE:$CAFILE" + # hxtool issue-certificate --self-signed --issue-ca \ + # --ca-private-key="FILE:$KEYFILE" \ + # --subject="CN=CA,DC=samba,DC=example,DC=com" \ + # --certificate="FILE:$CAFILE" --lifetime="25 years" open(CAFILE, ">$cafile"); print CAFILE <<EOF; -----BEGIN CERTIFICATE----- -MIIChTCCAe6gAwIBAgIUFZoF6jt0R+hQBdF7cWPy0tT3fGwwCwYJKoZIhvcNAQEFMFIxEzAR +MIICcTCCAdqgAwIBAgIUaBPmjnPVqyFqR5foICmLmikJTzgwCwYJKoZIhvcNAQEFMFIxEzAR BgoJkiaJk/IsZAEZDANjb20xFzAVBgoJkiaJk/IsZAEZDAdleGFtcGxlMRUwEwYKCZImiZPy -LGQBGQwFc2FtYmExCzAJBgNVBAMMAkNBMCIYDzIwMDcwMTIzMDU1MzA5WhgPMjAwODAxMjQw -NTUzMDlaMFIxEzARBgoJkiaJk/IsZAEZDANjb20xFzAVBgoJkiaJk/IsZAEZDAdleGFtcGxl +LGQBGQwFc2FtYmExCzAJBgNVBAMMAkNBMCIYDzIwMDgwMzAxMTIyMzEyWhgPMjAzMzAyMjQx +MjIzMTJaMFIxEzARBgoJkiaJk/IsZAEZDANjb20xFzAVBgoJkiaJk/IsZAEZDAdleGFtcGxl MRUwEwYKCZImiZPyLGQBGQwFc2FtYmExCzAJBgNVBAMMAkNBMIGfMA0GCSqGSIb3DQEBAQUA A4GNADCBiQKBgQDKg6pAwCHUMA1DfHDmWhZfd+F0C+9Jxcqvpw9ii9En3E1uflpcol3+S9/6 I/uaTmJHZre+DF3dTzb/UOZo0Zem8N+IzzkgoGkFafjXuT3BL5UPY2/H6H+pPqVIRLOmrWIm -ai359YyoKhFyo37Y6HPeU8QcZ+u2rS9geapIWfeuowIDAQABo1YwVDAOBgNVHQ8BAf8EBAMC -AqQwEgYDVR0lBAswCQYHKwYBBQIDBTAdBgNVHQ4EFgQUwtm596AMotmzRU7IVdgrUvozyjIw -DwYDVR0TBAgwBgEB/wIBADANBgkqhkiG9w0BAQUFAAOBgQBgzh5uLDmESGYv60iUdEfuk/T9 -VCpzb1z3VJVWt3uJoQYbcpR00SKeyMdlfTTLzO6tSPMmlk4hwqfvLkPzGCSObR4DRRYa0BtY -2laBVlg9X59bGpMUvpFQfpvxjvFWNJDL+377ELCVpLNdoR23I9TKXlalj0bY5Ks46CVIrm6W -EA== +ai359YyoKhFyo37Y6HPeU8QcZ+u2rS9geapIWfeuowIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC +AaYwHQYDVR0OBBYEFMLZufegDKLZs0VOyFXYK1L6M8oyMA8GA1UdEwEB/wQFMAMBAf8wDQYJ +KoZIhvcNAQEFBQADgYEAAZJbCAAkaqgFJ0xgNovn8Ydd0KswQPjicwiODPgw9ZPoD2HiOUVO +yYDRg/dhFF9y656OpcHk4N7qZ2sl3RlHkzDu+dseETW+CnKvQIoXNyeARRJSsSlwrwcoD4JR +HTLk2sGigsWwrJ2N99sG/cqSJLJ1MFwLrs6koweBnYU0f/g= -----END CERTIFICATE----- EOF @@ -434,17 +435,23 @@ EOF close(CERTFILE); #KDC certificate - # hxtool request-create --subject="CN=krbtgt,cn=users,$basedn" --key=FILE:$KEYFILE $KDCREQ + # hxtool request-create \ + # --subject="CN=krbtgt,CN=users,DC=samba,DC=example,DC=com" \ + # --key="FILE:$KEYFILE" $KDCREQ - # hxtool issue-certificate --ca-certificate=FILE:$CAFILE,$KEYFILE --type="pkinit-kdc" --pk-init-principal="krbtgt/$RELAM@$REALM" --req="$KDCREQ" --certificate="FILE:$KDCCERTFILE" + # hxtool issue-certificate --ca-certificate=FILE:$CAFILE,$KEYFILE \ + # --type="pkinit-kdc" \ + # --pk-init-principal="krbtgt/SAMBA.EXAMPLE.COM@SAMBA.EXAMPLE.COM" \ + # --req="PKCS10:$KDCREQ" --certificate="FILE:$KDCCERTFILE" \ + # --lifetime="25 years" open(KDCCERTFILE, ">$kdccertfile"); print KDCCERTFILE <<EOF; -----BEGIN CERTIFICATE----- -MIIDDDCCAnWgAwIBAgIUDEhjaOT1ZjHjHHEn+l5eYO05oK8wCwYJKoZIhvcNAQEFMFIxEzAR +MIIDDDCCAnWgAwIBAgIUI2Tzj+JnMzMcdeabcNo30rovzFAwCwYJKoZIhvcNAQEFMFIxEzAR BgoJkiaJk/IsZAEZDANjb20xFzAVBgoJkiaJk/IsZAEZDAdleGFtcGxlMRUwEwYKCZImiZPy -LGQBGQwFc2FtYmExCzAJBgNVBAMMAkNBMCIYDzIwMDcwMTIzMDcwNzA4WhgPMjAwODAxMjQw -NzA3MDhaMGYxEzARBgoJkiaJk/IsZAEZDANjb20xFzAVBgoJkiaJk/IsZAEZDAdleGFtcGxl +LGQBGQwFc2FtYmExCzAJBgNVBAMMAkNBMCIYDzIwMDgwMzAxMTMxOTIzWhgPMjAzMzAyMjQx +MzE5MjNaMGYxEzARBgoJkiaJk/IsZAEZDANjb20xFzAVBgoJkiaJk/IsZAEZDAdleGFtcGxl MRUwEwYKCZImiZPyLGQBGQwFc2FtYmExDjAMBgNVBAMMBXVzZXJzMQ8wDQYDVQQDDAZrcmJ0 Z3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMqDqkDAIdQwDUN8cOZaFl934XQL70nF yq+nD2KL0SfcTW5+WlyiXf5L3/oj+5pOYkdmt74MXd1PNv9Q5mjRl6bw34jPOSCgaQVp+Ne5 @@ -453,32 +460,40 @@ AAGjgcgwgcUwDgYDVR0PAQH/BAQDAgWgMBIGA1UdJQQLMAkGBysGAQUCAwUwVAYDVR0RBE0w S6BJBgYrBgEFAgKgPzA9oBMbEVNBTUJBLkVYQU1QTEUuQ09NoSYwJKADAgEBoR0wGxsGa3Ji dGd0GxFTQU1CQS5FWEFNUExFLkNPTTAfBgNVHSMEGDAWgBTC2bn3oAyi2bNFTshV2CtS+jPK MjAdBgNVHQ4EFgQUwtm596AMotmzRU7IVdgrUvozyjIwCQYDVR0TBAIwADANBgkqhkiG9w0B -AQUFAAOBgQCMSgLkIv9RobE0a95H2ECA+5YABBwKXIt4AyN/HpV7iJdRx7B9PE6vM+nboVKY -E7i7ECUc3bu6NgrLu7CKHelNclHWWMiZzSUwhkXyvG/LE9qtr/onNu9NfLt1OV+dwQwyLdEP -n63FxSmsKg3dfi3ryQI/DIKeisvipwDtLqOn9g== +AQUFAAOBgQBmrVD5MCmZjfHp1nEnHqTIh8r7lSmVtDx4s9MMjxm9oNrzbKXynvdhwQYFVarc +ge4yRRDXtSebErOl71zVJI9CVeQQpwcH+tA85oGA7oeFtO/S7ls581RUU6tGgyxV4veD+lJv +KPH5LevUtgD+q9H4LU4Sq5N3iFwBaeryB0g2wg== -----END CERTIFICATE----- EOF - #hxtool request-create --subject="CN=Administrator,cn=users,$basedn" --key=FILE:$ADMINKEYFILE $ADMINREQFILE - #hxtool issue-certificate --ca-certificate=FILE:$CAFILE,$KEYFILE --type="pkinit-client" --pk-init-principal="administrator@$REALM" --req="$ADMINREQFILE" --certificate="FILE:$ADMINCERTFILE" + # hxtool request-create \ + # --subject="CN=Administrator,CN=users,DC=samba,DC=example,DC=com" \ + # --key="FILE:$ADMINKEYFILE" $ADMINREQFILE + + # hxtool issue-certificate --ca-certificate=FILE:$CAFILE,$KEYFILE \ + # --type="pkinit-client" \ + # --pk-init-principal="administrator@SAMBA.EXAMPLE.COM" \ + # --req="PKCS10:$ADMINREQFILE" --certificate="FILE:$ADMINCERTFILE" \ + # --lifetime="25 years" open(ADMINCERTFILE, ">$admincertfile"); print ADMINCERTFILE <<EOF; -----BEGIN CERTIFICATE----- -MIICwjCCAiugAwIBAgIUXyECoq4im33ByZDWZMGhtpvHYWEwCwYJKoZIhvcNAQEFMFIxEzAR +MIIDHTCCAoagAwIBAgIUC0W5dW/N9kE+NgD0mKK34YgyqQ0wCwYJKoZIhvcNAQEFMFIxEzAR BgoJkiaJk/IsZAEZDANjb20xFzAVBgoJkiaJk/IsZAEZDAdleGFtcGxlMRUwEwYKCZImiZPy -LGQBGQwFc2FtYmExCzAJBgNVBAMMAkNBMCIYDzIwMDcwMTIzMDcyMzE2WhgPMjAwODAxMjQw -NzIzMTZaMCgxDjAMBgNVBAMMBXVzZXJzMRYwFAYDVQQDDA1BZG1pbmlzdHJhdG9yMIGfMA0G -CSqGSIb3DQEBAQUAA4GNADCBiQKBgQD0+OL7TQBj0RejbIH1+g5GeRaWaM9xF43uE5y7jUHE -si5owhZF5iIoHZeeL6cpDF5y1BZRs0JlA1VqMry1jjKlzFYVEMMFxB6esnXhl0Jpip1JkUMM -XLOP1m/0dqayuHBWozj9f/cdyCJr0wJIX1Z8Pr+EjYRGPn/MF0xdl3JRlwIDAQABo4G8MIG5 -MA4GA1UdDwEB/wQEAwIFoDASBgNVHSUECzAJBgcrBgEFAgMEMEgGA1UdEQRBMD+gPQYGKwYB -BQICoDMwMaATGxFTQU1CQS5FWEFNUExFLkNPTaEaMBigAwIBAaERMA8bDWFkbWluaXN0cmF0 -b3IwHwYDVR0jBBgwFoAUwtm596AMotmzRU7IVdgrUvozyjIwHQYDVR0OBBYEFCDzVsvJ8IDz -wLYH8EONeUa5oVrGMAkGA1UdEwQCMAAwDQYJKoZIhvcNAQEFBQADgYEAbTCnaPTieVZPV3bH -UmAMbnF9+YN1mCbe2xZJ0xzve+Yw1XO82iv/9kZaZkcRkaQt2qcwsBK/aSPOgfqGx+mJ7hXQ -AGWvAJhnWi25PawNaRysCN8WC6+nWKR4d2O2m5rpj3T9kH5WE7QbG0bCu92dGaS29FvWDCP3 -q9pRtDOoAZc= +LGQBGQwFc2FtYmExCzAJBgNVBAMMAkNBMCIYDzIwMDgwMzAxMTMyMzAwWhgPMjAzMzAyMjQx +MzIzMDBaMG0xEzARBgoJkiaJk/IsZAEZDANjb20xFzAVBgoJkiaJk/IsZAEZDAdleGFtcGxl +MRUwEwYKCZImiZPyLGQBGQwFc2FtYmExDjAMBgNVBAMMBXVzZXJzMRYwFAYDVQQDDA1BZG1p +bmlzdHJhdG9yMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD0+OL7TQBj0RejbIH1+g5G +eRaWaM9xF43uE5y7jUHEsi5owhZF5iIoHZeeL6cpDF5y1BZRs0JlA1VqMry1jjKlzFYVEMMF +xB6esnXhl0Jpip1JkUMMXLOP1m/0dqayuHBWozj9f/cdyCJr0wJIX1Z8Pr+EjYRGPn/MF0xd +l3JRlwIDAQABo4HSMIHPMA4GA1UdDwEB/wQEAwIFoDAoBgNVHSUEITAfBgcrBgEFAgMEBggr +BgEFBQcDAgYKKwYBBAGCNxQCAjBIBgNVHREEQTA/oD0GBisGAQUCAqAzMDGgExsRU0FNQkEu +RVhBTVBMRS5DT02hGjAYoAMCAQGhETAPGw1hZG1pbmlzdHJhdG9yMB8GA1UdIwQYMBaAFMLZ +ufegDKLZs0VOyFXYK1L6M8oyMB0GA1UdDgQWBBQg81bLyfCA88C2B/BDjXlGuaFaxjAJBgNV +HRMEAjAAMA0GCSqGSIb3DQEBBQUAA4GBAHsqSqul0hZCXn4t8Kfp3v/JLMiUMJihR1XOgzoa +ufLOQ1HNzFUHKuo1JEQ1+i5gHT/arLu/ZBF4BfQol7vW27gKIEt0fkRV8EvoPxXvSokHq0Ku +HCuPOhYNEP3wYiwB3g93NMCinWVlz0mh5aijEU7y/XrjlZxBKFFrTE+BJi1o -----END CERTIFICATE----- EOF close(ADMINCERTFILE); diff --git a/source4/torture/raw/chkpath.c b/source4/torture/raw/chkpath.c index 42a3c3cebe..fa69c92caa 100644 --- a/source4/torture/raw/chkpath.c +++ b/source4/torture/raw/chkpath.c @@ -54,24 +54,68 @@ static NTSTATUS single_search(struct smbcli_state *cli, return status; } -static bool test_path(struct smbcli_state *cli, const char *path, NTSTATUS expected, NTSTATUS dos_expected) +static bool test_path_ex(struct smbcli_state *cli, struct torture_context *tctx, + const char *path, const char *path_expected, + NTSTATUS expected, NTSTATUS dos_expected) { union smb_chkpath io; + union smb_fileinfo finfo; NTSTATUS status; + io.chkpath.in.path = path; status = smb_raw_chkpath(cli->tree, &io); if (!NT_STATUS_EQUAL(status, expected) && !NT_STATUS_EQUAL(status, dos_expected)) { - printf("%-40s FAILED %s should be %s or %s\n", + printf("FAILED %-30s chkpath %s should be %s or %s\n", path, nt_errstr(status), nt_errstr(expected), nt_errstr(dos_expected)); return false; } else { - printf("%-40s correct (%s)\n", path, nt_errstr(status)); + printf("%-30s chkpath correct (%s)\n", path, nt_errstr(status)); + } + + if (NT_STATUS_EQUAL(expected, NT_STATUS_NOT_A_DIRECTORY)) { + expected = NT_STATUS_OK; + } + + ZERO_STRUCT(finfo); + finfo.generic.level = RAW_FILEINFO_NAME_INFO; + finfo.generic.in.file.path = path; + status = smb_raw_pathinfo(cli->tree, cli, &finfo); + if (!NT_STATUS_EQUAL(status, expected) && !NT_STATUS_EQUAL(status, dos_expected)) { + printf("FAILED: %-30s pathinfo %s should be %s or %s\n", + path, nt_errstr(status), nt_errstr(expected), nt_errstr(dos_expected)); + return false; + } + + if (!NT_STATUS_IS_OK(status)) { + printf("%-30s chkpath correct (%s)\n", path, nt_errstr(status)); + return true; + } + if (path_expected && + (!finfo.name_info.out.fname.s || + strcmp(finfo.name_info.out.fname.s, path_expected) != 0)) { + if (tctx && torture_setting_bool(tctx, "samba4", false)) { + printf("IGNORE: %-30s => %-20s should be %s\n", + path, finfo.name_info.out.fname.s, path_expected); + return true; + } + printf("FAILED: %-30s => %-20s should be %s\n", + path, finfo.name_info.out.fname.s, path_expected); + return false; } + printf("%-30s => %-20s correct\n", + path, finfo.name_info.out.fname.s); + return true; } -static bool test_chkpath(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) +static bool test_path(struct smbcli_state *cli, const char *path, + NTSTATUS expected, NTSTATUS dos_expected) +{ + return test_path_ex(cli, NULL, path, path, expected, dos_expected); +} + +static bool test_chkpath(struct smbcli_state *cli, struct torture_context *tctx) { union smb_chkpath io; NTSTATUS status; @@ -86,7 +130,7 @@ static bool test_chkpath(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) ret &= test_path(cli, BASEDIR "\\nodir", NT_STATUS_OBJECT_NAME_NOT_FOUND, NT_STATUS_DOS(ERRDOS,ERRbadpath)); - fnum = create_complex_file(cli, mem_ctx, BASEDIR "\\test.txt.."); + fnum = create_complex_file(cli, tctx, BASEDIR "\\test.txt.."); if (fnum == -1) { printf("failed to open test.txt - %s\n", smbcli_errstr(cli->tree)); ret = false; @@ -101,9 +145,20 @@ static bool test_chkpath(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) goto done; } - ret &= test_path(cli, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); - ret &= test_path(cli, BASEDIR "\\foo\\..\\test.txt..", NT_STATUS_NOT_A_DIRECTORY, NT_STATUS_DOS(ERRDOS,ERRbadpath)); - ret &= test_path(cli, "", NT_STATUS_OK, NT_STATUS_OK); + ret &= test_path_ex(cli, tctx, BASEDIR, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); + ret &= test_path_ex(cli, tctx, ((char *)BASEDIR) + 1, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); + ret &= test_path_ex(cli, tctx, ((char *)BASEDIR"\\\\") + 1, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); + ret &= test_path_ex(cli, tctx, ((char *)BASEDIR"\\foo\\..") + 1, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); + ret &= test_path_ex(cli, tctx, ((char *)BASEDIR"\\f\\o\\o\\..\\..\\..") + 1, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); + ret &= test_path_ex(cli, tctx, ((char *)BASEDIR"\\foo\\\\\..\\\\") + 1, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); + ret &= test_path_ex(cli, tctx, BASEDIR"\\", BASEDIR, NT_STATUS_OK, NT_STATUS_OK); + ret &= test_path_ex(cli, tctx, BASEDIR"\\\\..\\"BASEDIR, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); + ret &= test_path_ex(cli, tctx, BASEDIR"\\\\\\", BASEDIR, NT_STATUS_OK, NT_STATUS_OK); + ret &= test_path_ex(cli, tctx, "\\\\\\\\"BASEDIR"\\\\\\\\", BASEDIR, NT_STATUS_OK, NT_STATUS_OK); + ret &= test_path_ex(cli, tctx, "\\\\\\\\"BASEDIR, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); + ret &= test_path_ex(cli, tctx, BASEDIR "\\foo\\..\\test.txt..", BASEDIR "\\test.txt..", + NT_STATUS_NOT_A_DIRECTORY, NT_STATUS_DOS(ERRDOS,ERRbadpath)); + ret &= test_path_ex(cli, tctx, "", "\\", NT_STATUS_OK, NT_STATUS_OK); ret &= test_path(cli, ".", NT_STATUS_OBJECT_NAME_INVALID, NT_STATUS_DOS(ERRDOS,ERRbadpath)); ret &= test_path(cli, ".\\", NT_STATUS_OBJECT_NAME_INVALID, NT_STATUS_DOS(ERRDOS,ERRbadpath)); ret &= test_path(cli, "\\\\\\.\\", NT_STATUS_OBJECT_NAME_INVALID, NT_STATUS_DOS(ERRDOS,ERRbadpath)); @@ -122,7 +177,7 @@ static bool test_chkpath(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) give different NT status returns for chkpth and findfirst. */ printf("testing findfirst on %s\n", "\\.\\\\\\\\\\\\."); - status = single_search(cli, mem_ctx, "\\.\\\\\\\\\\\\."); + status = single_search(cli, tctx, "\\.\\\\\\\\\\\\."); CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRinvalidname)); ret &= test_path(cli, "\\.\\\\\\\\\\\\.", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath)); @@ -164,7 +219,7 @@ static bool test_chkpath(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) ret &= test_path(cli, "\\..\\", NT_STATUS_OBJECT_PATH_SYNTAX_BAD,NT_STATUS_DOS(ERRDOS,ERRinvalidpath)); ret &= test_path(cli, "\\..", NT_STATUS_OBJECT_PATH_SYNTAX_BAD,NT_STATUS_DOS(ERRDOS,ERRinvalidpath)); ret &= test_path(cli, BASEDIR "\\.", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath)); - ret &= test_path(cli, BASEDIR "\\..", NT_STATUS_OK,NT_STATUS_OK); + ret &= test_path_ex(cli, tctx, BASEDIR "\\..", "\\", NT_STATUS_OK,NT_STATUS_OK); ret &= test_path(cli, BASEDIR "\\nt\\V S\\VB98\\vb600", NT_STATUS_OBJECT_NAME_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath)); ret &= test_path(cli, BASEDIR "\\nt\\V S\\VB98\\vb6.exe", NT_STATUS_NOT_A_DIRECTORY,NT_STATUS_DOS(ERRDOS,ERRbadpath)); @@ -183,7 +238,7 @@ static bool test_chkpath(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath)); printf("testing findfirst on %s\n", BASEDIR".\\.\\.\\.\\foo\\..\\.\\"); - status = single_search(cli, mem_ctx, BASEDIR".\\.\\.\\.\\foo\\..\\.\\"); + status = single_search(cli, tctx, BASEDIR".\\.\\.\\.\\foo\\..\\.\\"); CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath)); /* We expect this open to fail with the same error code as the chkpath below. */ diff --git a/source4/torture/raw/setfileinfo.c b/source4/torture/raw/setfileinfo.c index e58b3fd760..90ccde7213 100644 --- a/source4/torture/raw/setfileinfo.c +++ b/source4/torture/raw/setfileinfo.c @@ -453,6 +453,10 @@ bool torture_raw_sfileinfo_rename(struct torture_context *torture, char *fnum_fname_new; char *path_fname; char *path_fname_new; + char *path_dname; + char *path_dname_new; + char *saved_name; + char *saved_name_new; union smb_fileinfo finfo1, finfo2; union smb_setfileinfo sfinfo; NTSTATUS status, status2; @@ -464,6 +468,8 @@ bool torture_raw_sfileinfo_rename(struct torture_context *torture, asprintf(&path_fname_new, BASEDIR "\\fname_test_new_%d.txt", n); asprintf(&fnum_fname, BASEDIR "\\fnum_test_%d.txt", n); asprintf(&fnum_fname_new, BASEDIR "\\fnum_test_new_%d.txt", n); + asprintf(&path_dname, BASEDIR "\\dname_test_%d", n); + asprintf(&path_dname_new, BASEDIR "\\dname_test_new_%d", n); if (!torture_setup_dir(cli, BASEDIR)) { return false; @@ -553,17 +559,112 @@ bool torture_raw_sfileinfo_rename(struct torture_context *torture, sfinfo.rename_information.in.root_fid = d_fnum; CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_INVALID_PARAMETER); CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname); + smbcli_close(cli->tree, d_fnum); -done: - smb_raw_exit(cli->session); - smbcli_close(cli->tree, fnum); - if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fnum_fname))) { - printf("Failed to delete %s - %s\n", fnum_fname, smbcli_errstr(cli->tree)); + printf("Trying rename directory\n"); + if (!torture_setup_dir(cli, path_dname)) { + ret = false; + goto done; } - if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, path_fname))) { - printf("Failed to delete %s - %s\n", path_fname, smbcli_errstr(cli->tree)); + saved_name = path_fname; + saved_name_new = path_fname_new; + path_fname = path_dname; + path_fname_new = path_dname_new; + sfinfo.rename_information.in.new_name = path_dname_new+strlen(BASEDIR)+1; + sfinfo.rename_information.in.overwrite = 0; + sfinfo.rename_information.in.root_fid = 0; + CHECK_CALL_PATH(RENAME_INFORMATION, NT_STATUS_OK); + CHECK_STR(NAME_INFO, name_info, fname.s, path_dname_new); + path_fname = saved_name; + path_fname_new = saved_name_new; + + if (torture_setting_bool(torture, "samba3", false)) { + printf("SKIP: Trying rename directory with a handle\n"); + printf("SKIP: Trying rename by path while a handle is open\n"); + printf("SKIP: Trying rename directory by path while a handle is open\n"); + goto done; } + printf("Trying rename directory with a handle\n"); + status = create_directory_handle(cli->tree, path_dname_new, &d_fnum); + fnum_saved = fnum; + fnum = d_fnum; + saved_name = fnum_fname; + saved_name_new = fnum_fname_new; + fnum_fname = path_dname; + fnum_fname_new = path_dname_new; + sfinfo.rename_information.in.new_name = path_dname+strlen(BASEDIR)+1; + sfinfo.rename_information.in.overwrite = 0; + sfinfo.rename_information.in.root_fid = 0; + CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK); + CHECK_STR(NAME_INFO, name_info, fname.s, path_dname); + smbcli_close(cli->tree, d_fnum); + fnum = fnum_saved; + fnum_fname = saved_name; + fnum_fname_new = saved_name_new; + + printf("Trying rename by path while a handle is open\n"); + fnum_saved = fnum; + fnum = create_complex_file(cli, torture, path_fname); + sfinfo.rename_information.in.new_name = path_fname_new+strlen(BASEDIR)+1; + sfinfo.rename_information.in.overwrite = 0; + sfinfo.rename_information.in.root_fid = 0; + CHECK_CALL_PATH(RENAME_INFORMATION, NT_STATUS_OK); + CHECK_STR(NAME_INFO, name_info, fname.s, path_fname_new); + /* check that the handle returns the same name */ + check_fnum = true; + CHECK_STR(NAME_INFO, name_info, fname.s, path_fname_new); + /* rename it back on the handle */ + sfinfo.rename_information.in.new_name = path_fname+strlen(BASEDIR)+1; + CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK); + CHECK_STR(NAME_INFO, name_info, fname.s, path_fname); + check_fnum = false; + CHECK_STR(NAME_INFO, name_info, fname.s, path_fname); + smbcli_close(cli->tree, fnum); + fnum = fnum_saved; + + printf("Trying rename directory by path while a handle is open\n"); + status = create_directory_handle(cli->tree, path_dname, &d_fnum); + fnum_saved = fnum; + fnum = d_fnum; + saved_name = path_fname; + saved_name_new = path_fname_new; + path_fname = path_dname; + path_fname_new = path_dname_new; + sfinfo.rename_information.in.new_name = path_dname_new+strlen(BASEDIR)+1; + sfinfo.rename_information.in.overwrite = 0; + sfinfo.rename_information.in.root_fid = 0; + CHECK_CALL_PATH(RENAME_INFORMATION, NT_STATUS_OK); + CHECK_STR(NAME_INFO, name_info, fname.s, path_dname_new); + path_fname = saved_name; + path_fname_new = saved_name_new; + saved_name = fnum_fname; + saved_name_new = fnum_fname_new; + fnum_fname = path_dname; + fnum_fname_new = path_dname_new; + /* check that the handle returns the same name */ + check_fnum = true; + CHECK_STR(NAME_INFO, name_info, fname.s, path_dname_new); + /* rename it back on the handle */ + sfinfo.rename_information.in.new_name = path_dname+strlen(BASEDIR)+1; + CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK); + CHECK_STR(NAME_INFO, name_info, fname.s, path_dname); + fnum_fname = saved_name; + fnum_fname_new = saved_name_new; + saved_name = path_fname; + saved_name_new = path_fname_new; + path_fname = path_dname; + path_fname_new = path_dname_new; + check_fnum = false; + CHECK_STR(NAME_INFO, name_info, fname.s, path_dname); + smbcli_close(cli->tree, d_fnum); + fnum = fnum_saved; + path_fname = saved_name; + path_fname_new = saved_name_new; + +done: + smb_raw_exit(cli->session); + smbcli_deltree(cli->tree, BASEDIR); return ret; } diff --git a/source4/torture/rpc/winreg.c b/source4/torture/rpc/winreg.c index 4695733671..8b602ef652 100644 --- a/source4/torture/rpc/winreg.c +++ b/source4/torture/rpc/winreg.c @@ -848,7 +848,6 @@ static bool test_SecurityDescriptorInheritance(struct dcerpc_pipe *p, out: test_CloseKey(p, tctx, &new_handle); - test_Cleanup(p, tctx, handle, TEST_SUBSUBKEY_SD); test_Cleanup(p, tctx, handle, TEST_SUBKEY_SD); test_RestoreSecurity(p, tctx, handle, key, sd_orig); @@ -971,7 +970,6 @@ static bool test_SecurityDescriptorBlockInheritance(struct dcerpc_pipe *p, out: test_CloseKey(p, tctx, &new_handle); - test_Cleanup(p, tctx, handle, TEST_SUBSUBKEY_SD); test_Cleanup(p, tctx, handle, TEST_SUBKEY_SD); test_RestoreSecurity(p, tctx, handle, key, sd_orig); @@ -1386,27 +1384,6 @@ static bool test_DeleteKey(struct dcerpc_pipe *p, struct torture_context *tctx, return true; } -/* DeleteKey on a key with subkey(s) should - * return WERR_ACCESS_DENIED. */ -static bool test_DeleteKeyWithSubkey(struct dcerpc_pipe *p, - struct torture_context *tctx, - struct policy_handle *handle, - const char *key) -{ - struct winreg_DeleteKey r; - - r.in.handle = handle; - init_winreg_String(&r.in.key, key); - - torture_assert_ntstatus_ok(tctx, dcerpc_winreg_DeleteKey(p, tctx, &r), - "DeleteKeyWithSubkey failed"); - - torture_assert_werr_equal(tctx, r.out.result, WERR_ACCESS_DENIED, - "DeleteKeyWithSubkey failed"); - - return true; -} - static bool test_QueryInfoKey(struct dcerpc_pipe *p, struct torture_context *tctx, struct policy_handle *handle, char *class) @@ -1443,10 +1420,12 @@ static bool test_QueryInfoKey(struct dcerpc_pipe *p, } static bool test_key(struct dcerpc_pipe *p, struct torture_context *tctx, - struct policy_handle *handle, int depth); + struct policy_handle *handle, int depth, + bool test_security); static bool test_EnumKey(struct dcerpc_pipe *p, struct torture_context *tctx, - struct policy_handle *handle, int depth) + struct policy_handle *handle, int depth, + bool test_security) { struct winreg_EnumKey r; struct winreg_StringBuf class, name; @@ -1479,7 +1458,8 @@ static bool test_EnumKey(struct dcerpc_pipe *p, struct torture_context *tctx, if (!test_OpenKey(p, tctx, handle, r.out.name->name, &key_handle)) { } else { - test_key(p, tctx, &key_handle, depth + 1); + test_key(p, tctx, &key_handle, + depth + 1, test_security); } } @@ -1676,7 +1656,8 @@ static bool test_InitiateSystemShutdownEx(struct torture_context *tctx, #define MAX_DEPTH 2 /* Only go this far down the tree */ static bool test_key(struct dcerpc_pipe *p, struct torture_context *tctx, - struct policy_handle *handle, int depth) + struct policy_handle *handle, int depth, + bool test_security) { if (depth == MAX_DEPTH) return true; @@ -1687,10 +1668,10 @@ static bool test_key(struct dcerpc_pipe *p, struct torture_context *tctx, if (!test_NotifyChangeKeyValue(p, tctx, handle)) { } - if (!test_GetKeySecurity(p, tctx, handle, NULL)) { + if (test_security && !test_GetKeySecurity(p, tctx, handle, NULL)) { } - if (!test_EnumKey(p, tctx, handle, depth)) { + if (!test_EnumKey(p, tctx, handle, depth, test_security)) { } if (!test_EnumValue(p, tctx, handle, 0xFF, 0xFFFF)) { @@ -1703,13 +1684,85 @@ static bool test_key(struct dcerpc_pipe *p, struct torture_context *tctx, typedef NTSTATUS (*winreg_open_fn)(struct dcerpc_pipe *, TALLOC_CTX *, void *); +static bool test_Open_Security(struct torture_context *tctx, + struct dcerpc_pipe *p, void *userdata) +{ + struct policy_handle handle, newhandle; + bool ret = true, created2 = false; + bool created4 = false; + struct winreg_OpenHKLM r; + + winreg_open_fn open_fn = userdata; + + r.in.system_name = 0; + r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + r.out.handle = &handle; + + torture_assert_ntstatus_ok(tctx, open_fn(p, tctx, &r), + "open"); + + test_Cleanup(p, tctx, &handle, TEST_KEY_BASE); + + if (!test_CreateKey(p, tctx, &handle, TEST_KEY_BASE, NULL)) { + torture_comment(tctx, + "CreateKey (TEST_KEY_BASE) failed\n"); + } + + if (test_CreateKey_sd(p, tctx, &handle, TEST_KEY2, + NULL, &newhandle)) { + created2 = true; + } + + if (created2 && !test_CloseKey(p, tctx, &newhandle)) { + printf("CloseKey failed\n"); + ret = false; + } + + if (test_CreateKey_sd(p, tctx, &handle, TEST_KEY4, NULL, &newhandle)) { + created4 = true; + } + + if (created4 && !test_CloseKey(p, tctx, &newhandle)) { + printf("CloseKey failed\n"); + ret = false; + } + + if (created4 && !test_SecurityDescriptors(p, tctx, &handle, TEST_KEY4)) { + ret = false; + } + + if (created4 && !test_DeleteKey(p, tctx, &handle, TEST_KEY4)) { + printf("DeleteKey failed\n"); + ret = false; + } + + if (created2 && !test_DeleteKey(p, tctx, &handle, TEST_KEY2)) { + printf("DeleteKey failed\n"); + ret = false; + } + + /* The HKCR hive has a very large fanout */ + if (open_fn == (void *)dcerpc_winreg_OpenHKCR) { + if(!test_key(p, tctx, &handle, MAX_DEPTH - 1, true)) { + ret = false; + } + } else { + if (!test_key(p, tctx, &handle, 0, true)) { + ret = false; + } + } + + test_Cleanup(p, tctx, &handle, TEST_KEY_BASE); + + return ret; +} + static bool test_Open(struct torture_context *tctx, struct dcerpc_pipe *p, void *userdata) { struct policy_handle handle, newhandle; - bool ret = true, created = false, created2 = false, deleted = false; + bool ret = true, created = false, deleted = false; bool created3 = false, created_subkey = false; - bool created4 = false; struct winreg_OpenHKLM r; winreg_open_fn open_fn = userdata; @@ -1721,15 +1774,13 @@ static bool test_Open(struct torture_context *tctx, struct dcerpc_pipe *p, torture_assert_ntstatus_ok(tctx, open_fn(p, tctx, &r), "open"); - test_Cleanup(p, tctx, &handle, TEST_KEY1); - test_Cleanup(p, tctx, &handle, TEST_SUBSUBKEY_SD); - test_Cleanup(p, tctx, &handle, TEST_SUBKEY_SD); - test_Cleanup(p, tctx, &handle, TEST_KEY4); - test_Cleanup(p, tctx, &handle, TEST_KEY2); - test_Cleanup(p, tctx, &handle, TEST_SUBKEY); - test_Cleanup(p, tctx, &handle, TEST_KEY3); test_Cleanup(p, tctx, &handle, TEST_KEY_BASE); + if (!test_CreateKey(p, tctx, &handle, TEST_KEY_BASE, NULL)) { + torture_comment(tctx, + "CreateKey (TEST_KEY_BASE) failed\n"); + } + if (!test_CreateKey(p, tctx, &handle, TEST_KEY1, NULL)) { torture_comment(tctx, "CreateKey failed - not considering a failure\n"); @@ -1763,9 +1814,12 @@ static bool test_Open(struct torture_context *tctx, struct dcerpc_pipe *p, } if (created && deleted && - test_OpenKey(p, tctx, &handle, TEST_KEY1, &newhandle)) { + !_test_OpenKey(p, tctx, &handle, TEST_KEY1, + SEC_FLAG_MAXIMUM_ALLOWED, &newhandle, + WERR_BADFILE, NULL)) { torture_comment(tctx, - "DeleteKey failed (OpenKey after Delete worked)\n"); + "DeleteKey failed (OpenKey after Delete " + "did not return WERR_BADFILE)\n"); ret = false; } @@ -1774,40 +1828,6 @@ static bool test_Open(struct torture_context *tctx, struct dcerpc_pipe *p, ret = false; } - if (created && test_CreateKey_sd(p, tctx, &handle, TEST_KEY2, - NULL, &newhandle)) { - created2 = true; - } - - if (created2 && !test_CloseKey(p, tctx, &newhandle)) { - printf("CloseKey failed\n"); - ret = false; - } - - if (test_CreateKey_sd(p, tctx, &handle, TEST_KEY4, NULL, &newhandle)) { - created4 = true; - } - - if (!created4 && !test_CloseKey(p, tctx, &newhandle)) { - printf("CloseKey failed\n"); - ret = false; - } - - if (created4 && !test_SecurityDescriptors(p, tctx, &handle, TEST_KEY4)) { - ret = false; - } - - if (created4 && !test_DeleteKey(p, tctx, &handle, TEST_KEY4)) { - printf("DeleteKey failed\n"); - ret = false; - } - - - if (created && !test_DeleteKey(p, tctx, &handle, TEST_KEY2)) { - printf("DeleteKey failed\n"); - ret = false; - } - if (created && test_CreateKey(p, tctx, &handle, TEST_KEY3, NULL)) { created3 = true; } @@ -1818,19 +1838,6 @@ static bool test_Open(struct torture_context *tctx, struct dcerpc_pipe *p, } if (created_subkey && - !test_DeleteKeyWithSubkey(p, tctx, &handle, TEST_KEY3)) { - printf("DeleteKeyWithSubkey failed " - "(DeleteKey didn't return ACCESS_DENIED)\n"); - ret = false; - } - - if (created_subkey && - !test_DeleteKey(p, tctx, &handle, TEST_SUBKEY)) { - printf("DeleteKey failed\n"); - ret = false; - } - - if (created3 && !test_DeleteKey(p, tctx, &handle, TEST_KEY3)) { printf("DeleteKey failed\n"); ret = false; @@ -1838,13 +1845,13 @@ static bool test_Open(struct torture_context *tctx, struct dcerpc_pipe *p, /* The HKCR hive has a very large fanout */ if (open_fn == (void *)dcerpc_winreg_OpenHKCR) { - if(!test_key(p, tctx, &handle, MAX_DEPTH - 1)) { + if(!test_key(p, tctx, &handle, MAX_DEPTH - 1, false)) { + ret = false; + } + } else { + if (!test_key(p, tctx, &handle, 0, false)) { ret = false; } - } - - if (!test_key(p, tctx, &handle, 0)) { - ret = false; } test_Cleanup(p, tctx, &handle, TEST_KEY_BASE); @@ -1854,14 +1861,6 @@ static bool test_Open(struct torture_context *tctx, struct dcerpc_pipe *p, struct torture_suite *torture_rpc_winreg(TALLOC_CTX *mem_ctx) { - struct { - const char *name; - winreg_open_fn fn; - } open_fns[] = {{"OpenHKLM", (winreg_open_fn)dcerpc_winreg_OpenHKLM }, - {"OpenHKU", (winreg_open_fn)dcerpc_winreg_OpenHKU }, - {"OpenHKCR", (winreg_open_fn)dcerpc_winreg_OpenHKCR }, - {"OpenHKCU", (winreg_open_fn)dcerpc_winreg_OpenHKCU }}; - int i; struct torture_rpc_tcase *tcase; struct torture_suite *suite = torture_suite_create(mem_ctx, "WINREG"); struct torture_test *test; @@ -1877,10 +1876,33 @@ struct torture_suite *torture_rpc_winreg(TALLOC_CTX *mem_ctx) test_InitiateSystemShutdownEx); test->dangerous = true; - for (i = 0; i < ARRAY_SIZE(open_fns); i++) { - torture_rpc_tcase_add_test_ex(tcase, open_fns[i].name, - test_Open, open_fns[i].fn); - } + /* Basic tests without security descriptors */ + torture_rpc_tcase_add_test_ex(tcase, "HKLM-basic", + test_Open, + (winreg_open_fn)dcerpc_winreg_OpenHKLM); + torture_rpc_tcase_add_test_ex(tcase, "HKU-basic", + test_Open, + (winreg_open_fn)dcerpc_winreg_OpenHKU); + torture_rpc_tcase_add_test_ex(tcase, "HKCR-basic", + test_Open, + (winreg_open_fn)dcerpc_winreg_OpenHKCR); + torture_rpc_tcase_add_test_ex(tcase, "HKCU-basic", + test_Open, + (winreg_open_fn)dcerpc_winreg_OpenHKCU); + + /* Security descriptor tests */ + torture_rpc_tcase_add_test_ex(tcase, "HKLM-security", + test_Open_Security, + (winreg_open_fn)dcerpc_winreg_OpenHKLM); + torture_rpc_tcase_add_test_ex(tcase, "HKU-security", + test_Open_Security, + (winreg_open_fn)dcerpc_winreg_OpenHKU); + torture_rpc_tcase_add_test_ex(tcase, "HKCR-security", + test_Open_Security, + (winreg_open_fn)dcerpc_winreg_OpenHKCR); + torture_rpc_tcase_add_test_ex(tcase, "HKCU-security", + test_Open_Security, + (winreg_open_fn)dcerpc_winreg_OpenHKCU); return suite; } |