⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 open.c

📁 samba-3.0.22.tar.gz 编译smb服务器的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/*    Unix SMB/CIFS implementation.   file opening and share modes   Copyright (C) Andrew Tridgell 1992-1998   Copyright (C) Jeremy Allison 2001-2004   Copyright (C) Volker Lendecke 2005      This program is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 2 of the License, or   (at your option) any later version.      This program is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.      You should have received a copy of the GNU General Public License   along with this program; if not, write to the Free Software   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include "includes.h"extern struct current_user current_user;extern userdom_struct current_user_info;extern uint16 global_smbpid;extern BOOL global_client_failed_oplock_break;struct deferred_open_record {	BOOL delayed_for_oplocks;	SMB_DEV_T dev;	SMB_INO_T inode;};/**************************************************************************** fd support routines - attempt to do a dos_open.****************************************************************************/static int fd_open(struct connection_struct *conn,			const char *fname, 			int flags,			mode_t mode){	int fd;#ifdef O_NOFOLLOW	if (!lp_symlinks(SNUM(conn))) {		flags |= O_NOFOLLOW;	}#endif	fd = SMB_VFS_OPEN(conn,fname,flags,mode);	DEBUG(10,("fd_open: name %s, flags = 0%o mode = 0%o, fd = %d. %s\n", fname,		flags, (int)mode, fd, (fd == -1) ? strerror(errno) : "" ));	return fd;}/**************************************************************************** Close the file associated with a fsp.****************************************************************************/int fd_close(struct connection_struct *conn,		files_struct *fsp){	if (fsp->fh->fd == -1) {		return 0; /* What we used to call a stat open. */	}	if (fsp->fh->ref_count > 1) {		return 0; /* Shared handle. Only close last reference. */	}	return fd_close_posix(conn, fsp);}/**************************************************************************** Change the ownership of a file to that of the parent directory. Do this by fd if possible.****************************************************************************/void change_owner_to_parent(connection_struct *conn,				files_struct *fsp,				const char *fname,				SMB_STRUCT_STAT *psbuf){	const char *parent_path = parent_dirname(fname);	SMB_STRUCT_STAT parent_st;	int ret;	ret = SMB_VFS_STAT(conn, parent_path, &parent_st);	if (ret == -1) {		DEBUG(0,("change_owner_to_parent: failed to stat parent "			 "directory %s. Error was %s\n",			 parent_path, strerror(errno) ));		return;	}	if (fsp && fsp->fh->fd != -1) {		become_root();		ret = SMB_VFS_FCHOWN(fsp, fsp->fh->fd, parent_st.st_uid, (gid_t)-1);		unbecome_root();		if (ret == -1) {			DEBUG(0,("change_owner_to_parent: failed to fchown "				 "file %s to parent directory uid %u. Error "				 "was %s\n", fname,				 (unsigned int)parent_st.st_uid,				 strerror(errno) ));		}		DEBUG(10,("change_owner_to_parent: changed new file %s to "			  "parent directory uid %u.\n",	fname,			  (unsigned int)parent_st.st_uid ));	} else {		/* We've already done an lstat into psbuf, and we know it's a		   directory. If we can cd into the directory and the dev/ino		   are the same then we can safely chown without races as		   we're locking the directory in place by being in it.  This		   should work on any UNIX (thanks tridge :-). JRA.		*/		pstring saved_dir;		SMB_STRUCT_STAT sbuf;		if (!vfs_GetWd(conn,saved_dir)) {			DEBUG(0,("change_owner_to_parent: failed to get "				 "current working directory\n"));			return;		}		/* Chdir into the new path. */		if (vfs_ChDir(conn, fname) == -1) {			DEBUG(0,("change_owner_to_parent: failed to change "				 "current working directory to %s. Error "				 "was %s\n", fname, strerror(errno) ));			goto out;		}		if (SMB_VFS_STAT(conn,".",&sbuf) == -1) {			DEBUG(0,("change_owner_to_parent: failed to stat "				 "directory '.' (%s) Error was %s\n",				 fname, strerror(errno)));			goto out;		}		/* Ensure we're pointing at the same place. */		if (sbuf.st_dev != psbuf->st_dev ||		    sbuf.st_ino != psbuf->st_ino ||		    sbuf.st_mode != psbuf->st_mode ) {			DEBUG(0,("change_owner_to_parent: "				 "device/inode/mode on directory %s changed. "				 "Refusing to chown !\n", fname ));			goto out;		}		become_root();		ret = SMB_VFS_CHOWN(conn, ".", parent_st.st_uid, (gid_t)-1);		unbecome_root();		if (ret == -1) {			DEBUG(10,("change_owner_to_parent: failed to chown "				  "directory %s to parent directory uid %u. "				  "Error was %s\n", fname,				  (unsigned int)parent_st.st_uid, strerror(errno) ));			goto out;		}		DEBUG(10,("change_owner_to_parent: changed ownership of new "			  "directory %s to parent directory uid %u.\n",			  fname, (unsigned int)parent_st.st_uid ));  out:		vfs_ChDir(conn,saved_dir);	}}/**************************************************************************** Open a file.****************************************************************************/static BOOL open_file(files_struct *fsp,			connection_struct *conn,			const char *fname,			SMB_STRUCT_STAT *psbuf,			int flags,			mode_t unx_mode,			uint32 access_mask){	int accmode = (flags & O_ACCMODE);	int local_flags = flags;	BOOL file_existed = VALID_STAT(*psbuf);	fsp->fh->fd = -1;	errno = EPERM;	/* Check permissions */	/*	 * This code was changed after seeing a client open request 	 * containing the open mode of (DENY_WRITE/read-only) with	 * the 'create if not exist' bit set. The previous code	 * would fail to open the file read only on a read-only share	 * as it was checking the flags parameter  directly against O_RDONLY,	 * this was failing as the flags parameter was set to O_RDONLY|O_CREAT.	 * JRA.	 */	if (!CAN_WRITE(conn)) {		/* It's a read-only share - fail if we wanted to write. */		if(accmode != O_RDONLY) {			DEBUG(3,("Permission denied opening %s\n",fname));			return False;		} else if(flags & O_CREAT) {			/* We don't want to write - but we must make sure that			   O_CREAT doesn't create the file if we have write			   access into the directory.			*/			flags &= ~O_CREAT;			local_flags &= ~O_CREAT;		}	}	/*	 * This little piece of insanity is inspired by the	 * fact that an NT client can open a file for O_RDONLY,	 * but set the create disposition to FILE_EXISTS_TRUNCATE.	 * If the client *can* write to the file, then it expects to	 * truncate the file, even though it is opening for readonly.	 * Quicken uses this stupid trick in backup file creation...	 * Thanks *greatly* to "David W. Chapman Jr." <dwcjr@inethouston.net>	 * for helping track this one down. It didn't bite us in 2.0.x	 * as we always opened files read-write in that release. JRA.	 */	if ((accmode == O_RDONLY) && ((flags & O_TRUNC) == O_TRUNC)) {		DEBUG(10,("open_file: truncate requested on read-only open "			  "for file %s\n",fname ));		local_flags = (flags & ~O_ACCMODE)|O_RDWR;	}	if ((access_mask & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) ||	    (local_flags & O_CREAT) ||	    ((local_flags & O_TRUNC) == O_TRUNC) ) {		/*		 * We can't actually truncate here as the file may be locked.		 * open_file_shared will take care of the truncate later. JRA.		 */		local_flags &= ~O_TRUNC;#if defined(O_NONBLOCK) && defined(S_ISFIFO)		/*		 * We would block on opening a FIFO with no one else on the		 * other end. Do what we used to do and add O_NONBLOCK to the		 * open flags. JRA.		 */		if (file_existed && S_ISFIFO(psbuf->st_mode)) {			local_flags |= O_NONBLOCK;		}#endif		/* Don't create files with Microsoft wildcard characters. */		if ((local_flags & O_CREAT) && !file_existed &&		    ms_has_wild(fname))  {			set_saved_ntstatus(NT_STATUS_OBJECT_NAME_INVALID);			return False;		}		/* Actually do the open */		fsp->fh->fd = fd_open(conn, fname, local_flags, unx_mode);		if (fsp->fh->fd == -1)  {			DEBUG(3,("Error opening file %s (%s) (local_flags=%d) "				 "(flags=%d)\n",				 fname,strerror(errno),local_flags,flags));			return False;		}		/* Inherit the ACL if the file was created. */		if ((local_flags & O_CREAT) && !file_existed) {			inherit_access_acl(conn, fname, unx_mode);		}	} else {		fsp->fh->fd = -1; /* What we used to call a stat open. */	}	if (!file_existed) {		int ret;		if (fsp->fh->fd == -1) {			ret = SMB_VFS_STAT(conn, fname, psbuf);		} else {			ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,psbuf);			/* If we have an fd, this stat should succeed. */			if (ret == -1) {				DEBUG(0,("Error doing fstat on open file %s "					 "(%s)\n", fname,strerror(errno) ));			}		}		/* For a non-io open, this stat failing means file not found. JRA */		if (ret == -1) {			fd_close(conn, fsp);			return False;		}	}	/*	 * POSIX allows read-only opens of directories. We don't	 * want to do this (we use a different code path for this)	 * so catch a directory open and return an EISDIR. JRA.	 */	if(S_ISDIR(psbuf->st_mode)) {		fd_close(conn, fsp);		errno = EISDIR;		return False;	}	fsp->mode = psbuf->st_mode;	fsp->inode = psbuf->st_ino;	fsp->dev = psbuf->st_dev;	fsp->vuid = current_user.vuid;	fsp->file_pid = global_smbpid;	fsp->can_lock = True;	fsp->can_read = (access_mask & (FILE_READ_DATA)) ? True : False;	if (!CAN_WRITE(conn)) {		fsp->can_write = False;	} else {		fsp->can_write = (access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) ? True : False;	}	fsp->print_file = False;	fsp->modified = False;	fsp->sent_oplock_break = NO_BREAK_SENT;	fsp->is_directory = False;	fsp->is_stat = False;	if (conn->aio_write_behind_list &&	    is_in_path(fname, conn->aio_write_behind_list, conn->case_sensitive)) {		fsp->aio_write_behind = True;	}	string_set(&fsp->fsp_name,fname);	fsp->wcp = NULL; /* Write cache pointer. */	DEBUG(2,("%s opened file %s read=%s write=%s (numopen=%d)\n",		 *current_user_info.smb_name ? current_user_info.smb_name : conn->user,fsp->fsp_name,		 BOOLSTR(fsp->can_read), BOOLSTR(fsp->can_write),		 conn->num_files_open + 1));	errno = 0;	return True;}/******************************************************************* Return True if the filename is one of the special executable types.********************************************************************/static BOOL is_executable(const char *fname){	if ((fname = strrchr_m(fname,'.'))) {		if (strequal(fname,".com") ||		    strequal(fname,".dll") ||		    strequal(fname,".exe") ||		    strequal(fname,".sym")) {			return True;		}	}	return False;}/**************************************************************************** Check if we can open a file with a share mode. Returns True if conflict, False if not.****************************************************************************/static BOOL share_conflict(struct share_mode_entry *entry,			   uint32 access_mask,			   uint32 share_access){	DEBUG(10,("share_conflict: entry->access_mask = 0x%x, "		  "entry->share_access = 0x%x, "		  "entry->private_options = 0x%x\n",		  (unsigned int)entry->access_mask,		  (unsigned int)entry->share_access,		  (unsigned int)entry->private_options));	DEBUG(10,("share_conflict: access_mask = 0x%x, share_access = 0x%x\n",		  (unsigned int)access_mask, (unsigned int)share_access));	if ((entry->access_mask & (FILE_WRITE_DATA|				   FILE_APPEND_DATA|				   FILE_READ_DATA|				   FILE_EXECUTE|				   DELETE_ACCESS)) == 0) {		DEBUG(10,("share_conflict: No conflict due to "			  "entry->access_mask = 0x%x\n",			  (unsigned int)entry->access_mask ));		return False;	}	if ((access_mask & (FILE_WRITE_DATA|			    FILE_APPEND_DATA|			    FILE_READ_DATA|			    FILE_EXECUTE|			    DELETE_ACCESS)) == 0) {		DEBUG(10,("share_conflict: No conflict due to "			  "access_mask = 0x%x\n",			  (unsigned int)access_mask ));		return False;	}#if 1 /* JRA TEST - Superdebug. */#define CHECK_MASK(num, am, right, sa, share) \	DEBUG(10,("share_conflict: [%d] am (0x%x) & right (0x%x) = 0x%x\n", \		(unsigned int)(num), (unsigned int)(am), \		(unsigned int)(right), (unsigned int)(am)&(right) )); \	DEBUG(10,("share_conflict: [%d] sa (0x%x) & share (0x%x) = 0x%x\n", \		(unsigned int)(num), (unsigned int)(sa), \		(unsigned int)(share), (unsigned int)(sa)&(share) )); \	if (((am) & (right)) && !((sa) & (share))) { \		DEBUG(10,("share_conflict: check %d conflict am = 0x%x, right = 0x%x, \sa = 0x%x, share = 0x%x\n", (num), (unsigned int)(am), (unsigned int)(right), (unsigned int)(sa), \			(unsigned int)(share) )); \		return True; \	}#else#define CHECK_MASK(num, am, right, sa, share) \	if (((am) & (right)) && !((sa) & (share))) { \		DEBUG(10,("share_conflict: check %d conflict am = 0x%x, right = 0x%x, \sa = 0x%x, share = 0x%x\n", (num), (unsigned int)(am), (unsigned int)(right), (unsigned int)(sa), \			(unsigned int)(share) )); \		return True; \	}#endif	CHECK_MASK(1, entry->access_mask, FILE_WRITE_DATA | FILE_APPEND_DATA,		   share_access, FILE_SHARE_WRITE);	CHECK_MASK(2, access_mask, FILE_WRITE_DATA | FILE_APPEND_DATA,		   entry->share_access, FILE_SHARE_WRITE);		CHECK_MASK(3, entry->access_mask, FILE_READ_DATA | FILE_EXECUTE,		   share_access, FILE_SHARE_READ);	CHECK_MASK(4, access_mask, FILE_READ_DATA | FILE_EXECUTE,		   entry->share_access, FILE_SHARE_READ);	CHECK_MASK(5, entry->access_mask, DELETE_ACCESS,		   share_access, FILE_SHARE_DELETE);	CHECK_MASK(6, access_mask, DELETE_ACCESS,		   entry->share_access, FILE_SHARE_DELETE);	DEBUG(10,("share_conflict: No conflict.\n"));	return False;}#if defined(DEVELOPER)static void validate_my_share_entries(int num,				      struct share_mode_entry *share_entry){	files_struct *fsp;	if (!procid_is_me(&share_entry->pid)) {		return;	}	if (is_deferred_open_entry(share_entry) &&	    !open_was_deferred(share_entry->op_mid)) {		pstring str;		DEBUG(0, ("Got a deferred entry without a request: "			  "PANIC: %s\n", share_mode_str(num, share_entry)));		smb_panic(str);	}	if (!is_valid_share_mode_entry(share_entry)) {		return;	}	fsp = file_find_dif(share_entry->dev, share_entry->inode,			    share_entry->share_file_id);	if (!fsp) {		DEBUG(0,("validate_my_share_entries: PANIC : %s\n",			 share_mode_str(num, share_entry) ));		smb_panic("validate_my_share_entries: Cannot match a "			  "share entry with an open file\n");	}	if (is_deferred_open_entry(share_entry) ||	    is_unused_share_mode_entry(share_entry)) {		goto panic;	}	if ((share_entry->op_type == NO_OPLOCK) &&	    (fsp->oplock_type == FAKE_LEVEL_II_OPLOCK)) {		/* Someone has already written to it, but I haven't yet		 * noticed */		return;	}	if (((uint16)fsp->oplock_type) != share_entry->op_type) {		goto panic;	}	return; panic:	{		pstring str;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -