static BOOL check_share_mode(connection_struct *conn, share_mode_entry *share, int share_mode, uint32 desired_access, const char *fname, BOOL fcbopen, int *flags) { int deny_mode = GET_DENY_MODE(share_mode); int old_open_mode = GET_OPEN_MODE(share->share_mode); int old_deny_mode = GET_DENY_MODE(share->share_mode); /* * share modes = false means don't bother to check for * DENY mode conflict. This is a *really* bad idea :-). JRA. */ if(!lp_share_modes(SNUM(conn))) return True; /* * Don't allow any opens once the delete on close flag has been * set. */ if (GET_DELETE_ON_CLOSE_FLAG(share->share_mode)) { DEBUG(5,("check_share_mode: Failing open on file %s as delete on close flag is set.\n", fname )); /* Use errno to map to correct error. */ unix_ERR_class = SMB_SUCCESS; unix_ERR_code = 0; unix_ERR_ntstatus = NT_STATUS_OK; return False; } /* this is a nasty hack, but necessary until we rewrite our open handling to use a NTCreateX call as the basic call. NT may open a file with neither read nor write access, and in this case it expects the open not to conflict with any existing deny modes. This happens (for example) during a "xcopy /o" where the second file descriptor is used for ACL sets (tridge) */ /* * This is a bit wierd - the test for desired access not having the * critical bits seems seems odd. Firstly, if both opens have no * critical bits then always ignore. Then check the "allow delete" * then check for either. This probably isn't quite right yet but * gets us much closer. JRA. */ /* * If desired_access doesn't contain READ_DATA,WRITE_DATA,APPEND_DATA or EXECUTE * and the existing desired_acces then share modes don't conflict. */ if ( !(desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) && !(share->desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) ) { /* * Wrinkle discovered by smbtorture.... * If both are non-io open and requester is asking for delete and current open has delete access * but neither open has allowed file share delete then deny.... this is very strange and * seems to be the only case in which non-io opens conflict. JRA. */ if ((desired_access & DELETE_ACCESS) && (share->desired_access & DELETE_ACCESS) && (!GET_ALLOW_SHARE_DELETE(share->share_mode) || !GET_ALLOW_SHARE_DELETE(share_mode))) { DEBUG(5,("check_share_mode: Failing open on file %s as delete access requests conflict.\n", fname )); unix_ERR_class = ERRDOS; unix_ERR_code = ERRbadshare; unix_ERR_ntstatus = NT_STATUS_SHARING_VIOLATION; return False; } DEBUG(5,("check_share_mode: Allowing open on file %s as both desired access (0x%x) \ and existing desired access (0x%x) are non-data opens\n", fname, (unsigned int)desired_access, (unsigned int)share->desired_access )); return True; } /* * If delete access was requested and the existing share mode doesn't have * ALLOW_SHARE_DELETE then deny. */ if ((desired_access & DELETE_ACCESS) && !GET_ALLOW_SHARE_DELETE(share->share_mode)) { DEBUG(5,("check_share_mode: Failing open on file %s as delete access requested and allow share delete not set.\n", fname )); unix_ERR_class = ERRDOS; unix_ERR_code = ERRbadshare; unix_ERR_ntstatus = NT_STATUS_SHARING_VIOLATION; return False; } /* * The inverse of the above. * If delete access was granted and the new share mode doesn't have * ALLOW_SHARE_DELETE then deny. */ if ((share->desired_access & DELETE_ACCESS) && !GET_ALLOW_SHARE_DELETE(share_mode)) { DEBUG(5,("check_share_mode: Failing open on file %s as delete access granted and allow share delete not requested.\n", fname )); unix_ERR_class = ERRDOS; unix_ERR_code = ERRbadshare; unix_ERR_ntstatus = NT_STATUS_SHARING_VIOLATION; return False; } /* * If desired_access doesn't contain READ_DATA,WRITE_DATA,APPEND_DATA or EXECUTE * then share modes don't conflict. Likewise with existing desired access. */ if ( !(desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) || !(share->desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) ) { DEBUG(5,("check_share_mode: Allowing open on file %s as desired access (0x%x) doesn't conflict with\ existing desired access (0x%x).\n", fname, (unsigned int)desired_access, (unsigned int)share->desired_access )); return True; }
static int close_normal_file(files_struct *fsp, BOOL normal_close) { share_mode_entry *share_entry = NULL; size_t share_entry_count = 0; BOOL delete_on_close = False; connection_struct *conn = fsp->conn; int err = 0; int err1 = 0; remove_pending_lock_requests_by_fid(fsp); /* * If we're flushing on a close we can get a write * error here, we must remember this. */ if (close_filestruct(fsp) == -1) err1 = -1; if (fsp->print_file) { print_fsp_end(fsp, normal_close); file_free(fsp); return 0; } /* * Lock the share entries, and determine if we should delete * on close. If so delete whilst the lock is still in effect. * This prevents race conditions with the file being created. JRA. */ lock_share_entry_fsp(fsp); if (fsp->delete_on_close) { /* * Modify the share mode entry for all files open * on this device and inode to tell other smbds we have * changed the delete on close flag. The last closer will delete the file * if flag is set. */ NTSTATUS status =set_delete_on_close_over_all(fsp, fsp->delete_on_close); if (NT_STATUS_V(status) != NT_STATUS_V(NT_STATUS_OK)) DEBUG(0,("close_normal_file: failed to change delete on close flag for file %s\n", fsp->fsp_name )); } share_entry_count = del_share_mode(fsp, &share_entry); DEBUG(10,("close_normal_file: share_entry_count = %lu for file %s\n", (unsigned long)share_entry_count, fsp->fsp_name )); /* * We delete on close if it's the last open, and the * delete on close flag was set in the entry we just deleted. */ if ((share_entry_count == 0) && share_entry && GET_DELETE_ON_CLOSE_FLAG(share_entry->share_mode) ) delete_on_close = True; SAFE_FREE(share_entry); /* * NT can set delete_on_close of the last open * reference to a file. */ if (normal_close && delete_on_close) { DEBUG(5,("close_file: file %s. Delete on close was set - deleting file.\n", fsp->fsp_name)); if(SMB_VFS_UNLINK(conn,fsp->fsp_name) != 0) { /* * This call can potentially fail as another smbd may have * had the file open with delete on close set and deleted * it when its last reference to this file went away. Hence * we log this but not at debug level zero. */ DEBUG(5,("close_file: file %s. Delete on close was set and unlink failed \ with error %s\n", fsp->fsp_name, strerror(errno) )); }