From 8c363e9252cfaeb1a7d30870e3a0d44cb9d8a39b Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 8 Feb 2011 17:04:19 -0800 Subject: Move to opening an fd on directory opens. Get more careful about symlink races. --- source3/smbd/open.c | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) (limited to 'source3') diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 2379b8ebb2..89d137506b 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -2524,6 +2524,22 @@ static NTSTATUS mkdir_internal(connection_struct *conn, return NT_STATUS_OK; } +/**************************************************************************** + Ensure we didn't get symlink raced on opening a directory. +****************************************************************************/ + +static bool check_same_stat(const SMB_STRUCT_STAT *sbuf1, + const SMB_STRUCT_STAT *sbuf2) +{ + if (sbuf1->st_ex_uid != sbuf2->st_ex_uid || + sbuf1->st_ex_gid != sbuf2->st_ex_gid || + sbuf1->st_ex_dev != sbuf2->st_ex_dev || + sbuf1->st_ex_ino != sbuf2->st_ex_ino) { + return false; + } + return true; +} + /**************************************************************************** Open a directory from an NT SMB call. ****************************************************************************/ @@ -2726,6 +2742,10 @@ static NTSTATUS open_directory(connection_struct *conn, #ifdef O_DIRECTORY status = fd_open(conn, fsp, O_RDONLY|O_DIRECTORY, 0); +#else + /* POSIX allows us to open a directory with O_RDONLY. */ + status = fd_open(conn, fsp, O_RDONLY, 0); +#endif if (!NT_STATUS_IS_OK(status)) { DEBUG(5, ("open_directory: Could not open fd for " "%s (%s)\n", @@ -2734,7 +2754,23 @@ static NTSTATUS open_directory(connection_struct *conn, file_free(req, fsp); return status; } -#endif + + status = vfs_stat_fsp(fsp); + if (NT_STATUS_IS_OK(status)) { + fd_close(fsp); + file_free(req, fsp); + return status; + } + + /* Ensure there was no race condition. */ + if (!check_same_stat(&smb_dname->st, &fsp->fsp_name->st)) { + DEBUG(5,("open_directory: stat struct differs for " + "directory %s.\n", + smb_fname_str_dbg(smb_dname))); + fd_close(fsp); + file_free(req, fsp); + return NT_STATUS_ACCESS_DENIED; + } lck = get_share_mode_lock(talloc_tos(), fsp->file_id, conn->connectpath, smb_dname, &mtimespec); -- cgit