From ebf9ecd31a1f69b069398cbdadccf4a311a6e306 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 27 Sep 2005 17:42:11 +0000 Subject: r10551: We need to check if the source path is a parent directory of the destination (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must refuse the rename with a sharing violation. Under UNIX the above call can *succeed* if /foo/bar/baz is a symlink to another area in the share. We probably need to check that the client is a Windows one before disallowing this as a UNIX client (one with UNIX extensions) can know the source is a symlink and make this decision intelligently. Found by an excellent bug report from . Jeremy. --- source/smbd/reply.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'source/smbd') diff --git a/source/smbd/reply.c b/source/smbd/reply.c index 2d9a31032ba..5572f47e427 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -4075,6 +4075,35 @@ static void rename_open_files(connection_struct *conn, SMB_DEV_T dev, SMB_INO_T (unsigned int)dev, (double)inode, newname )); } +/**************************************************************************** + We need to check if the source path is a parent directory of the destination + (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must + refuse the rename with a sharing violation. Under UNIX the above call can + *succeed* if /foo/bar/baz is a symlink to another area in the share. We + probably need to check that the client is a Windows one before disallowing + this as a UNIX client (one with UNIX extensions) can know the source is a + symlink and make this decision intelligently. Found by an excellent bug + report from . +****************************************************************************/ + +static BOOL rename_path_prefix_equal(const char *src, const char *dest) +{ + const char *psrc = src; + const char *pdst = dest; + size_t slen; + + if (psrc[0] == '.' && psrc[1] == '/') { + psrc += 2; + } + if (pdst[0] == '.' && pdst[1] == '/') { + pdst += 2; + } + if ((slen = strlen(psrc)) > strlen(pdst)) { + return False; + } + return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/'); +} + /**************************************************************************** Rename an open file - given an fsp. ****************************************************************************/ @@ -4170,6 +4199,10 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char * return error; } + if (rename_path_prefix_equal(fsp->fsp_name, newname)) { + return NT_STATUS_ACCESS_DENIED; + } + if(SMB_VFS_RENAME(conn,fsp->fsp_name, newname) == 0) { DEBUG(3,("rename_internals_fsp: succeeded doing rename on %s -> %s\n", fsp->fsp_name,newname)); @@ -4391,6 +4424,10 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n", return NT_STATUS_OBJECT_NAME_COLLISION; } + if (rename_path_prefix_equal(directory, newname)) { + return NT_STATUS_SHARING_VIOLATION; + } + if(SMB_VFS_RENAME(conn,directory, newname) == 0) { DEBUG(3,("rename_internals: succeeded doing rename on %s -> %s\n", directory,newname)); @@ -4489,6 +4526,10 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n", continue; } + if (rename_path_prefix_equal(fname, destname)) { + return NT_STATUS_SHARING_VIOLATION; + } + if (!SMB_VFS_RENAME(conn,fname,destname)) { rename_open_files(conn, sbuf1.st_dev, sbuf1.st_ino, newname); count++; -- cgit