From 97fb05c2c0d0b08f3ed5aa7358a4d6d8c1725012 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 21 Nov 2008 12:14:53 -0800 Subject: First part of fix for bug #5903 - vfs_streams_xattr breaks contents of the file. Restructures parts of open code so that fsp must be allocated before calling open_file_ntcreate(_internal). Also fix up file ref-counting inside files.c. Jeremy. --- source3/smbd/close.c | 8 +-- source3/smbd/fake_file.c | 1 - source3/smbd/files.c | 74 +++++++++++------------- source3/smbd/open.c | 143 +++++++++++++++++++++++++++-------------------- source3/smbd/reply.c | 9 ++- 5 files changed, 126 insertions(+), 109 deletions(-) (limited to 'source3/smbd') diff --git a/source3/smbd/close.c b/source3/smbd/close.c index d4c531ab19..ce918ab6a3 100644 --- a/source3/smbd/close.c +++ b/source3/smbd/close.c @@ -106,8 +106,7 @@ static void check_magic(struct files_struct *fsp) static NTSTATUS close_filestruct(files_struct *fsp) { NTSTATUS status = NT_STATUS_OK; - connection_struct *conn = fsp->conn; - + if (fsp->fh->fd != -1) { if(flush_write_cache(fsp, CLOSE_FLUSH) == -1) { status = map_nt_error_from_unix(errno); @@ -115,9 +114,8 @@ static NTSTATUS close_filestruct(files_struct *fsp) delete_write_cache(fsp); } - conn->num_files_open--; return status; -} +} /**************************************************************************** If any deferred opens are waiting on this close, notify them. @@ -583,7 +581,7 @@ static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp, DEBUG(2,("%s closed file %s (numopen=%d) %s\n", conn->server_info->unix_name,fsp->fsp_name, - conn->num_files_open, + conn->num_files_open - 1, nt_errstr(status) )); file_free(req, fsp); diff --git a/source3/smbd/fake_file.c b/source3/smbd/fake_file.c index 58b09604c4..7feedcc9f9 100644 --- a/source3/smbd/fake_file.c +++ b/source3/smbd/fake_file.c @@ -141,7 +141,6 @@ NTSTATUS open_fake_file(struct smb_request *req, connection_struct *conn, return NT_STATUS_NO_MEMORY; } - conn->num_files_open++; *result = fsp; return NT_STATUS_OK; } diff --git a/source3/smbd/files.c b/source3/smbd/files.c index d3bfce7499..1a3a997e59 100644 --- a/source3/smbd/files.c +++ b/source3/smbd/files.c @@ -129,6 +129,8 @@ NTSTATUS file_new(struct smb_request *req, connection_struct *conn, ZERO_STRUCT(fsp_fi_cache); + conn->num_files_open++; + *result = fsp; return NT_STATUS_OK; } @@ -420,9 +422,7 @@ void file_free(struct smb_request *req, files_struct *fsp) DEBUG(5,("freed files structure %d (%d used)\n", fsp->fnum, files_used)); - /* this is paranoia, just in case someone tries to reuse the - information */ - ZERO_STRUCTP(fsp); + fsp->conn->num_files_open--; if ((req != NULL) && (fsp == req->chain_fsp)) { req->chain_fsp = NULL; @@ -438,6 +438,10 @@ void file_free(struct smb_request *req, files_struct *fsp) vfs_remove_fsp_extension(fsp->vfs_extension->owner, fsp); } + /* this is paranoia, just in case someone tries to reuse the + information */ + ZERO_STRUCTP(fsp); + SAFE_FREE(fsp); } @@ -484,46 +488,34 @@ files_struct *file_fsp(struct smb_request *req, uint16 fid) Duplicate the file handle part for a DOS or FCB open. ****************************************************************************/ -NTSTATUS dup_file_fsp(struct smb_request *req, files_struct *fsp, +void dup_file_fsp(struct smb_request *req, files_struct *from, uint32 access_mask, uint32 share_access, - uint32 create_options, files_struct **result) + uint32 create_options, files_struct *to) { - NTSTATUS status; - files_struct *dup_fsp; - - status = file_new(NULL, fsp->conn, &dup_fsp); - - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - SAFE_FREE(dup_fsp->fh); - - dup_fsp->fh = fsp->fh; - dup_fsp->fh->ref_count++; - - dup_fsp->file_id = fsp->file_id; - dup_fsp->initial_allocation_size = fsp->initial_allocation_size; - dup_fsp->mode = fsp->mode; - dup_fsp->file_pid = fsp->file_pid; - dup_fsp->vuid = fsp->vuid; - dup_fsp->open_time = fsp->open_time; - dup_fsp->access_mask = access_mask; - dup_fsp->share_access = share_access; - dup_fsp->oplock_type = fsp->oplock_type; - dup_fsp->can_lock = fsp->can_lock; - dup_fsp->can_read = (access_mask & (FILE_READ_DATA)) ? True : False; - if (!CAN_WRITE(fsp->conn)) { - dup_fsp->can_write = False; + SAFE_FREE(to->fh); + + to->fh = from->fh; + to->fh->ref_count++; + + to->file_id = from->file_id; + to->initial_allocation_size = from->initial_allocation_size; + to->mode = from->mode; + to->file_pid = from->file_pid; + to->vuid = from->vuid; + to->open_time = from->open_time; + to->access_mask = access_mask; + to->share_access = share_access; + to->oplock_type = from->oplock_type; + to->can_lock = from->can_lock; + to->can_read = (access_mask & (FILE_READ_DATA)) ? True : False; + if (!CAN_WRITE(from->conn)) { + to->can_write = False; } else { - dup_fsp->can_write = (access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) ? True : False; + to->can_write = (access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) ? True : False; } - dup_fsp->print_file = fsp->print_file; - dup_fsp->modified = fsp->modified; - dup_fsp->is_directory = fsp->is_directory; - dup_fsp->aio_write_behind = fsp->aio_write_behind; - string_set(&dup_fsp->fsp_name,fsp->fsp_name); - - *result = dup_fsp; - return NT_STATUS_OK; + to->print_file = from->print_file; + to->modified = from->modified; + to->is_directory = from->is_directory; + to->aio_write_behind = from->aio_write_behind; + string_set(&to->fsp_name,from->fsp_name); } diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 3fd0d1a03a..aca64917b5 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -462,7 +462,7 @@ static NTSTATUS open_file(files_struct *fsp, conn->server_info->unix_name, fsp->fsp_name, BOOLSTR(fsp->can_read), BOOLSTR(fsp->can_write), - conn->num_files_open + 1)); + conn->num_files_open)); errno = 0; return NT_STATUS_OK; @@ -951,9 +951,10 @@ static bool open_match_attributes(connection_struct *conn, Try and find a duplicated file handle. ****************************************************************************/ -static files_struct *fcb_or_dos_open(struct smb_request *req, +static NTSTATUS fcb_or_dos_open(struct smb_request *req, connection_struct *conn, - const char *fname, + files_struct *fsp_to_dup_into, + const char *fname, struct file_id id, uint16 file_pid, uint16 vuid, @@ -962,7 +963,6 @@ static files_struct *fcb_or_dos_open(struct smb_request *req, uint32 create_options) { files_struct *fsp; - files_struct *dup_fsp; DEBUG(5,("fcb_or_dos_open: attempting old open semantics for " "file %s.\n", fname )); @@ -991,23 +991,21 @@ static files_struct *fcb_or_dos_open(struct smb_request *req, } if (!fsp) { - return NULL; + return NT_STATUS_NOT_FOUND; } /* quite an insane set of semantics ... */ if (is_executable(fname) && (fsp->fh->private_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) { DEBUG(10,("fcb_or_dos_open: file fail due to is_executable.\n")); - return NULL; + return NT_STATUS_INVALID_PARAMETER; } /* We need to duplicate this fsp. */ - if (!NT_STATUS_IS_OK(dup_file_fsp(req, fsp, access_mask, share_access, - create_options, &dup_fsp))) { - return NULL; - } + dup_file_fsp(req, fsp, access_mask, share_access, + create_options, fsp_to_dup_into); - return dup_fsp; + return NT_STATUS_OK; } /**************************************************************************** @@ -1249,10 +1247,10 @@ static NTSTATUS calculate_access_mask(connection_struct *conn, } /**************************************************************************** - Open a file with a share mode. + Open a file with a share mode. Passed in an already created files_struct *. ****************************************************************************/ -NTSTATUS open_file_ntcreate(connection_struct *conn, +static NTSTATUS open_file_ntcreate_internal(connection_struct *conn, struct smb_request *req, const char *fname, SMB_STRUCT_STAT *psbuf, @@ -1264,7 +1262,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, int oplock_request, /* internal Samba oplock codes. */ /* Information (FILE_EXISTS etc.) */ int *pinfo, - files_struct **result) + files_struct *fsp) { int flags=0; int flags2=0; @@ -1274,7 +1272,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, bool new_file_created = False; struct file_id id; NTSTATUS fsp_open = NT_STATUS_ACCESS_DENIED; - files_struct *fsp = NULL; mode_t new_unx_mode = (mode_t)0; mode_t unx_mode = (mode_t)0; int info; @@ -1291,7 +1288,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, ZERO_STRUCT(id); if (conn->printer) { - /* + /* * Printers are handled completely differently. * Most of the passed parameters are ignored. */ @@ -1302,7 +1299,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, DEBUG(10, ("open_file_ntcreate: printer open fname=%s\n", fname)); - return print_fsp_open(req, conn, fname, req->vuid, result); + return print_fsp_open(req, conn, fname, req->vuid, fsp); } if (!parent_dirname_talloc(talloc_tos(), fname, &parent_dir, @@ -1366,7 +1363,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, status = check_name(conn, fname); if (!NT_STATUS_IS_OK(status)) { return status; - } + } if (!posix_open) { new_dos_attributes &= SAMBA_ATTRIBUTES_MASK; @@ -1533,7 +1530,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, flags2 |= O_SYNC; } #endif /* O_SYNC */ - + if (posix_open && (access_mask & FILE_APPEND_DATA)) { flags2 |= O_APPEND; } @@ -1560,11 +1557,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, return NT_STATUS_ACCESS_DENIED; } - status = file_new(req, conn, &fsp); - if(!NT_STATUS_IS_OK(status)) { - return status; - } - fsp->file_id = vfs_file_id_from_sbuf(conn, psbuf); fsp->share_access = share_access; fsp->fh->private_options = create_options; @@ -1589,7 +1581,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, fname, &old_write_time); if (lck == NULL) { - file_free(req, fsp); DEBUG(0, ("Could not get share mode lock\n")); return NT_STATUS_SHARING_VIOLATION; } @@ -1600,7 +1591,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, oplock_request)) { schedule_defer_open(lck, request_time, req); TALLOC_FREE(lck); - file_free(req, fsp); return NT_STATUS_SHARING_VIOLATION; } @@ -1620,7 +1610,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, oplock_request)) { schedule_defer_open(lck, request_time, req); TALLOC_FREE(lck); - file_free(req, fsp); return NT_STATUS_SHARING_VIOLATION; } } @@ -1628,7 +1617,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, if (NT_STATUS_EQUAL(status, NT_STATUS_DELETE_PENDING)) { /* DELETE_PENDING is not deferred for a second */ TALLOC_FREE(lck); - file_free(req, fsp); return status; } @@ -1643,33 +1631,31 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, if (create_options & (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS| NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) { - files_struct *fsp_dup; - if (req == NULL) { DEBUG(0, ("DOS open without an SMB " "request!\n")); TALLOC_FREE(lck); - file_free(req, fsp); return NT_STATUS_INTERNAL_ERROR; } /* Use the client requested access mask here, * not the one we open with. */ - fsp_dup = fcb_or_dos_open(req, conn, fname, id, - req->smbpid, - req->vuid, - access_mask, - share_access, - create_options); - - if (fsp_dup) { + status = fcb_or_dos_open(req, + conn, + fsp, + fname, + id, + req->smbpid, + req->vuid, + access_mask, + share_access, + create_options); + + if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(lck); - file_free(req, fsp); if (pinfo) { *pinfo = FILE_WAS_OPENED; } - conn->num_files_open++; - *result = fsp_dup; return NT_STATUS_OK; } } @@ -1697,7 +1683,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, can_access = False; } - /* + /* * If we're returning a share violation, ensure we * cope with the braindead 1 second delay. */ @@ -1750,7 +1736,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, } else { status = NT_STATUS_ACCESS_DENIED; } - file_free(req, fsp); return status; } @@ -1788,7 +1773,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, if (lck != NULL) { TALLOC_FREE(lck); } - file_free(req, fsp); return fsp_open; } @@ -1819,7 +1803,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, DEBUG(0, ("open_file_ntcreate: Could not get share " "mode lock for %s\n", fname)); fd_close(fsp); - file_free(req, fsp); return NT_STATUS_SHARING_VIOLATION; } @@ -1830,7 +1813,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, schedule_defer_open(lck, request_time, req); TALLOC_FREE(lck); fd_close(fsp); - file_free(req, fsp); return NT_STATUS_SHARING_VIOLATION; } @@ -1849,7 +1831,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, schedule_defer_open(lck, request_time, req); TALLOC_FREE(lck); fd_close(fsp); - file_free(req, fsp); return NT_STATUS_SHARING_VIOLATION; } } @@ -1858,7 +1839,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, struct deferred_open_record state; fd_close(fsp); - file_free(req, fsp); state.delayed_for_oplocks = False; state.id = id; @@ -1900,7 +1880,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, TALLOC_FREE(lck); fd_close(fsp); - file_free(req, fsp); return NT_STATUS_SHARING_VIOLATION; } @@ -1926,7 +1905,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, status = map_nt_error_from_unix(errno); TALLOC_FREE(lck); fd_close(fsp); - file_free(req, fsp); return status; } } @@ -1958,7 +1936,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, *pinfo = info; } - /* + /* * Setup the oplock info in both the shared memory and * file structs. */ @@ -1990,14 +1968,13 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, del_share_mode(lck, fsp); TALLOC_FREE(lck); fd_close(fsp); - file_free(req, fsp); return status; } /* Note that here we set the *inital* delete on close flag, not the regular one. The magic gets handled in close. */ fsp->initial_delete_on_close = True; } - + if (new_file_created) { /* Files should be initially set as archive */ if (lp_map_archive(SNUM(conn)) || @@ -2066,10 +2043,57 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, } TALLOC_FREE(lck); - conn->num_files_open++; + return NT_STATUS_OK; +} + +/**************************************************************************** + Open a file with a share mode. +****************************************************************************/ + +NTSTATUS open_file_ntcreate(connection_struct *conn, + struct smb_request *req, + const char *fname, + SMB_STRUCT_STAT *psbuf, + uint32 access_mask, /* access bits (FILE_READ_DATA etc.) */ + uint32 share_access, /* share constants (FILE_SHARE_READ etc) */ + uint32 create_disposition, /* FILE_OPEN_IF etc. */ + uint32 create_options, /* options such as delete on close. */ + uint32 new_dos_attributes, /* attributes used for new file. */ + int oplock_request, /* internal Samba oplock codes. */ + /* Information (FILE_EXISTS etc.) */ + int *pinfo, + files_struct **result) +{ + NTSTATUS status; + files_struct *fsp = NULL; + + *result = NULL; + + status = file_new(req, conn, &fsp); + if(!NT_STATUS_IS_OK(status)) { + return status; + } + + status = open_file_ntcreate_internal(conn, + req, + fname, + psbuf, + access_mask, + share_access, + create_disposition, + create_options, + new_dos_attributes, + oplock_request, + pinfo, + fsp); + + if(!NT_STATUS_IS_OK(status)) { + file_free(req, fsp); + return status; + } *result = fsp; - return NT_STATUS_OK; + return status; } /**************************************************************************** @@ -2097,10 +2121,9 @@ NTSTATUS open_file_fchmod(struct smb_request *req, connection_struct *conn, status = open_file(fsp, conn, NULL, NULL, NULL, fname, psbuf, O_WRONLY, 0, FILE_WRITE_DATA, FILE_WRITE_DATA); - /* + /* * This is not a user visible file open. - * Don't set a share mode and don't increment - * the conn->num_files_open. + * Don't set a share mode. */ if (!NT_STATUS_IS_OK(status)) { @@ -2431,8 +2454,6 @@ NTSTATUS open_directory(connection_struct *conn, *pinfo = info; } - conn->num_files_open++; - *result = fsp; return NT_STATUS_OK; } diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index c363ed5609..1f99db2de4 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -4558,8 +4558,15 @@ void reply_printopen(struct smb_request *req) return; } + status = file_new(req, conn, &fsp); + if(!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + END_PROFILE(SMBsplopen); + return; + } + /* Open for exclusive use, write only. */ - status = print_fsp_open(req, conn, NULL, req->vuid, &fsp); + status = print_fsp_open(req, conn, NULL, req->vuid, fsp); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); -- cgit