mirror of
https://github.com/samba-team/samba.git
synced 2025-02-23 09:57:40 +03:00
Fix the mp3 rename bug - also tidy up our open code and remove the special
cases for rename and unlink. Had to add desired_access into the share mode record. Jeremy. (This used to be commit 3b1b8ac43535fb0839c5474fa55bf7150f6cde31)
This commit is contained in:
parent
ce236d1dbf
commit
c90cd26e94
@ -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;
|
||||
|
@ -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)) {
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
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);
|
||||
if (vfs_stat(conn,fname,&sbuf) == -1)
|
||||
return(True);
|
||||
|
||||
dev = sbuf.st_dev;
|
||||
inode = sbuf.st_ino;
|
||||
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);
|
||||
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.
|
||||
*/
|
||||
/*
|
||||
* Check if the share modes will give us access.
|
||||
*/
|
||||
|
||||
if(num_share_modes != 0)
|
||||
{
|
||||
BOOL broke_oplock;
|
||||
if(num_share_modes != 0) {
|
||||
BOOL broke_oplock;
|
||||
|
||||
do
|
||||
{
|
||||
do {
|
||||
|
||||
broke_oplock = False;
|
||||
for(i = 0; i < num_share_modes; i++)
|
||||
{
|
||||
share_mode_entry *share_entry = &old_shares[i];
|
||||
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))
|
||||
{
|
||||
/*
|
||||
* 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)) {
|
||||
|
||||
#if 0
|
||||
|
||||
/* 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....
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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, \
|
||||
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;
|
||||
}
|
||||
}
|
||||
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 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;
|
||||
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.
|
||||
*/
|
||||
/*
|
||||
* 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 ((GET_DENY_MODE(share_entry->share_mode) != DENY_DOS) ||
|
||||
(share_entry->pid != pid))
|
||||
goto free_and_exit;
|
||||
if(broke_oplock) {
|
||||
SAFE_FREE(old_shares);
|
||||
num_share_modes = get_share_modes(conn, dev, inode, &old_shares);
|
||||
}
|
||||
} while(broke_oplock);
|
||||
}
|
||||
|
||||
} /* end for */
|
||||
/*
|
||||
* XXXX exactly what share mode combinations should be allowed for
|
||||
* deleting/renaming?
|
||||
*/
|
||||
|
||||
if(broke_oplock)
|
||||
{
|
||||
SAFE_FREE(old_shares);
|
||||
num_share_modes = get_share_modes(conn, dev, inode, &old_shares);
|
||||
}
|
||||
} while(broke_oplock);
|
||||
}
|
||||
/*
|
||||
* 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).
|
||||
*/
|
||||
|
||||
/* 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;
|
||||
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
|
||||
|
@ -1206,6 +1206,41 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
|
||||
return(outsize);
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user