diff options
-rw-r--r-- | source3/include/proto.h | 4 | ||||
-rw-r--r-- | source3/smbd/nttrans.c | 2 | ||||
-rw-r--r-- | source3/smbd/trans2.c | 104 |
3 files changed, 104 insertions, 6 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h index 154efeb43b..3deeb9fa2f 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -6368,8 +6368,10 @@ void send_trans2_replies(connection_struct *conn, unsigned char *create_volume_objectid(connection_struct *conn, unsigned char objid[16]); NTSTATUS hardlink_internals(TALLOC_CTX *ctx, connection_struct *conn, + struct smb_request *req, + bool overwrite_if_exists, const struct smb_filename *smb_fname_old, - const struct smb_filename *smb_fname_new); + struct smb_filename *smb_fname_new); NTSTATUS smb_set_file_time(connection_struct *conn, files_struct *fsp, const struct smb_filename *smb_fname, diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index b42d665668..9b4d38a904 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -1550,6 +1550,8 @@ void reply_ntrename(struct smb_request *req) status = NT_STATUS_OBJECT_PATH_SYNTAX_BAD; } else { status = hardlink_internals(ctx, conn, + req, + false, smb_fname_old, smb_fname_new); } diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 56d22b37bb..dec9d7f8f9 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -5348,8 +5348,10 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd NTSTATUS hardlink_internals(TALLOC_CTX *ctx, connection_struct *conn, + struct smb_request *req, + bool overwrite_if_exists, const struct smb_filename *smb_fname_old, - const struct smb_filename *smb_fname_new) + struct smb_filename *smb_fname_new) { NTSTATUS status = NT_STATUS_OK; @@ -5358,9 +5360,23 @@ NTSTATUS hardlink_internals(TALLOC_CTX *ctx, return NT_STATUS_OBJECT_NAME_NOT_FOUND; } - /* Disallow if newname already exists. */ if (VALID_STAT(smb_fname_new->st)) { - return NT_STATUS_OBJECT_NAME_COLLISION; + if (overwrite_if_exists) { + if (S_ISDIR(smb_fname_new->st.st_ex_mode)) { + return NT_STATUS_FILE_IS_A_DIRECTORY; + } + status = unlink_internals(conn, + req, + FILE_ATTRIBUTE_NORMAL, + smb_fname_new, + false); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + } else { + /* Disallow if newname already exists. */ + return NT_STATUS_OBJECT_NAME_COLLISION; + } } /* No links from a directory. */ @@ -5870,7 +5886,7 @@ static NTSTATUS smb_set_file_unix_link(connection_struct *conn, static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn, struct smb_request *req, const char *pdata, int total_data, - const struct smb_filename *smb_fname_new) + struct smb_filename *smb_fname_new) { char *oldname = NULL; struct smb_filename *smb_fname_old = NULL; @@ -5902,7 +5918,8 @@ static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn, return status; } - return hardlink_internals(ctx, conn, smb_fname_old, smb_fname_new); + return hardlink_internals(ctx, conn, req, false, + smb_fname_old, smb_fname_new); } /**************************************************************************** @@ -6006,6 +6023,75 @@ static NTSTATUS smb2_file_rename_information(connection_struct *conn, return status; } +static NTSTATUS smb_file_link_information(connection_struct *conn, + struct smb_request *req, + const char *pdata, + int total_data, + files_struct *fsp, + struct smb_filename *smb_fname_src) +{ + bool overwrite; + uint32_t len; + char *newname = NULL; + struct smb_filename *smb_fname_dst = NULL; + NTSTATUS status = NT_STATUS_OK; + TALLOC_CTX *ctx = talloc_tos(); + + if (!fsp) { + return NT_STATUS_INVALID_HANDLE; + } + + if (total_data < 20) { + return NT_STATUS_INVALID_PARAMETER; + } + + overwrite = (CVAL(pdata,0) ? true : false); + len = IVAL(pdata,16); + + if (len > (total_data - 20) || (len == 0)) { + return NT_STATUS_INVALID_PARAMETER; + } + + srvstr_get_path(ctx, pdata, req->flags2, &newname, + &pdata[20], len, STR_TERMINATE, + &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + DEBUG(10,("smb_file_link_information: got name |%s|\n", + newname)); + + status = filename_convert(ctx, + conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + newname, + 0, + NULL, + &smb_fname_dst); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (fsp->base_fsp) { + /* No stream names. */ + return NT_STATUS_NOT_SUPPORTED; + } + + DEBUG(10,("smb_file_link_information: " + "SMB_FILE_LINK_INFORMATION (fnum %d) %s -> %s\n", + fsp->fnum, fsp_str_dbg(fsp), + smb_fname_str_dbg(smb_fname_dst))); + status = hardlink_internals(ctx, + conn, + req, + overwrite, + fsp->fsp_name, + smb_fname_dst); + + TALLOC_FREE(smb_fname_dst); + return status; +} /**************************************************************************** Deal with SMB_FILE_RENAME_INFORMATION. @@ -7609,6 +7695,14 @@ NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn, break; } + case SMB_FILE_LINK_INFORMATION: + { + status = smb_file_link_information(conn, req, + pdata, total_data, + fsp, smb_fname); + break; + } + #if defined(HAVE_POSIX_ACLS) case SMB_SET_POSIX_ACL: { |