summaryrefslogtreecommitdiff
path: root/source3/smbd/open.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/smbd/open.c')
-rw-r--r--source3/smbd/open.c375
1 files changed, 187 insertions, 188 deletions
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index a67f8103e9..8fe87d5a51 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -1940,6 +1940,12 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
NTSTATUS status;
char *parent_dir;
SMB_STRUCT_STAT saved_stat = smb_fname->st;
+ struct share_mode_entry *batch_entry = NULL;
+ struct share_mode_entry *exclusive_entry = NULL;
+ bool got_level2_oplock = false;
+ bool got_a_none_oplock = false;
+ struct timespec old_write_time;
+ struct file_id id;
if (conn->printer) {
/*
@@ -2265,225 +2271,218 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
return NT_STATUS_ACCESS_DENIED;
}
- {
- struct share_mode_entry *batch_entry = NULL;
- struct share_mode_entry *exclusive_entry = NULL;
- bool got_level2_oplock = false;
- bool got_a_none_oplock = false;
- struct timespec old_write_time = smb_fname->st.st_ex_mtime;
- struct file_id id;
- /*
- * 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.
- */
+ old_write_time = smb_fname->st.st_ex_mtime;
- /*
- * 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.
- */
+ /*
+ * 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.
+ */
- id = fsp->file_id;
+ /*
+ * 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.
+ */
- lck = get_share_mode_lock(talloc_tos(), id,
- conn->connectpath,
- smb_fname, &old_write_time);
+ id = fsp->file_id;
- if (lck == NULL) {
- DEBUG(0, ("open_file_ntcreate: Could not get share "
- "mode lock for %s\n",
- smb_fname_str_dbg(smb_fname)));
- fd_close(fsp);
- return NT_STATUS_SHARING_VIOLATION;
- }
+ lck = get_share_mode_lock(talloc_tos(), id,
+ conn->connectpath,
+ smb_fname, &old_write_time);
- /* Get the types we need to examine. */
- find_oplock_types(fsp,
- oplock_request,
- lck,
- &batch_entry,
- &exclusive_entry,
- &got_level2_oplock,
- &got_a_none_oplock);
+ if (lck == NULL) {
+ DEBUG(0, ("open_file_ntcreate: Could not get share "
+ "mode lock for %s\n",
+ smb_fname_str_dbg(smb_fname)));
+ fd_close(fsp);
+ return NT_STATUS_SHARING_VIOLATION;
+ }
- /* First pass - send break only on batch oplocks. */
+ /* Get the types we need to examine. */
+ find_oplock_types(fsp,
+ oplock_request,
+ lck,
+ &batch_entry,
+ &exclusive_entry,
+ &got_level2_oplock,
+ &got_a_none_oplock);
+
+ /* First pass - send break only on batch oplocks. */
+ if ((req != NULL) &&
+ delay_for_batch_oplocks(fsp,
+ req->mid,
+ oplock_request,
+ batch_entry)) {
+ schedule_defer_open(lck, request_time, req);
+ TALLOC_FREE(lck);
+ fd_close(fsp);
+ return NT_STATUS_SHARING_VIOLATION;
+ }
+
+ status = open_mode_check(conn, lck, fsp->name_hash,
+ access_mask, share_access,
+ create_options, &file_existed);
+
+ 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 ((req != NULL) &&
- delay_for_batch_oplocks(fsp,
- req->mid,
- oplock_request,
- batch_entry)) {
+ delay_for_exclusive_oplocks(
+ fsp,
+ req->mid,
+ oplock_request,
+ exclusive_entry)) {
schedule_defer_open(lck, request_time, req);
TALLOC_FREE(lck);
fd_close(fsp);
return NT_STATUS_SHARING_VIOLATION;
}
+ }
- status = open_mode_check(conn, lck, fsp->name_hash,
- access_mask, share_access,
- create_options, &file_existed);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_DELETE_PENDING)) {
+ /* DELETE_PENDING is not deferred for a second */
+ TALLOC_FREE(lck);
+ return status;
+ }
- 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 ((req != NULL) &&
- delay_for_exclusive_oplocks(
- fsp,
- req->mid,
- oplock_request,
- exclusive_entry)) {
- schedule_defer_open(lck, request_time, req);
+ if (!NT_STATUS_IS_OK(status)) {
+ uint32 can_access_mask;
+ bool can_access = True;
+
+ SMB_ASSERT(NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION));
+
+ /* Check if this can be done with the deny_dos and fcb
+ * calls. */
+ if (private_flags &
+ (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS|
+ NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
+ if (req == NULL) {
+ DEBUG(0, ("DOS open without an SMB "
+ "request!\n"));
TALLOC_FREE(lck);
- fd_close(fsp);
- return NT_STATUS_SHARING_VIOLATION;
+ return NT_STATUS_INTERNAL_ERROR;
}
- }
- if (NT_STATUS_EQUAL(status, NT_STATUS_DELETE_PENDING)) {
- /* DELETE_PENDING is not deferred for a second */
- TALLOC_FREE(lck);
- return status;
- }
+ /* Use the client requested access mask here,
+ * not the one we open with. */
+ status = fcb_or_dos_open(req,
+ conn,
+ fsp,
+ smb_fname,
+ id,
+ req->smbpid,
+ req->vuid,
+ access_mask,
+ share_access,
+ create_options);
- if (!NT_STATUS_IS_OK(status)) {
- uint32 can_access_mask;
- bool can_access = True;
-
- SMB_ASSERT(NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION));
-
- /* Check if this can be done with the deny_dos and fcb
- * calls. */
- if (private_flags &
- (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS|
- NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
- if (req == NULL) {
- DEBUG(0, ("DOS open without an SMB "
- "request!\n"));
- TALLOC_FREE(lck);
- return NT_STATUS_INTERNAL_ERROR;
+ if (NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(lck);
+ if (pinfo) {
+ *pinfo = FILE_WAS_OPENED;
}
+ return NT_STATUS_OK;
+ }
+ }
- /* Use the client requested access mask here,
- * not the one we open with. */
- status = fcb_or_dos_open(req,
- conn,
- fsp,
- smb_fname,
- id,
- req->smbpid,
- req->vuid,
- access_mask,
- share_access,
- create_options);
+ /*
+ * This next line is a subtlety we need for
+ * MS-Access. If a file open will fail due to share
+ * permissions and also for security (access) reasons,
+ * we need to return the access failed error, not the
+ * share error. We can't open the file due to kernel
+ * oplock deadlock (it's possible we failed above on
+ * the open_mode_check()) so use a userspace check.
+ */
- if (NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(lck);
- if (pinfo) {
- *pinfo = FILE_WAS_OPENED;
- }
- return NT_STATUS_OK;
- }
- }
+ if (flags & O_RDWR) {
+ can_access_mask = FILE_READ_DATA|FILE_WRITE_DATA;
+ } else if (flags & O_WRONLY) {
+ can_access_mask = FILE_WRITE_DATA;
+ } else {
+ can_access_mask = FILE_READ_DATA;
+ }
- /*
- * This next line is a subtlety we need for
- * MS-Access. If a file open will fail due to share
- * permissions and also for security (access) reasons,
- * we need to return the access failed error, not the
- * share error. We can't open the file due to kernel
- * oplock deadlock (it's possible we failed above on
- * the open_mode_check()) so use a userspace check.
- */
+ if (((can_access_mask & FILE_WRITE_DATA) &&
+ !CAN_WRITE(conn)) ||
+ !NT_STATUS_IS_OK(smbd_check_access_rights(conn,
+ smb_fname,
+ false,
+ can_access_mask))) {
+ can_access = False;
+ }
- if (flags & O_RDWR) {
- can_access_mask = FILE_READ_DATA|FILE_WRITE_DATA;
- } else if (flags & O_WRONLY) {
- can_access_mask = FILE_WRITE_DATA;
- } else {
- can_access_mask = FILE_READ_DATA;
- }
+ /*
+ * If we're returning a share violation, ensure we
+ * cope with the braindead 1 second delay.
+ */
- if (((can_access_mask & FILE_WRITE_DATA) &&
- !CAN_WRITE(conn)) ||
- !NT_STATUS_IS_OK(smbd_check_access_rights(conn,
- smb_fname,
- false,
- can_access_mask))) {
- can_access = False;
+ if (!(oplock_request & INTERNAL_OPEN_ONLY) &&
+ lp_defer_sharing_violations()) {
+ struct timeval timeout;
+ struct deferred_open_record state;
+ int timeout_usecs;
+
+ /* this is a hack to speed up torture tests
+ in 'make test' */
+ timeout_usecs = lp_parm_int(SNUM(conn),
+ "smbd","sharedelay",
+ SHARING_VIOLATION_USEC_WAIT);
+
+ /* This is a relative time, added to the absolute
+ request_time value to get the absolute timeout time.
+ Note that if this is the second or greater time we enter
+ this codepath for this particular request mid then
+ request_time is left as the absolute time of the *first*
+ time this request mid was processed. This is what allows
+ the request to eventually time out. */
+
+ timeout = timeval_set(0, timeout_usecs);
+
+ /* Nothing actually uses state.delayed_for_oplocks
+ but it's handy to differentiate in debug messages
+ between a 30 second delay due to oplock break, and
+ a 1 second delay for share mode conflicts. */
+
+ state.delayed_for_oplocks = False;
+ state.async_open = false;
+ state.id = id;
+
+ if ((req != NULL)
+ && !request_timed_out(request_time,
+ timeout)) {
+ defer_open(lck, request_time, timeout,
+ req, &state);
}
+ }
+ TALLOC_FREE(lck);
+ if (can_access) {
/*
- * If we're returning a share violation, ensure we
- * cope with the braindead 1 second delay.
+ * We have detected a sharing violation here
+ * so return the correct error code
*/
-
- if (!(oplock_request & INTERNAL_OPEN_ONLY) &&
- lp_defer_sharing_violations()) {
- struct timeval timeout;
- struct deferred_open_record state;
- int timeout_usecs;
-
- /* this is a hack to speed up torture tests
- in 'make test' */
- timeout_usecs = lp_parm_int(SNUM(conn),
- "smbd","sharedelay",
- SHARING_VIOLATION_USEC_WAIT);
-
- /* This is a relative time, added to the absolute
- request_time value to get the absolute timeout time.
- Note that if this is the second or greater time we enter
- this codepath for this particular request mid then
- request_time is left as the absolute time of the *first*
- time this request mid was processed. This is what allows
- the request to eventually time out. */
-
- timeout = timeval_set(0, timeout_usecs);
-
- /* Nothing actually uses state.delayed_for_oplocks
- but it's handy to differentiate in debug messages
- between a 30 second delay due to oplock break, and
- a 1 second delay for share mode conflicts. */
-
- state.delayed_for_oplocks = False;
- state.async_open = false;
- state.id = id;
-
- if ((req != NULL)
- && !request_timed_out(request_time,
- timeout)) {
- defer_open(lck, request_time, timeout,
- req, &state);
- }
- }
-
- TALLOC_FREE(lck);
- if (can_access) {
- /*
- * We have detected a sharing violation here
- * so return the correct error code
- */
- status = NT_STATUS_SHARING_VIOLATION;
- } else {
- status = NT_STATUS_ACCESS_DENIED;
- }
- return status;
+ status = NT_STATUS_SHARING_VIOLATION;
+ } else {
+ status = NT_STATUS_ACCESS_DENIED;
}
+ return status;
+ }
- grant_fsp_oplock_type(fsp,
- oplock_request,
- got_level2_oplock,
- got_a_none_oplock);
+ grant_fsp_oplock_type(fsp,
+ oplock_request,
+ got_level2_oplock,
+ got_a_none_oplock);
- /*
- * We exit this block with the share entry *locked*.....
- */
-
- }
+ /*
+ * We have the share entry *locked*.....
+ */
SMB_ASSERT(lck != NULL);