From: Ralph Boehme Date: Tue, 2 Feb 2021 10:18:54 +0000 (+0100) Subject: smbd: don't return NT_STATUS_STOPPED_ON_SYMLINK in openat_pathref_fsp() X-Git-Tag: tevent-0.11.0~1820 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=977f37643b223e164fbbf6c3ba1d37aa546ddb7d;p=thirdparty%2Fsamba.git smbd: don't return NT_STATUS_STOPPED_ON_SYMLINK in openat_pathref_fsp() NT_STATUS_STOPPED_ON_SYMLINK is returned when trying to open a symlink, most callers are not interested in this. Some callers that would want to know whether openat_pathref_fsp() failed specifically on a symlink are setup_close_full_information(), smbd_dirptr_get_entry(), unlink_internals() and filename_convert_internal(), so we fix those callers to handle the symlink case themselves. Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison --- diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c index d7b1363205c..9d5244e3c4e 100644 --- a/source3/smbd/dir.c +++ b/source3/smbd/dir.c @@ -936,44 +936,25 @@ bool smbd_dirptr_get_entry(TALLOC_CTX *ctx, */ status = openat_pathref_fsp(dirptr->dir_hnd->fsp, atname); if (!NT_STATUS_IS_OK(status) && - !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) && - !NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) + !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { TALLOC_FREE(atname); TALLOC_FREE(dname); TALLOC_FREE(fname); TALLOC_FREE(smb_fname); continue; - } else if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) { + } else if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { if (!(atname->flags & SMB_FILENAME_POSIX_PATH)) { - TALLOC_FREE(atname); - TALLOC_FREE(dname); - TALLOC_FREE(fname); - TALLOC_FREE(smb_fname); - continue; + check_dfs_symlink = true; } /* - * It's a symlink, disable getting dosmode in the - * mode_fn() and prime the mode as - * FILE_ATTRIBUTE_NORMAL. + * Check if it's a symlink. We only want to return this + * if it's a DFS symlink or in POSIX mode. Disable + * getting dosmode in the mode_fn() and prime the mode + * as FILE_ATTRIBUTE_NORMAL. */ mode = FILE_ATTRIBUTE_NORMAL; get_dosmode = false; - } else if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { - if (atname->flags & SMB_FILENAME_POSIX_PATH) { - TALLOC_FREE(atname); - TALLOC_FREE(dname); - TALLOC_FREE(fname); - TALLOC_FREE(smb_fname); - continue; - } - /* - * Likely a dangling symlink. We only want to return - * this if it's a DFS symlink, so we need to check for - * that. Set get_dosmode to skip getting dosmode. - */ - get_dosmode = false; - check_dfs_symlink = true; } status = move_smb_fname_fsp_link(smb_fname, atname); diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c index 184a293f205..9035c7e82c7 100644 --- a/source3/smbd/filename.c +++ b/source3/smbd/filename.c @@ -1982,14 +1982,9 @@ static NTSTATUS filename_convert_internal(TALLOC_CTX *ctx, } status = openat_pathref_fsp(conn->cwd_fsp, smb_fname); - if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) { + if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { /* - * Don't leak NT_STATUS_STOPPED_ON_SYMLINK into the callers: - * it's a special SMB2 error that needs an extended SMB2 error - * response. We don't support that for SMB2 and it doesn't exist - * at all in SMB1. - * - * So we deal with symlinks here as we do in + * We deal with symlinks here as we do in * SMB_VFS_CREATE_FILE(): return success for POSIX clients with * the notable difference that there will be no fsp in * smb_fname->fsp. @@ -1997,10 +1992,10 @@ static NTSTATUS filename_convert_internal(TALLOC_CTX *ctx, * For Windows (non POSIX) clients fail with * NT_STATUS_OBJECT_NAME_NOT_FOUND. */ - if (ucf_flags & UCF_POSIX_PATHNAMES) { + if (smb_fname->flags & SMB_FILENAME_POSIX_PATH && + S_ISLNK(smb_fname->st.st_ex_mode)) + { status = NT_STATUS_OK; - } else { - status = NT_STATUS_OBJECT_NAME_NOT_FOUND; } } if (!NT_STATUS_IS_OK(status)) { diff --git a/source3/smbd/files.c b/source3/smbd/files.c index e3e02e5dad1..83ccb332bf4 100644 --- a/source3/smbd/files.c +++ b/source3/smbd/files.c @@ -456,7 +456,7 @@ NTSTATUS openat_pathref_fsp(const struct files_struct *dirfsp, } if (S_ISLNK(smb_fname->st.st_ex_mode)) { - return NT_STATUS_STOPPED_ON_SYMLINK; + return NT_STATUS_OBJECT_NAME_NOT_FOUND; } status = fsp_new(conn, conn, &fsp); @@ -503,7 +503,8 @@ NTSTATUS openat_pathref_fsp(const struct files_struct *dirfsp, status = fd_openat(dirfsp, smb_fname, fsp, open_flags, 0); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND) || - NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_NOT_FOUND)) + NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_NOT_FOUND) || + NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) { /* * streams_xattr return NT_STATUS_NOT_FOUND for @@ -515,6 +516,10 @@ NTSTATUS openat_pathref_fsp(const struct files_struct *dirfsp, * * NT_STATUS_OBJECT_NAME_NOT_FOUND is the simple * ENOENT case. + * + * NT_STATUS_STOPPED_ON_SYMLINK is returned when trying + * to open a symlink, our callers are not interested in + * this. */ status = NT_STATUS_OBJECT_NAME_NOT_FOUND; } diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index a09e11e8493..c9820df2bb5 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -3468,9 +3468,13 @@ NTSTATUS unlink_internals(connection_struct *conn, } status = openat_pathref_fsp(conn->cwd_fsp, f); - if (!NT_STATUS_IS_OK(status) && - !NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) + if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) && + (f->flags & SMB_FILENAME_POSIX_PATH) && + S_ISLNK(f->st.st_ex_mode)) { + status = NT_STATUS_OK; + } + if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(dir_hnd); TALLOC_FREE(frame); TALLOC_FREE(talloced); diff --git a/source3/smbd/smb2_close.c b/source3/smbd/smb2_close.c index 229b41cd91c..5948ba95a5d 100644 --- a/source3/smbd/smb2_close.c +++ b/source3/smbd/smb2_close.c @@ -167,7 +167,10 @@ static void setup_close_full_information(connection_struct *conn, int ret; status = openat_pathref_fsp(conn->cwd_fsp, smb_fname); - if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) { + if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) && + (smb_fname->flags & SMB_FILENAME_POSIX_PATH) && + S_ISLNK(smb_fname->st.st_ex_mode)) + { status = NT_STATUS_OK; } if (!NT_STATUS_IS_OK(status)) {