diff options
-rw-r--r-- | source3/smbd/files.c | 25 | ||||
-rw-r--r-- | source4/torture/raw/rename.c | 50 |
2 files changed, 69 insertions, 6 deletions
diff --git a/source3/smbd/files.c b/source3/smbd/files.c index a170f774fe..146d809738 100644 --- a/source3/smbd/files.c +++ b/source3/smbd/files.c @@ -404,14 +404,15 @@ bool file_find_subpath(files_struct *dir_fsp) { files_struct *fsp; size_t dlen; - char *d_fullname; + char *d_fullname = NULL; + bool ret = false; d_fullname = talloc_asprintf(talloc_tos(), "%s/%s", dir_fsp->conn->connectpath, dir_fsp->fsp_name->base_name); if (!d_fullname) { - return false; + goto out; } dlen = strlen(d_fullname); @@ -429,15 +430,27 @@ bool file_find_subpath(files_struct *dir_fsp) fsp->fsp_name->base_name); if (strnequal(d_fullname, d1_fullname, dlen)) { - TALLOC_FREE(d_fullname); + int d1_len = strlen(d1_fullname); + + /* + * If the open file is a second file handle to the + * same name or is a stream on the original file, then + * don't return true. + */ + if (d1_len == dlen) { + TALLOC_FREE(d1_fullname); + continue; + } + TALLOC_FREE(d1_fullname); - return true; + ret = true; + goto out; } TALLOC_FREE(d1_fullname); } - + out: TALLOC_FREE(d_fullname); - return false; + return ret; } /**************************************************************************** diff --git a/source4/torture/raw/rename.c b/source4/torture/raw/rename.c index e91c3b2319..15fed0e3d8 100644 --- a/source4/torture/raw/rename.c +++ b/source4/torture/raw/rename.c @@ -529,6 +529,7 @@ static bool test_dir_rename(struct torture_context *tctx, struct smbcli_state *c const char *dname1 = BASEDIR "\\dir_for_rename"; const char *dname2 = BASEDIR "\\renamed_dir"; const char *fname = BASEDIR "\\dir_for_rename\\file.txt"; + const char *sname = BASEDIR "\\dir_for_rename:a stream:$DATA"; bool ret = true; int fnum = -1; @@ -593,6 +594,55 @@ static bool test_dir_rename(struct torture_context *tctx, struct smbcli_state *c status = smb_raw_rename(cli->tree, &ren_io); CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); + /* Close the file and try the rename. */ + smbcli_close(cli->tree, fnum); + + status = smb_raw_rename(cli->tree, &ren_io); + CHECK_STATUS(status, NT_STATUS_OK); + + /* + * Now try just holding a second handle on the directory and holding + * it open across a rename. This should be allowed. + */ + io.ntcreatex.in.fname = dname2; + io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF; + + io.ntcreatex.in.access_mask = SEC_STD_READ_CONTROL | + SEC_FILE_READ_ATTRIBUTE | SEC_FILE_READ_EA | SEC_FILE_READ_DATA; + + status = smb_raw_open(cli->tree, tctx, &io); + CHECK_STATUS(status, NT_STATUS_OK); + fnum = io.ntcreatex.out.file.fnum; + + ren_io.generic.level = RAW_RENAME_RENAME; + ren_io.rename.in.pattern1 = dname2; + ren_io.rename.in.pattern2 = dname1; + ren_io.rename.in.attrib = 0; + + status = smb_raw_rename(cli->tree, &ren_io); + CHECK_STATUS(status, NT_STATUS_OK); + + /* close our handle to the directory. */ + smbcli_close(cli->tree, fnum); + + /* + * Now try opening a stream on the directory and holding it open + * across a rename. This should be allowed. + */ + io.ntcreatex.in.fname = sname; + + status = smb_raw_open(cli->tree, tctx, &io); + CHECK_STATUS(status, NT_STATUS_OK); + fnum = io.ntcreatex.out.file.fnum; + + ren_io.generic.level = RAW_RENAME_RENAME; + ren_io.rename.in.pattern1 = dname1; + ren_io.rename.in.pattern2 = dname2; + ren_io.rename.in.attrib = 0; + + status = smb_raw_rename(cli->tree, &ren_io); + CHECK_STATUS(status, NT_STATUS_OK); + done: if (fnum != -1) { |