diff options
| -rw-r--r-- | source3/include/smb.h | 9 | ||||
| -rw-r--r-- | source3/lib/util_sock.c | 2 | ||||
| -rw-r--r-- | source3/locking/locking.c | 7 | ||||
| -rw-r--r-- | source3/rpc_server/srv_srvsvc_nt.c | 4 | ||||
| -rw-r--r-- | source3/smbd/dir.c | 4 | ||||
| -rw-r--r-- | source3/smbd/nttrans.c | 9 | ||||
| -rw-r--r-- | source3/smbd/open.c | 331 | ||||
| -rw-r--r-- | source3/smbd/reply.c | 81 | ||||
| -rw-r--r-- | source3/smbd/trans2.c | 2 | ||||
| -rw-r--r-- | source3/torture/torture.c | 69 | ||||
| -rw-r--r-- | source3/utils/status.c | 5 | 
11 files changed, 314 insertions, 209 deletions
diff --git a/source3/include/smb.h b/source3/include/smb.h index cd15a96be2..8963528e9a 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -123,11 +123,6 @@ typedef int BOOL;  #define GET_DELETE_ON_CLOSE_FLAG(x) (((x) & DELETE_ON_CLOSE_FLAG) ? True : False)  #define SET_DELETE_ON_CLOSE_FLAG(x) ((x) ? DELETE_ON_CLOSE_FLAG : 0) -/* was delete access requested in NT open ? */ -#define DELETE_ACCESS_REQUESTED (1<<17) -#define GET_DELETE_ACCESS_REQUESTED(x) (((x) & DELETE_ACCESS_REQUESTED) ? True : False) -#define SET_DELETE_ACCESS_REQUESTED(x) ((x) ? DELETE_ACCESS_REQUESTED : 0) -  /* open disposition values */  #define FILE_EXISTS_FAIL 0  #define FILE_EXISTS_OPEN 1 @@ -386,6 +381,7 @@ typedef struct files_struct  	write_cache *wcp;  	struct timeval open_time;  	int share_mode; +	uint32 desired_access;  	time_t pending_modtime;  	int oplock_type;  	int sent_oplock_break; @@ -553,6 +549,7 @@ typedef struct {  	uint16 op_port;  	uint16 op_type;  	int share_mode; +	uint32 desired_access;  	struct timeval time;  	SMB_DEV_T dev;  	SMB_INO_T inode; @@ -1390,7 +1387,7 @@ extern int global_is_multibyte_codepage;  #define COPYBUF_SIZE (8*1024)  /*  - * Integers used to override error codes.  + * Values used to override error codes.    */  extern int unix_ERR_class;  extern int unix_ERR_code; diff --git a/source3/lib/util_sock.c b/source3/lib/util_sock.c index 9081f28f83..af3182264d 100644 --- a/source3/lib/util_sock.c +++ b/source3/lib/util_sock.c @@ -677,7 +677,7 @@ BOOL receive_smb(int fd,char *buffer, unsigned int timeout)  	/*  	 * A WRITEX with CAP_LARGE_WRITEX can be 64k worth of data plus 65 bytes -     * of header. Don't print the error if this fits.... JRA. +	 * of header. Don't print the error if this fits.... JRA.  	 */  	if (len > (BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE)) { diff --git a/source3/locking/locking.c b/source3/locking/locking.c index 6efe4a73d7..87df805250 100644 --- a/source3/locking/locking.c +++ b/source3/locking/locking.c @@ -361,8 +361,8 @@ static char *share_mode_str(int num, share_mode_entry *e)  	static pstring share_str;  	slprintf(share_str, sizeof(share_str)-1, "share_mode_entry[%d]: \ -pid = %u, share_mode = 0x%x, port = 0x%x, type= 0x%x, file_id = %lu, dev = 0x%x, inode = %.0f", -	num, e->pid, e->share_mode, e->op_port, e->op_type, e->share_file_id, +pid = %u, share_mode = 0x%x, desired_access = 0x%x, port = 0x%x, type= 0x%x, file_id = %lu, dev = 0x%x, inode = %.0f", +	num, e->pid, e->share_mode, (unsigned int)e->desired_access, e->op_port, e->op_type, e->share_file_id,  	(unsigned int)e->dev, (double)e->inode );  	return share_str; @@ -471,6 +471,7 @@ static void fill_share_mode(char *p, files_struct *fsp, uint16 port, uint16 op_t  	memset(e, '\0', sizeof(share_mode_entry));  	e->pid = sys_getpid();  	e->share_mode = fsp->share_mode; +	e->desired_access = fsp->desired_access;  	e->op_port = port;  	e->op_type = op_type;  	memcpy(x, &fsp->open_time, sizeof(struct timeval)); @@ -481,7 +482,7 @@ static void fill_share_mode(char *p, files_struct *fsp, uint16 port, uint16 op_t  /*******************************************************************   Check if two share mode entries are identical, ignoring oplock  - and port info.  + and port info and desired_access.  ********************************************************************/  BOOL share_modes_identical( share_mode_entry *e1, share_mode_entry *e2) diff --git a/source3/rpc_server/srv_srvsvc_nt.c b/source3/rpc_server/srv_srvsvc_nt.c index db94b8dc94..cfd4a0bf1f 100644 --- a/source3/rpc_server/srv_srvsvc_nt.c +++ b/source3/rpc_server/srv_srvsvc_nt.c @@ -1628,7 +1628,7 @@ WERROR _srv_net_file_query_secdesc(pipes_struct *p, SRV_Q_NET_FILE_QUERY_SECDESC  	if (!fsp) {  		/* Perhaps it is a directory */  		if (errno == EISDIR) -			fsp = open_directory(conn, filename, &st,0, +			fsp = open_directory(conn, filename, &st,FILE_READ_ATTRIBUTES,0,  					(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, &action);  		if (!fsp) { @@ -1733,7 +1733,7 @@ WERROR _srv_net_file_set_secdesc(pipes_struct *p, SRV_Q_NET_FILE_SET_SECDESC *q_  	if (!fsp) {  		/* Perhaps it is a directory */  		if (errno == EISDIR) -			fsp = open_directory(conn, filename, &st,0, +			fsp = open_directory(conn, filename, &st,FILE_READ_ATTRIBUTES,0,  						(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, &action);  		if (!fsp) { diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c index 40b198ed72..0bf234dd3e 100644 --- a/source3/smbd/dir.c +++ b/source3/smbd/dir.c @@ -687,7 +687,7 @@ static BOOL user_can_read_file(connection_struct *conn, char *name)  	/* Pseudo-open the file (note - no fd's created). */  	if(S_ISDIR(ste.st_mode))	 -		 fsp = open_directory(conn, name, &ste, SET_DENY_MODE(DENY_NONE), (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), +		 fsp = open_directory(conn, name, &ste, 0, SET_DENY_MODE(DENY_NONE), (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),  			unix_mode(conn,aRONLY|aDIR, name), &smb_action);  	else  		fsp = open_file_shared1(conn, name, &ste, FILE_READ_ATTRIBUTES, SET_DENY_MODE(DENY_NONE), @@ -698,7 +698,7 @@ static BOOL user_can_read_file(connection_struct *conn, char *name)  	/* Get NT ACL -allocated in main loop talloc context. No free needed here. */  	sd_size = conn->vfs_ops.fget_nt_acl(fsp, fsp->fd, &psd); -	close_file(fsp, True); +	close_file(fsp, False);  	/* No access if SD get failed. */  	if (!sd_size) diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index fb985bb325..ba6fd3eb44 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -412,7 +412,6 @@ static int map_share_mode( char *fname, uint32 create_options,  	 */  	if(*desired_access & DELETE_ACCESS) { -		smb_open_mode |= DELETE_ACCESS_REQUESTED;  		DEBUG(10,("map_share_mode: DELETE_ACCESS requested. open_mode = 0x%x\n", smb_open_mode));  	} @@ -681,7 +680,7 @@ int reply_ntcreate_and_X(connection_struct *conn,  	if(create_options & FILE_DIRECTORY_FILE) {  		oplock_request = 0; -		fsp = open_directory(conn, fname, &sbuf, smb_open_mode, smb_ofun, unixmode, &smb_action); +		fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, unixmode, &smb_action);  		restore_case_semantics(file_attributes); @@ -752,7 +751,7 @@ int reply_ntcreate_and_X(connection_struct *conn,  				}  				oplock_request = 0; -				fsp = open_directory(conn, fname, &sbuf, smb_open_mode, smb_ofun, unixmode, &smb_action); +				fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, unixmode, &smb_action);  				if(!fsp) {  					restore_case_semantics(file_attributes); @@ -1177,7 +1176,7 @@ static int call_nt_transact_create(connection_struct *conn,       * CreateDirectory() call.       */ -    fsp = open_directory(conn, fname, &sbuf, smb_open_mode, smb_ofun, unixmode, &smb_action); +    fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, unixmode, &smb_action);      if(!fsp) {        restore_case_semantics(file_attributes); @@ -1214,7 +1213,7 @@ static int call_nt_transact_create(connection_struct *conn,  			}  			oplock_request = 0; -			fsp = open_directory(conn, fname, &sbuf, smb_open_mode, smb_ofun, unixmode, &smb_action); +			fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, unixmode, &smb_action);  			if(!fsp) {  				restore_case_semantics(file_attributes); diff --git a/source3/smbd/open.c b/source3/smbd/open.c index c36dbdd522..bcb866c378 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -149,7 +149,7 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn,  	local_flags &= ~O_TRUNC; -	if (desired_access == 0 || (desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) || +	if ((desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) ||  			(local_flags & O_CREAT)) {  		/* actually do the open */ @@ -201,6 +201,7 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn,  	fsp->can_read = ((flags & O_WRONLY)==0);  	fsp->can_write = ((flags & (O_WRONLY|O_RDWR))!=0);  	fsp->share_mode = 0; +	fsp->desired_access = desired_access;  	fsp->print_file = False;  	fsp->modified = False;  	fsp->oplock_type = NO_OPLOCK; @@ -354,7 +355,7 @@ static int access_table(int new_deny,int old_deny,int old_mode,  check if we can open a file with a share mode  ****************************************************************************/ -static BOOL check_share_mode(connection_struct *conn, share_mode_entry *share, int share_mode,  +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); @@ -382,12 +383,43 @@ static BOOL check_share_mode(connection_struct *conn, share_mode_entry *share, i  		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)) ) { +		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 (GET_DELETE_ACCESS_REQUESTED(share_mode) && !GET_ALLOW_SHARE_DELETE(share->share_mode)) { +	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; @@ -402,7 +434,7 @@ static BOOL check_share_mode(connection_struct *conn, share_mode_entry *share, i  	 * ALLOW_SHARE_DELETE then deny.  	 */ -	if (GET_DELETE_ACCESS_REQUESTED(share->share_mode) && !GET_ALLOW_SHARE_DELETE(share_mode)) { +	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; @@ -411,9 +443,21 @@ static BOOL check_share_mode(connection_struct *conn, share_mode_entry *share, i  		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; +	} +  	{  		int access_allowed = access_table(deny_mode,old_deny_mode,old_open_mode, -										(share->pid == sys_getpid()),is_executable(fname)); +						(share->pid == sys_getpid()),is_executable(fname));  		if ((access_allowed == AFAIL) ||  			(!fcbopen && (access_allowed == AREAD && *flags == O_RDWR)) || @@ -523,28 +567,13 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou  				*p_all_current_opens_are_level_II = 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 -			   This code should be removed once we have a propoer ntcreateX -			   open functions -			   (tridge) -			*/ -			if (desired_access == 0 ||  -			    (desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE))) { -				/* someone else has a share lock on it, check to see  -				   if we can too */ -				if (!check_share_mode(conn, share_entry, share_mode,  -						      fname, fcbopen, p_flags)) { -					SAFE_FREE(old_shares); -					errno = EACCES; -					return -1; -				} -			} +			/* someone else has a share lock on it, check to see if we can too */ +			if (!check_share_mode(conn, share_entry, share_mode, desired_access, +						fname, fcbopen, p_flags)) { +				SAFE_FREE(old_shares); +				errno = EACCES; +				return -1; +                        }  		} /* end for */ @@ -653,7 +682,6 @@ files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_  	int flags2=0;  	int deny_mode = GET_DENY_MODE(share_mode);  	BOOL allow_share_delete = GET_ALLOW_SHARE_DELETE(share_mode); -	BOOL delete_access_requested = GET_DELETE_ACCESS_REQUESTED(share_mode);  	BOOL delete_on_close = GET_DELETE_ON_CLOSE_FLAG(share_mode);  	BOOL file_existed = VALID_STAT(*psbuf);  	BOOL fcbopen = False; @@ -732,16 +760,24 @@ files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_  	switch (GET_OPEN_MODE(share_mode)) {  		case DOS_OPEN_WRONLY:   			flags = O_WRONLY;  +			if (desired_access == 0) +				desired_access = FILE_WRITE_DATA;  			break;  		case DOS_OPEN_FCB:   			fcbopen = True;  			flags = O_RDWR;  +			if (desired_access == 0) +				desired_access = FILE_READ_DATA|FILE_WRITE_DATA;  			break;  		case DOS_OPEN_RDWR:   			flags = O_RDWR;  +			if (desired_access == 0) +				desired_access = FILE_READ_DATA|FILE_WRITE_DATA;  			break;  		default:  			flags = O_RDONLY; +			if (desired_access == 0) +				desired_access = FILE_READ_DATA;  			break;  	} @@ -922,8 +958,7 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n",  	fsp->share_mode = SET_DENY_MODE(deny_mode) |   						SET_OPEN_MODE(open_mode) |  -						SET_ALLOW_SHARE_DELETE(allow_share_delete) | -						SET_DELETE_ACCESS_REQUESTED(delete_access_requested); +						SET_ALLOW_SHARE_DELETE(allow_share_delete);  	DEBUG(10,("open_file_shared : share_mode = %x\n", fsp->share_mode )); @@ -1036,8 +1071,8 @@ int close_file_fchmod(files_struct *fsp)   Open a directory from an NT SMB call.  ****************************************************************************/ -files_struct *open_directory(connection_struct *conn, char *fname, -							SMB_STRUCT_STAT *psbuf, int share_mode, int smb_ofun, mode_t unixmode, int *action) +files_struct *open_directory(connection_struct *conn, char *fname, SMB_STRUCT_STAT *psbuf, +			uint32 desired_access, int share_mode, int smb_ofun, mode_t unixmode, int *action)  {  	extern struct current_user current_user;  	BOOL got_stat = False; @@ -1136,6 +1171,7 @@ files_struct *open_directory(connection_struct *conn, char *fname,  	fsp->can_read = False;  	fsp->can_write = False;  	fsp->share_mode = share_mode; +	fsp->desired_access = desired_access;  	fsp->print_file = False;  	fsp->modified = False;  	fsp->oplock_type = NO_OPLOCK; @@ -1157,6 +1193,9 @@ files_struct *open_directory(connection_struct *conn, char *fname,  	return fsp;  } +#if 0 + +Old code - I have replaced with correct desired_access checking. JRA.  /*******************************************************************   Check if the share mode on a file allows it to be deleted or unlinked. @@ -1165,149 +1204,107 @@ files_struct *open_directory(connection_struct *conn, char *fname,  BOOL check_file_sharing(connection_struct *conn,char *fname, BOOL rename_op)  { -  int i; -  int ret = False; -  share_mode_entry *old_shares = 0; -  int num_share_modes; -  SMB_STRUCT_STAT sbuf; -  pid_t pid = sys_getpid(); -  SMB_DEV_T dev; -  SMB_INO_T inode; - -  if (vfs_stat(conn,fname,&sbuf) == -1) -    return(True); - -  dev = sbuf.st_dev; -  inode = sbuf.st_ino; - -  lock_share_entry(conn, dev, inode); -  num_share_modes = get_share_modes(conn, dev, inode, &old_shares); - -  /* -   * Check if the share modes will give us access. -   */ - -  if(num_share_modes != 0) -  { -    BOOL broke_oplock; - -    do -    { - -      broke_oplock = False; -      for(i = 0; i < num_share_modes; i++) -      { -        share_mode_entry *share_entry = &old_shares[i]; - -        /*  -         * Break oplocks before checking share modes. See comment in -         * open_file_shared for details.  -         * Check if someone has an oplock on this file. If so we must  -         * break it before continuing.  -         */ -        if(BATCH_OPLOCK_TYPE(share_entry->op_type)) -        { +	int i; +	int ret = False; +	share_mode_entry *old_shares = 0; +	int num_share_modes; +	SMB_STRUCT_STAT sbuf; +	pid_t pid = sys_getpid(); +	SMB_DEV_T dev; +	SMB_INO_T inode; -#if 0 +	if (vfs_stat(conn,fname,&sbuf) == -1) +		return(True); -/* JRA. Try removing this code to see if the new oplock changes -   fix the problem. I'm dubious, but Andrew is recommending we -   try this.... -*/ +	dev = sbuf.st_dev; +	inode = sbuf.st_ino; -          /* -           * It appears that the NT redirector may have a bug, in that -           * it tries to do an SMBmv on a file that it has open with a -           * batch oplock, and then fails to respond to the oplock break -           * request. This only seems to occur when the client is doing an -           * SMBmv to the smbd it is using - thus we try and detect this -           * condition by checking if the file being moved is open and oplocked by -           * this smbd process, and then not sending the oplock break in this -           * special case. If the file was open with a deny mode that  -           * prevents the move the SMBmv will fail anyway with a share -           * violation error. JRA. -           */ -          if(rename_op && (share_entry->pid == pid)) -          { - -            DEBUG(0,("check_file_sharing: NT redirector workaround - rename attempted on \ -batch oplocked file %s, dev = %x, inode = %.0f\n", fname, (unsigned int)dev, (double)inode)); - -            /*  -             * This next line is a test that allows the deny-mode -             * processing to be skipped. This seems to be needed as -             * NT insists on the rename succeeding (in Office 9x no less !). -             * This should be removed as soon as (a) MS fix the redirector -             * bug or (b) NT SMB support in Samba makes NT not issue the -             * call (as is my fervent hope). JRA. -             */  -            continue; -          } -          else -#endif /* 0 */ -          { - -            DEBUG(5,("check_file_sharing: breaking oplock (%x) on file %s, \ +	lock_share_entry(conn, dev, inode); +	num_share_modes = get_share_modes(conn, dev, inode, &old_shares); + +	/* +	 * Check if the share modes will give us access. +	 */ + +	if(num_share_modes != 0) { +		BOOL broke_oplock; + +		do { + +			broke_oplock = False; +			for(i = 0; i < num_share_modes; i++) { +				share_mode_entry *share_entry = &old_shares[i]; + +				/*  +				 * Break oplocks before checking share modes. See comment in +				 * open_file_shared for details.  +				 * Check if someone has an oplock on this file. If so we must  +				 * break it before continuing.  +				 */ +				if(BATCH_OPLOCK_TYPE(share_entry->op_type)) { + +					DEBUG(5,("check_file_sharing: breaking oplock (%x) on file %s, \  dev = %x, inode = %.0f\n", share_entry->op_type, fname, (unsigned int)dev, (double)inode)); -            /* Oplock break.... */ -            unlock_share_entry(conn, dev, inode); -            if(request_oplock_break(share_entry) == False) -            { -              DEBUG(0,("check_file_sharing: FAILED when breaking oplock (%x) on file %s, \ +					/* Oplock break.... */ +					unlock_share_entry(conn, dev, inode); + +					if(request_oplock_break(share_entry) == False) { +						DEBUG(0,("check_file_sharing: FAILED when breaking oplock (%x) on file %s, \  dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (double)inode)); -              SAFE_FREE(old_shares); -              return False; -            } -            lock_share_entry(conn, dev, inode); -            broke_oplock = True; -            break; -          } -        } - -        /*  -         * If this is a delete request and ALLOW_SHARE_DELETE is set then allow  -         * this to proceed. This takes precedence over share modes. -         */ - -        if(!rename_op && GET_ALLOW_SHARE_DELETE(share_entry->share_mode)) -          continue; - -        /*  -         * Someone else has a share lock on it, check to see  -         * if we can too. -         */ - -        if ((GET_DENY_MODE(share_entry->share_mode) != DENY_DOS) ||  -	    (share_entry->pid != pid)) -          goto free_and_exit; - -      } /* end for */ - -      if(broke_oplock) -      { -        SAFE_FREE(old_shares); -        num_share_modes = get_share_modes(conn, dev, inode, &old_shares); -      } -    } while(broke_oplock); -  } - -  /* XXXX exactly what share mode combinations should be allowed for -     deleting/renaming? */ -  /*  -   * If we got here then either there were no share modes or -   * all share modes were DENY_DOS and the pid == getpid() or -   * delete access was requested and all share modes had the -   * ALLOW_SHARE_DELETE bit set (takes precedence over other -   * share modes). -   */ - -  ret = True; +						SAFE_FREE(old_shares); +						return False; +					} +					lock_share_entry(conn, dev, inode); +					broke_oplock = True; +					break; +				} + +				/*  +				 * If this is a delete request and ALLOW_SHARE_DELETE is set then allow  +				 * this to proceed. This takes precedence over share modes. +				 */ + +				if(!rename_op && GET_ALLOW_SHARE_DELETE(share_entry->share_mode)) +					continue; + +				/*  +				 * Someone else has a share lock on it, check to see  +				 * if we can too. +				 */ +       			 	if ((GET_DENY_MODE(share_entry->share_mode) != DENY_DOS) ||  +							(share_entry->pid != pid)) +					goto free_and_exit; +	 +			} /* end for */ + +			if(broke_oplock) { +				SAFE_FREE(old_shares); +				num_share_modes = get_share_modes(conn, dev, inode, &old_shares); +			} +		} while(broke_oplock); +	} + +	/* +	 * XXXX exactly what share mode combinations should be allowed for +	 * deleting/renaming? +	 */ + +	/*  +	 * If we got here then either there were no share modes or +	 * all share modes were DENY_DOS and the pid == getpid() or +	 * delete access was requested and all share modes had the +	 * ALLOW_SHARE_DELETE bit set (takes precedence over other +	 * share modes). +	 */ + +	ret = True;  free_and_exit: -  unlock_share_entry(conn, dev, inode); -  SAFE_FREE(old_shares); -  return(ret); +	unlock_share_entry(conn, dev, inode); +	SAFE_FREE(old_shares); +	return(ret);  } +#endif diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 4dcb674ff1..b556862e68 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -1207,6 +1207,41 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,  }  /******************************************************************* + Check if a user is allowed to rename a file. +********************************************************************/ + +static NTSTATUS can_rename(char *fname,connection_struct *conn, SMB_STRUCT_STAT *pst) +{ +	int smb_action; +	int access_mode; +	files_struct *fsp; + +	if (!CAN_WRITE(conn)) +		return NT_STATUS_MEDIA_WRITE_PROTECTED; +	 +	if (S_ISDIR(pst->st_mode)) +		return NT_STATUS_OK; + +	/* We need a better way to return NT status codes from open... */ +	unix_ERR_class = 0; +	unix_ERR_code = 0; + +	fsp = open_file_shared1(conn, fname, pst, DELETE_ACCESS, SET_DENY_MODE(DENY_ALL), +		(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &smb_action); + +	if (!fsp) { +		NTSTATUS ret = NT_STATUS_ACCESS_DENIED; +		if (unix_ERR_class == ERRDOS && unix_ERR_code == ERRbadshare) +			ret = NT_STATUS_SHARING_VIOLATION; +		unix_ERR_class = 0; +		unix_ERR_code = 0; +		return ret; +	} +	close_file(fsp,False); +	return NT_STATUS_OK; +} + +/*******************************************************************   Check if a user is allowed to delete a file.  ********************************************************************/ @@ -1214,6 +1249,9 @@ static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype)  {  	SMB_STRUCT_STAT sbuf;  	int fmode; +	int smb_action; +	int access_mode; +	files_struct *fsp;  	if (!CAN_WRITE(conn))  		return NT_STATUS_MEDIA_WRITE_PROTECTED; @@ -1231,9 +1269,22 @@ static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype)  	if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM))  		return NT_STATUS_CANNOT_DELETE; -	if (!check_file_sharing(conn,fname,False)) -		return NT_STATUS_SHARING_VIOLATION; +	/* We need a better way to return NT status codes from open... */ +	unix_ERR_class = 0; +	unix_ERR_code = 0; + +	fsp = open_file_shared1(conn, fname, &sbuf, DELETE_ACCESS, SET_DENY_MODE(DENY_ALL), +		(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &smb_action); +	if (!fsp) { +		NTSTATUS ret = NT_STATUS_ACCESS_DENIED; +		if (unix_ERR_class == ERRDOS && unix_ERR_code == ERRbadshare) +			ret = NT_STATUS_SHARING_VIOLATION; +		unix_ERR_class = 0; +		unix_ERR_code = 0; +		return ret; +	} +	close_file(fsp,False);  	return NT_STATUS_OK;  } @@ -2950,21 +3001,6 @@ static BOOL resolve_wildcards(char *name1,char *name2)    return(True);  } -/******************************************************************* - Check if a user is allowed to rename a file. -********************************************************************/ - -static NTSTATUS can_rename(char *fname,connection_struct *conn) -{ -	if (!CAN_WRITE(conn)) -		return NT_STATUS_ACCESS_DENIED; - -	if (!check_file_sharing(conn,fname,True)) -		return NT_STATUS_SHARING_VIOLATION; - -	return NT_STATUS_OK; -} -  /****************************************************************************   The guts of the rename command, split out so it may be called by the NT SMB   code.  @@ -3099,7 +3135,7 @@ directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n",  		 * The source object must exist.  		 */ -		if (!vfs_object_exist(conn, directory, NULL)) { +		if (!vfs_object_exist(conn, directory, &sbuf1)) {  			DEBUG(3,("rename_internals: source doesn't exist doing rename %s -> %s\n",  				directory,newname)); @@ -3124,7 +3160,7 @@ directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n",  			return error;  		} -		error = can_rename(directory,conn); +		error = can_rename(directory,conn,&sbuf1);  		if (!NT_STATUS_IS_OK(error)) {  			DEBUG(3,("rename_internals: Error %s rename %s -> %s\n", @@ -3190,7 +3226,12 @@ directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n",  				error = NT_STATUS_ACCESS_DENIED;  				slprintf(fname,sizeof(fname)-1,"%s/%s",directory,dname); -				error = can_rename(fname,conn); +				if (!vfs_object_exist(conn, fname, &sbuf1)) { +					error = NT_STATUS_OBJECT_NAME_NOT_FOUND; +					DEBUG(6,("rename %s failed. Error %s\n", fname, nt_errstr(error))); +					continue; +				} +				error = can_rename(fname,conn,&sbuf1);  				if (!NT_STATUS_IS_OK(error)) {  					DEBUG(6,("rename %s refused\n", fname));  					continue; diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 185fe1c633..5d0ee08f42 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -1861,7 +1861,7 @@ NTSTATUS set_delete_on_close_internal(files_struct *fsp, BOOL delete_on_close)  	 * Only allow delete on close for files/directories opened with delete intent.  	 */ -	if (delete_on_close && !GET_DELETE_ACCESS_REQUESTED(fsp->share_mode)) { +	if (delete_on_close && !(fsp->desired_access & DELETE_ACCESS)) {  		DEBUG(10,("set_delete_on_close_internal: file %s delete on close flag set but delete access denied.\n",  				fsp->fsp_name ));  				return NT_STATUS_ACCESS_DENIED; diff --git a/source3/torture/torture.c b/source3/torture/torture.c index f4c816b325..e1373cc355 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -622,6 +622,20 @@ static BOOL run_readwritelarge(int dummy)  		correct = False;  	} +#if 0 +	/* ToDo - set allocation. JRA */ +	if(!cli_set_allocation_size(&cli1, fnum1, 0)) { +		printf("set allocation size to zero failed (%s)\n", cli_errstr(&cli1)); +		return False; +	} +	if (!cli_qfileinfo(&cli1, fnum1, NULL, &fsize, NULL, NULL, NULL, NULL, NULL)) { +		printf("qfileinfo failed (%s)\n", cli_errstr(&cli1)); +		correct = False; +	} +	if (fsize != 0) +		printf("readwritelarge test 3 (truncate test) succeeded (size = %x)\n", fsize); +#endif +  	if (!cli_close(&cli1, fnum1)) {  		printf("close failed (%s)\n", cli_errstr(&cli1));  		correct = False; @@ -2902,7 +2916,11 @@ static BOOL run_rename(int dummy)  	cli_unlink(&cli1, fname);  	cli_unlink(&cli1, fname1);  	fnum1 = cli_nt_create_full(&cli1, fname,GENERIC_READ_ACCESS, FILE_ATTRIBUTE_NORMAL, +#if 0 +				   FILE_SHARE_DELETE|FILE_SHARE_NONE, FILE_OVERWRITE_IF, 0); +#else  				   FILE_SHARE_DELETE|FILE_SHARE_READ, FILE_OVERWRITE_IF, 0); +#endif  	if (fnum1 == -1) {  		printf("Second open failed - %s\n", cli_errstr(&cli1)); @@ -2924,6 +2942,57 @@ static BOOL run_rename(int dummy)  	cli_unlink(&cli1, fname);  	cli_unlink(&cli1, fname1); +#if 0 +	fnum1 = cli_nt_create_full(&cli1, fname,FILE_READ_DATA, FILE_ATTRIBUTE_NORMAL, +#else +	fnum1 = cli_nt_create_full(&cli1, fname,READ_CONTROL_ACCESS, FILE_ATTRIBUTE_NORMAL, +#endif +				   FILE_SHARE_NONE, FILE_OVERWRITE_IF, 0); + +	if (fnum1 == -1) { +		printf("Third open failed - %s\n", cli_errstr(&cli1)); +		return False; +	} + + +#if 1 +  { +  int fnum2; + +	fnum2 = cli_nt_create_full(&cli1, fname,DELETE_ACCESS, FILE_ATTRIBUTE_NORMAL, +				   FILE_SHARE_NONE, FILE_OVERWRITE_IF, 0); + +	if (fnum2 == -1) { +		printf("Fourth open failed - %s\n", cli_errstr(&cli1)); +		return False; +	} +	if (!cli_nt_delete_on_close(&cli1, fnum2, True)) { +		printf("[8] setting delete_on_close on file failed !\n"); +		return False; +	} +	 +	if (!cli_close(&cli1, fnum2)) { +		printf("close - 4 failed (%s)\n", cli_errstr(&cli1)); +		return False; +	} +  } +#endif + +	if (!cli_rename(&cli1, fname, fname1)) { +		printf("Third rename failed - this should have succeeded - %s\n", cli_errstr(&cli1)); +		correct = False; +	} else { +		printf("Third rename succeeded\n"); +	} + +	if (!cli_close(&cli1, fnum1)) { +		printf("close - 3 failed (%s)\n", cli_errstr(&cli1)); +		return False; +	} + +	cli_unlink(&cli1, fname); +	cli_unlink(&cli1, fname1); +  	if (!torture_close_connection(&cli1)) {  		correct = False;  	} diff --git a/source3/utils/status.c b/source3/utils/status.c index 58efecbce1..6f4b9eb28c 100644 --- a/source3/utils/status.c +++ b/source3/utils/status.c @@ -90,8 +90,8 @@ static void print_share_mode(share_mode_entry *e, char *fname)  	static int count;  	if (count==0) {  		d_printf("Locked files:\n"); -		d_printf("Pid    DenyMode   R/W        Oplock           Name\n"); -		d_printf("--------------------------------------------------\n"); +		d_printf("Pid    DenyMode   Access      R/W        Oplock           Name\n"); +		d_printf("--------------------------------------------------------------\n");  	}  	count++; @@ -105,6 +105,7 @@ static void print_share_mode(share_mode_entry *e, char *fname)  	  case DENY_WRITE:printf("DENY_WRITE "); break;  	  case DENY_FCB:  d_printf("DENY_FCB "); break;  	  } +	  d_printf("0x%-8x  ",(unsigned int)e->desired_access);  	  switch (e->share_mode&0xF) {  	  case 0: d_printf("RDONLY     "); break;  	  case 1: d_printf("WRONLY     "); break;  | 
