summaryrefslogtreecommitdiffstats
path: root/source/smbd/open.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/smbd/open.c')
-rw-r--r--source/smbd/open.c160
1 files changed, 70 insertions, 90 deletions
diff --git a/source/smbd/open.c b/source/smbd/open.c
index 94441c5df9b..a3c3cc4fc95 100644
--- a/source/smbd/open.c
+++ b/source/smbd/open.c
@@ -185,7 +185,8 @@ static BOOL open_file(files_struct *fsp,
SMB_STRUCT_STAT *psbuf,
int flags,
mode_t unx_mode,
- uint32 access_mask)
+ uint32 access_mask, /* client requested access mask. */
+ uint32 open_access_mask) /* what we're actually using in the open. */
{
int accmode = (flags & O_ACCMODE);
int local_flags = flags;
@@ -239,7 +240,7 @@ static BOOL open_file(files_struct *fsp,
local_flags = (flags & ~O_ACCMODE)|O_RDWR;
}
- if ((access_mask & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) ||
+ if ((open_access_mask & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) ||
(!file_existed && (local_flags & O_CREAT)) ||
((local_flags & O_TRUNC) == O_TRUNC) ) {
@@ -1112,6 +1113,7 @@ files_struct *open_file_ntcreate(connection_struct *conn,
uint16 mid = get_current_mid();
struct timeval request_time = timeval_zero();
struct share_mode_lock *lck = NULL;
+ uint32 open_access_mask = access_mask;
NTSTATUS status;
if (conn->printer) {
@@ -1202,12 +1204,14 @@ files_struct *open_file_ntcreate(connection_struct *conn,
/* If file exists replace/overwrite. If file doesn't
* exist create. */
flags2 |= (O_CREAT | O_TRUNC);
+ open_access_mask |= FILE_WRITE_DATA; /* This will cause oplock breaks. */
break;
case FILE_OVERWRITE_IF:
/* If file exists replace/overwrite. If file doesn't
* exist create. */
flags2 |= (O_CREAT | O_TRUNC);
+ open_access_mask |= FILE_WRITE_DATA; /* This will cause oplock breaks. */
break;
case FILE_OPEN:
@@ -1234,6 +1238,7 @@ files_struct *open_file_ntcreate(connection_struct *conn,
return NULL;
}
flags2 |= O_TRUNC;
+ open_access_mask |= FILE_WRITE_DATA; /* This will cause oplock breaks. */
break;
case FILE_CREATE:
@@ -1286,7 +1291,10 @@ files_struct *open_file_ntcreate(connection_struct *conn,
/* This is a nasty hack - must fix... JRA. */
if (access_mask == MAXIMUM_ALLOWED_ACCESS) {
- access_mask = FILE_GENERIC_ALL;
+ open_access_mask = access_mask = FILE_GENERIC_ALL;
+ if (flags2 & O_TRUNC) {
+ open_access_mask |= FILE_WRITE_DATA; /* This will cause oplock breaks. */
+ }
}
/*
@@ -1351,7 +1359,7 @@ files_struct *open_file_ntcreate(connection_struct *conn,
fsp->inode = psbuf->st_ino;
fsp->share_access = share_access;
fsp->fh->private_options = create_options;
- fsp->access_mask = access_mask;
+ fsp->access_mask = open_access_mask; /* We change this to the requested access_mask after the open is done. */
/* Ensure no SAMBA_PRIVATE bits can be set. */
fsp->oplock_type = (oplock_request & ~SAMBA_PRIVATE_OPLOCK_MASK);
@@ -1382,6 +1390,7 @@ files_struct *open_file_ntcreate(connection_struct *conn,
return NULL;
}
+ /* Use the client requested access mask here, not the one we open with. */
status = open_mode_check(conn, fname, lck,
access_mask, share_access,
create_options, &file_existed);
@@ -1417,6 +1426,8 @@ files_struct *open_file_ntcreate(connection_struct *conn,
(NTCREATEX_OPTIONS_PRIVATE_DENY_DOS|
NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
files_struct *fsp_dup;
+
+ /* Use the client requested access mask here, not the one we open with. */
fsp_dup = fcb_or_dos_open(conn, fname, dev,
inode, access_mask,
share_access,
@@ -1532,119 +1543,88 @@ files_struct *open_file_ntcreate(connection_struct *conn,
(unsigned int)flags, (unsigned int)flags2,
(unsigned int)unx_mode));
- /* Drop the lock before doing any real file access. Allows kernel
- oplock breaks to be processed. Handle any races after the open
- call when we re-acquire the lock. */
-
- if (lck) {
- TALLOC_FREE(lck);
- }
-
/*
* open_file strips any O_TRUNC flags itself.
*/
fsp_open = open_file(fsp,conn,fname,psbuf,flags|flags2,unx_mode,
- access_mask);
+ access_mask, open_access_mask);
if (!fsp_open) {
+ if (lck != NULL) {
+ TALLOC_FREE(lck);
+ }
file_free(fsp);
return NULL;
}
- /*
- * Deal with the race condition where two smbd's detect the
- * file doesn't exist and do the create at the same time. One
- * of them will win and set a share mode, the other (ie. this
- * one) should check if the requested share mode for this
- * create is allowed.
- */
-
- /*
- * Now the file exists and fsp is successfully opened,
- * fsp->dev and fsp->inode are valid and should replace the
- * dev=0,inode=0 from a non existent file. Spotted by
- * Nadav Danieli <nadavd@exanet.com>. JRA.
- */
-
- dev = fsp->dev;
- inode = fsp->inode;
+ if (!file_existed) {
- lck = get_share_mode_lock(NULL, dev, inode,
- conn->connectpath,
- fname);
+ /*
+ * Deal with the race condition where two smbd's detect the
+ * file doesn't exist and do the create at the same time. One
+ * of them will win and set a share mode, the other (ie. this
+ * one) should check if the requested share mode for this
+ * create is allowed.
+ */
- if (lck == NULL) {
- DEBUG(0, ("open_file_ntcreate: Could not get share mode lock for %s\n", fname));
- fd_close(conn, fsp);
- file_free(fsp);
- set_saved_ntstatus(NT_STATUS_SHARING_VIOLATION);
- return NULL;
- }
+ /*
+ * Now the file exists and fsp is successfully opened,
+ * fsp->dev and fsp->inode are valid and should replace the
+ * dev=0,inode=0 from a non existent file. Spotted by
+ * Nadav Danieli <nadavd@exanet.com>. JRA.
+ */
- /*
- * The share entry is again *locked*.....
- */
+ dev = fsp->dev;
+ inode = fsp->inode;
- /* First pass - send break only on batch oplocks. */
- if (delay_for_oplocks(lck, fsp, 1, oplock_request)) {
- schedule_defer_open(lck, request_time);
- fd_close(conn, fsp);
- file_free(fsp);
- TALLOC_FREE(lck);
- set_saved_ntstatus(NT_STATUS_SHARING_VIOLATION);
- return NULL;
- }
-
- status = open_mode_check(conn, fname, lck,
- access_mask, share_access,
- create_options, &file_existed);
+ lck = get_share_mode_lock(NULL, dev, inode,
+ conn->connectpath,
+ fname);
- if (NT_STATUS_IS_OK(status)) {
- /* We might be going to allow this open. Check oplock status again. */
- /* Second pass - send break for both batch or exclusive oplocks. */
- if (delay_for_oplocks(lck, fsp, 2, oplock_request)) {
- schedule_defer_open(lck, request_time);
+ if (lck == NULL) {
+ DEBUG(0, ("open_file_ntcreate: Could not get share mode lock for %s\n", fname));
fd_close(conn, fsp);
file_free(fsp);
- TALLOC_FREE(lck);
set_saved_ntstatus(NT_STATUS_SHARING_VIOLATION);
return NULL;
}
- }
- if (NT_STATUS_EQUAL(status, NT_STATUS_DELETE_PENDING)) {
- /* DELETE_PENDING is not deferred for a second */
- fd_close(conn, fsp);
- file_free(fsp);
- TALLOC_FREE(lck);
- set_saved_ntstatus(status);
- return NULL;
- }
+ status = open_mode_check(conn, fname, lck,
+ access_mask, share_access,
+ create_options, &file_existed);
- if (!NT_STATUS_IS_OK(status)) {
- struct deferred_open_record state;
+ if (!NT_STATUS_IS_OK(status)) {
+ struct deferred_open_record state;
- fd_close(conn, fsp);
- file_free(fsp);
+ fd_close(conn, fsp);
+ file_free(fsp);
- state.delayed_for_oplocks = False;
- state.dev = dev;
- state.inode = inode;
+ state.delayed_for_oplocks = False;
+ state.dev = dev;
+ state.inode = inode;
- /* Do it all over again immediately. In the second
- * round we will find that the file existed and handle
- * the DELETE_PENDING and FCB cases correctly. No need
- * to duplicate the code here. Essentially this is a
- * "goto top of this function", but don't tell
- * anybody... */
+ /* Do it all over again immediately. In the second
+ * round we will find that the file existed and handle
+ * the DELETE_PENDING and FCB cases correctly. No need
+ * to duplicate the code here. Essentially this is a
+ * "goto top of this function", but don't tell
+ * anybody... */
+
+ defer_open(lck, request_time, timeval_zero(),
+ &state);
+ TALLOC_FREE(lck);
+ return NULL;
+ }
+
+ /*
+ * We exit this block with the share entry *locked*.....
+ */
- defer_open(lck, request_time, timeval_zero(),
- &state);
- TALLOC_FREE(lck);
- return NULL;
}
+ SMB_ASSERT(lck != NULL);
+
/* note that we ignore failure for the following. It is
basically a hack for NFS, and NFS will never set one of
these only read them. Nobody but Samba can ever set a deny
@@ -1685,7 +1665,7 @@ files_struct *open_file_ntcreate(connection_struct *conn,
if (file_existed) {
/* stat opens on existing files don't get oplocks. */
- if (is_stat_open(fsp->access_mask)) {
+ if (is_stat_open(open_access_mask)) {
fsp->oplock_type = NO_OPLOCK;
}
@@ -1828,7 +1808,7 @@ files_struct *open_file_fchmod(connection_struct *conn, const char *fname,
/* note! we must use a non-zero desired access or we don't get
a real file descriptor. Oh what a twisted web we weave. */
- fsp_open = open_file(fsp,conn,fname,psbuf,O_WRONLY,0,FILE_WRITE_DATA);
+ fsp_open = open_file(fsp,conn,fname,psbuf,O_WRONLY,0,FILE_WRITE_DATA,FILE_WRITE_DATA);
/*
* This is not a user visible file open.