예제 #1
0
파일: open.c 프로젝트: jophxy/samba
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;
	}
예제 #2
0
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) ));
		}