mirror of
https://github.com/samba-team/samba.git
synced 2025-10-07 03:33:18 +03:00
smbd: Return NT_STATUS_STOPPED_ON_SYMLINK
Do this for "follow symlinks = now" and smb2 unix extensions Signed-off-by: Volker Lendecke <vl@samba.org> Reviewed-by: Ralph Boehme <slow@samba.org>
This commit is contained in:
committed by
Ralph Boehme
parent
cc0ed15fec
commit
34be8ef596
@@ -1,4 +0,0 @@
|
||||
^samba.tests.smb2symlink.samba.tests.smb2symlink.Smb2SymlinkTests.test_symlinkerror_directory
|
||||
^samba.tests.smb2symlink.samba.tests.smb2symlink.Smb2SymlinkTests.test_symlinkerror_file
|
||||
^samba.tests.smb2symlink.samba.tests.smb2symlink.Smb2SymlinkTests.test_symlinkerror_absolute_outside_share
|
||||
^samba.tests.smb2symlink.samba.tests.smb2symlink.Smb2SymlinkTests.test_symlinkerror_absolute_inshare
|
@@ -1343,11 +1343,17 @@ EOF
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "$out" | grep 'NT_STATUS_OBJECT_NAME_NOT_FOUND'
|
||||
if [ "$PROTOCOL" = "SMB3" ]; then
|
||||
expected_error="NT_STATUS_STOPPED_ON_SYMLINK"
|
||||
else
|
||||
expected_error="NT_STATUS_OBJECT_NAME_NOT_FOUND"
|
||||
fi
|
||||
|
||||
echo "$out" | grep "$expected_error"
|
||||
ret=$?
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo "$out"
|
||||
echo "failed - should get NT_STATUS_OBJECT_NAME_NOT_FOUND getting \\nosymlinks\\source"
|
||||
echo "failed - should get ${expected_error} getting \\nosymlinks\\source"
|
||||
return 1
|
||||
fi
|
||||
|
||||
|
@@ -41,11 +41,7 @@ uint32_t ucf_flags_from_smb_request(struct smb_request *req)
|
||||
}
|
||||
|
||||
if (req->posix_pathnames) {
|
||||
ucf_flags |= UCF_POSIX_PATHNAMES;
|
||||
|
||||
if (!conn_using_smb2(req->sconn)) {
|
||||
ucf_flags |= UCF_LCOMP_LNK_OK;
|
||||
}
|
||||
ucf_flags |= (UCF_POSIX_PATHNAMES|UCF_LCOMP_LNK_OK);
|
||||
}
|
||||
if (req->flags2 & FLAGS2_DFS_PATHNAMES) {
|
||||
ucf_flags |= UCF_DFS_PATHNAME;
|
||||
|
@@ -1216,17 +1216,6 @@ static NTSTATUS open_file(
|
||||
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (S_ISLNK(smb_fname->st.st_ex_mode) &&
|
||||
!posix_open)
|
||||
{
|
||||
/*
|
||||
* Don't allow stat opens on symlinks directly unless
|
||||
* it's a POSIX open. Match the return code from
|
||||
* openat_pathref_fsp().
|
||||
*/
|
||||
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (!fsp->fsp_flags.is_pathref) {
|
||||
/*
|
||||
* There is only one legit case where end up here:
|
||||
@@ -1236,11 +1225,6 @@ static NTSTATUS open_file(
|
||||
* pathref fsp at this point. The subsequent checks
|
||||
* assert this.
|
||||
*/
|
||||
if (!(smb_fname->flags & SMB_FILENAME_POSIX_PATH)) {
|
||||
DBG_ERR("[%s] is not a POSIX pathname\n",
|
||||
smb_fname_str_dbg(smb_fname));
|
||||
return NT_STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
if (!S_ISLNK(smb_fname->st.st_ex_mode)) {
|
||||
DBG_ERR("[%s] is not a symlink\n",
|
||||
smb_fname_str_dbg(smb_fname));
|
||||
@@ -1290,13 +1274,19 @@ static NTSTATUS open_file(
|
||||
fsp->file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
|
||||
fsp->vuid = req ? req->vuid : UID_FIELD_INVALID;
|
||||
fsp->file_pid = req ? req->smbpid : 0;
|
||||
fsp->fsp_flags.can_lock = true;
|
||||
fsp->fsp_flags.can_read = ((access_mask & FILE_READ_DATA) != 0);
|
||||
fsp->fsp_flags.can_write =
|
||||
CAN_WRITE(conn) &&
|
||||
((access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0);
|
||||
if (fsp->fsp_name->twrp != 0) {
|
||||
if (file_existed && S_ISLNK(smb_fname->st.st_ex_mode)) {
|
||||
fsp->fsp_flags.can_lock = false;
|
||||
fsp->fsp_flags.can_read = false;
|
||||
fsp->fsp_flags.can_write = false;
|
||||
} else {
|
||||
fsp->fsp_flags.can_lock = true;
|
||||
fsp->fsp_flags.can_read = ((access_mask & FILE_READ_DATA) !=
|
||||
0);
|
||||
fsp->fsp_flags.can_write = CAN_WRITE(conn) &&
|
||||
((access_mask &
|
||||
(FILE_WRITE_DATA |
|
||||
FILE_APPEND_DATA)) != 0) &&
|
||||
(fsp->fsp_name->twrp == 0);
|
||||
}
|
||||
fsp->print_file = NULL;
|
||||
fsp->fsp_flags.modified = false;
|
||||
|
@@ -479,7 +479,9 @@ static void smbd_smb2_request_create_done(struct tevent_req *tsubreq)
|
||||
if (smbd_smb2_is_compound(smb2req)) {
|
||||
smb2req->compound_create_err = status;
|
||||
}
|
||||
error = smbd_smb2_create_error(smb2req, status, NULL);
|
||||
error = smbd_smb2_create_error(smb2req,
|
||||
status,
|
||||
symlink_reparse);
|
||||
if (!NT_STATUS_IS_OK(error)) {
|
||||
smbd_server_connection_terminate(smb2req->xconn,
|
||||
nt_errstr(error));
|
||||
@@ -732,6 +734,9 @@ struct smbd_smb2_create_state {
|
||||
uint64_t out_file_id_persistent;
|
||||
uint64_t out_file_id_volatile;
|
||||
struct smb2_create_blobs *out_context_blobs;
|
||||
|
||||
/* symlink error data */
|
||||
struct reparse_data_buffer *symlink_err;
|
||||
};
|
||||
|
||||
static void smbd_smb2_create_purge_replay_cache(struct tevent_req *req,
|
||||
@@ -1187,14 +1192,42 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
|
||||
state->in_create_disposition,
|
||||
state->in_create_options);
|
||||
|
||||
status = filename_convert_dirfsp(
|
||||
req,
|
||||
if (lp_follow_symlinks(SNUM(smb1req->conn)) &&
|
||||
(state->posx == NULL)) {
|
||||
status = filename_convert_dirfsp(mem_ctx,
|
||||
smb1req->conn,
|
||||
state->fname,
|
||||
ucf_flags,
|
||||
state->twrp_time,
|
||||
&dirfsp,
|
||||
&smb_fname);
|
||||
} else {
|
||||
struct smb_filename *smb_fname_rel = NULL;
|
||||
|
||||
status = filename_convert_dirfsp_nosymlink(
|
||||
mem_ctx,
|
||||
smb1req->conn,
|
||||
smb1req->conn->cwd_fsp,
|
||||
state->fname,
|
||||
ucf_flags,
|
||||
state->twrp_time,
|
||||
&dirfsp,
|
||||
&smb_fname,
|
||||
&smb_fname_rel,
|
||||
&state->symlink_err);
|
||||
TALLOC_FREE(smb_fname_rel);
|
||||
|
||||
if ((state->symlink_err != NULL) &&
|
||||
!(state->in_create_options & FILE_OPEN_REPARSE_POINT))
|
||||
{
|
||||
if (dirfsp != NULL) {
|
||||
close_file_free(NULL, &dirfsp, ERROR_CLOSE);
|
||||
}
|
||||
TALLOC_FREE(smb_fname);
|
||||
TALLOC_FREE(smb_fname_rel);
|
||||
status = NT_STATUS_STOPPED_ON_SYMLINK;
|
||||
}
|
||||
}
|
||||
if (tevent_req_nterror(req, status)) {
|
||||
return tevent_req_post(req, state->ev);
|
||||
}
|
||||
@@ -1636,6 +1669,56 @@ static void smbd_smb2_create_after_exec(struct tevent_req *req)
|
||||
|
||||
state->out_file_attributes = fdos_mode(state->result);
|
||||
|
||||
if ((state->out_file_attributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
|
||||
(!(state->in_create_options & FILE_OPEN_REPARSE_POINT)))
|
||||
{
|
||||
|
||||
uint32_t tag;
|
||||
uint8_t *data = NULL;
|
||||
uint32_t len = 0;
|
||||
|
||||
status = fsctl_get_reparse_point(
|
||||
state->result, talloc_tos(), &tag, &data, 65536, &len);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (tag != IO_REPARSE_TAG_SYMLINK) {
|
||||
status = NT_STATUS_IO_REPARSE_TAG_NOT_HANDLED;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
state->symlink_err = talloc_zero(state,
|
||||
struct reparse_data_buffer);
|
||||
if (state->symlink_err == NULL) {
|
||||
TALLOC_FREE(data);
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
status = reparse_data_buffer_parse(state->symlink_err,
|
||||
state->symlink_err,
|
||||
data,
|
||||
len);
|
||||
TALLOC_FREE(data);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DBG_DEBUG("reparse_data_buffer_parse failed: %s\n",
|
||||
nt_errstr(status));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checked above, just to make sure
|
||||
*/
|
||||
SMB_ASSERT(state->symlink_err->tag == IO_REPARSE_TAG_SYMLINK);
|
||||
|
||||
DBG_DEBUG("Redirecting to %s\n",
|
||||
state->symlink_err->parsed.lnk.substitute_name);
|
||||
|
||||
status = NT_STATUS_STOPPED_ON_SYMLINK;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (state->mxac != NULL) {
|
||||
NTTIME last_write_time;
|
||||
|
||||
@@ -1919,11 +2002,57 @@ static NTSTATUS smbd_smb2_create_recv(struct tevent_req *req,
|
||||
struct smb2_create_blobs *out_context_blobs,
|
||||
struct reparse_data_buffer **symlink_reparse)
|
||||
{
|
||||
NTSTATUS status;
|
||||
NTSTATUS status = NT_STATUS_OK;
|
||||
struct smbd_smb2_create_state *state = tevent_req_data(req,
|
||||
struct smbd_smb2_create_state);
|
||||
bool error;
|
||||
|
||||
if (tevent_req_is_nterror(req, &status)) {
|
||||
error = tevent_req_is_nterror(req, &status);
|
||||
|
||||
if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
|
||||
struct symlink_reparse_struct *lnk = &state->symlink_err
|
||||
->parsed.lnk;
|
||||
size_t fname_len = strlen(state->fname);
|
||||
|
||||
/*
|
||||
* filename_convert_dirfsp_nosymlink() calculates
|
||||
* unparsed_path_length. Just assert it did not mess up big
|
||||
* time.
|
||||
*/
|
||||
SMB_ASSERT(lnk->unparsed_path_length <= fname_len);
|
||||
|
||||
if (lnk->unparsed_path_length != 0) {
|
||||
bool ok;
|
||||
char *unparsed_unix = NULL;
|
||||
char *utf_16 = NULL;
|
||||
size_t utf_16_len;
|
||||
|
||||
unparsed_unix = state->fname + fname_len -
|
||||
lnk->unparsed_path_length;
|
||||
|
||||
ok = convert_string_talloc(talloc_tos(),
|
||||
CH_UNIX,
|
||||
CH_UTF16,
|
||||
unparsed_unix,
|
||||
lnk->unparsed_path_length,
|
||||
&utf_16,
|
||||
&utf_16_len);
|
||||
if (!ok) {
|
||||
tevent_req_received(req);
|
||||
return NT_STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
TALLOC_FREE(utf_16);
|
||||
|
||||
if (utf_16_len > UINT16_MAX) {
|
||||
tevent_req_received(req);
|
||||
return NT_STATUS_BUFFER_OVERFLOW;
|
||||
}
|
||||
lnk->unparsed_path_length = utf_16_len;
|
||||
}
|
||||
*symlink_reparse = talloc_move(mem_ctx, &state->symlink_err);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
tevent_req_received(req);
|
||||
return status;
|
||||
}
|
||||
|
Reference in New Issue
Block a user