s4:smbd/open: add missing TALLOC_FREE(frame) to inherit_new_acl()
[kai/samba.git] / source3 / smbd / open.c
index 9c9eff5a46c3040b9d9251757b65aaef0e502de7..d736f4f795bb05d935afff6060f326e9e7c5761d 100644 (file)
@@ -115,7 +115,7 @@ NTSTATUS smbd_check_access_rights(struct connection_struct *conn,
        status = SMB_VFS_GET_NT_ACL(conn, smb_fname->base_name,
                        (SECINFO_OWNER |
                        SECINFO_GROUP |
-                       SECINFO_DACL),&sd);
+                        SECINFO_DACL), talloc_tos(), &sd);
 
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(10, ("smbd_check_access_rights: Could not get acl "
@@ -131,7 +131,13 @@ NTSTATUS smbd_check_access_rights(struct connection_struct *conn,
        }
 
        /*
-        * Never test FILE_READ_ATTRIBUTES. se_file_access_check() also takes care of
+        * If we can access the path to this file, by
+        * default we have FILE_READ_ATTRIBUTES from the
+        * containing directory. See the section:
+        * "Algorithm to Check Access to an Existing File"
+        * in MS-FSA.pdf.
+        *
+        * se_file_access_check() also takes care of
         * owner WRITE_DAC and READ_CONTROL.
         */
        status = se_file_access_check(sd,
@@ -237,6 +243,7 @@ static NTSTATUS check_parent_access(struct connection_struct *conn,
        status = SMB_VFS_GET_NT_ACL(conn,
                                parent_dir,
                                SECINFO_DACL,
+                                   talloc_tos(),
                                &parent_sd);
 
        if (!NT_STATUS_IS_OK(status)) {
@@ -248,7 +255,13 @@ static NTSTATUS check_parent_access(struct connection_struct *conn,
        }
 
        /*
-        * Never test FILE_READ_ATTRIBUTES. se_file_access_check() also takes care of
+        * If we can access the path to this file, by
+        * default we have FILE_READ_ATTRIBUTES from the
+        * containing directory. See the section:
+        * "Algorithm to Check Access to an Existing File"
+        * in MS-FSA.pdf.
+        *
+        * se_file_access_check() also takes care of
         * owner WRITE_DAC and READ_CONTROL.
         */
        status = se_file_access_check(parent_sd,
@@ -1011,7 +1024,8 @@ static void validate_my_share_entries(struct smbd_server_connection *sconn,
        }
 
        if (is_deferred_open_entry(share_entry) &&
-           !open_was_deferred(sconn, share_entry->op_mid)) {
+           !open_was_deferred(sconn, share_entry->op_mid))
+       {
                char *str = talloc_asprintf(talloc_tos(),
                        "Got a deferred entry without a request: "
                        "PANIC: %s\n",
@@ -1037,7 +1051,8 @@ static void validate_my_share_entries(struct smbd_server_connection *sconn,
        }
 
        if ((share_entry->op_type == NO_OPLOCK) &&
-           (fsp->oplock_type == FAKE_LEVEL_II_OPLOCK)) {
+           (fsp->oplock_type == FAKE_LEVEL_II_OPLOCK))
+       {
                /* Someone has already written to it, but I haven't yet
                 * noticed */
                return;
@@ -1683,7 +1698,8 @@ static NTSTATUS smbd_calculate_maximum_allowed_access(
        status = SMB_VFS_GET_NT_ACL(conn, smb_fname->base_name,
                                    (SECINFO_OWNER |
                                     SECINFO_GROUP |
-                                    SECINFO_DACL),&sd);
+                                    SECINFO_DACL),
+                                   talloc_tos(), &sd);
 
        if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
                /*
@@ -1700,7 +1716,13 @@ static NTSTATUS smbd_calculate_maximum_allowed_access(
        }
 
        /*
-        * Never test FILE_READ_ATTRIBUTES. se_file_access_check()
+        * If we can access the path to this file, by
+        * default we have FILE_READ_ATTRIBUTES from the
+        * containing directory. See the section:
+        * "Algorithm to Check Access to an Existing File"
+        * in MS-FSA.pdf.
+        *
+        * se_file_access_check()
         * also takes care of owner WRITE_DAC and READ_CONTROL.
         */
        status = se_file_access_check(sd,
@@ -1929,6 +1951,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
        bool def_acl = False;
        bool posix_open = False;
        bool new_file_created = False;
+       bool first_open_attempt = true;
        NTSTATUS fsp_open = NT_STATUS_ACCESS_DENIED;
        mode_t new_unx_mode = (mode_t)0;
        mode_t unx_mode = (mode_t)0;
@@ -1940,6 +1963,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) {
                /*
@@ -2029,6 +2058,8 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
 
                        /* Ensure we don't reprocess this message. */
                        remove_deferred_open_message_smb(req->sconn, req->mid);
+
+                       first_open_attempt = false;
                }
        }
 
@@ -2185,6 +2216,24 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                flags2 &= ~(O_CREAT|O_TRUNC);
        }
 
+       if (first_open_attempt && lp_kernel_oplocks(SNUM(conn))) {
+               /*
+                * With kernel oplocks the open breaking an oplock
+                * blocks until the oplock holder has given up the
+                * oplock or closed the file. We prevent this by first
+                * trying to open the file with O_NONBLOCK (see "man
+                * fcntl" on Linux). For the second try, triggered by
+                * an oplock break response, we do not need this
+                * anymore.
+                *
+                * This is true under the assumption that only Samba
+                * requests kernel oplocks. Once someone else like
+                * NFSv4 starts to use that API, we will have to
+                * modify this by communicating with the NFSv4 server.
+                */
+               flags2 |= O_NONBLOCK;
+       }
+
        /*
         * Ensure we can't write on a read-only share or file.
         */
@@ -2214,209 +2263,6 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                request_time = fsp->open_time;
        }
 
-       if (file_existed) {
-               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 file_id id;
-
-               struct timespec old_write_time = smb_fname->st.st_ex_mtime;
-               id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
-
-               lck = get_share_mode_lock(talloc_tos(), id,
-                                         conn->connectpath,
-                                         smb_fname, &old_write_time);
-               if (lck == NULL) {
-                       DEBUG(0, ("Could not get share mode lock\n"));
-                       return NT_STATUS_SHARING_VIOLATION;
-               }
-
-               /* 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);
-                       return NT_STATUS_SHARING_VIOLATION;
-               }
-
-               /* Use the client requested access mask here, not the one we
-                * open with. */
-               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_exclusive_oplocks(
-                                               fsp,
-                                               req->mid,
-                                               oplock_request,
-                                               exclusive_entry)) {
-                               schedule_defer_open(lck, request_time, req);
-                               TALLOC_FREE(lck);
-                               return NT_STATUS_SHARING_VIOLATION;
-                       }
-               }
-
-               if (NT_STATUS_EQUAL(status, NT_STATUS_DELETE_PENDING)) {
-                       /* DELETE_PENDING is not deferred for a second */
-                       TALLOC_FREE(lck);
-                       return status;
-               }
-
-               grant_fsp_oplock_type(fsp,
-                                oplock_request,
-                                got_level2_oplock,
-                                got_a_none_oplock);
-
-               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;
-                               }
-
-                               /* 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)) {
-                                       TALLOC_FREE(lck);
-                                       if (pinfo) {
-                                               *pinfo = FILE_WAS_OPENED;
-                                       }
-                                       return NT_STATUS_OK;
-                               }
-                       }
-
-                       /*
-                        * 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 (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 (((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 we're returning a share violation, ensure we
-                        * cope with the braindead 1 second delay.
-                        */
-
-                       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;
-               }
-
-               /*
-                * We exit this block with the share entry *locked*.....
-                */
-       }
-
-       SMB_ASSERT(!file_existed || (lck != NULL));
-
        /*
         * Ensure we pay attention to default ACLs on directories if required.
         */
@@ -2436,6 +2282,64 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                             flags|flags2, unx_mode, access_mask,
                             open_access_mask, &new_file_created);
 
+       if (NT_STATUS_EQUAL(fsp_open, NT_STATUS_NETWORK_BUSY)) {
+               struct deferred_open_record state;
+
+               /*
+                * EWOULDBLOCK/EAGAIN maps to NETWORK_BUSY.
+                */
+               if (file_existed && S_ISFIFO(fsp->fsp_name->st.st_ex_mode)) {
+                       DEBUG(10, ("FIFO busy\n"));
+                       return NT_STATUS_NETWORK_BUSY;
+               }
+               if (req == NULL) {
+                       DEBUG(10, ("Internal open busy\n"));
+                       return NT_STATUS_NETWORK_BUSY;
+               }
+
+               /*
+                * From here on we assume this is an oplock break triggered
+                */
+
+               lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
+               if (lck == NULL) {
+                       state.delayed_for_oplocks = false;
+                       state.async_open = false;
+                       state.id = fsp->file_id;
+                       defer_open(NULL, request_time, timeval_set(0, 0),
+                                  req, &state);
+                       DEBUG(10, ("No share mode lock found after "
+                                  "EWOULDBLOCK, retrying sync\n"));
+                       return NT_STATUS_SHARING_VIOLATION;
+               }
+
+               find_oplock_types(fsp, 0, lck, &batch_entry, &exclusive_entry,
+                                 &got_level2_oplock, &got_a_none_oplock);
+
+               if (delay_for_batch_oplocks(fsp, req->mid, 0, batch_entry) ||
+                   delay_for_exclusive_oplocks(fsp, req->mid, 0,
+                                               exclusive_entry)) {
+                       schedule_defer_open(lck, request_time, req);
+                       TALLOC_FREE(lck);
+                       DEBUG(10, ("Sent oplock break request to kernel "
+                                  "oplock holder\n"));
+                       return NT_STATUS_SHARING_VIOLATION;
+               }
+
+               /*
+                * No oplock from Samba around. Immediately retry with
+                * a blocking open.
+                */
+               state.delayed_for_oplocks = false;
+               state.async_open = false;
+               state.id = lck->data->id;
+               defer_open(lck, request_time, timeval_set(0, 0), req, &state);
+               TALLOC_FREE(lck);
+               DEBUG(10, ("No Samba oplock around after EWOULDBLOCK. "
+                          "Retrying sync\n"));
+               return NT_STATUS_SHARING_VIOLATION;
+       }
+
        if (!NT_STATUS_IS_OK(fsp_open)) {
                if (NT_STATUS_EQUAL(fsp_open, NT_STATUS_RETRY)) {
                        schedule_async_open(request_time, req);
@@ -2468,227 +2372,221 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                return NT_STATUS_ACCESS_DENIED;
        }
 
-       if (!file_existed) {
-               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);
+
+       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;
+       }
+
+       /* 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;
+       }
 
-               /* 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);
+       status = open_mode_check(conn, lck, fsp->name_hash,
+                                access_mask, share_access,
+                                create_options, &file_existed);
 
-               /* First pass - send break only on batch oplocks. */
+       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);
+               fd_close(fsp);
+               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);
+               fd_close(fsp);
+               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;
                }
-
-               grant_fsp_oplock_type(fsp,
-                                oplock_request,
-                                got_level2_oplock,
-                                got_a_none_oplock);
-
-               /*
-                * We exit this block with the share entry *locked*.....
-                */
-
+               return status;
        }
 
-       SMB_ASSERT(lck != NULL);
+       grant_fsp_oplock_type(fsp,
+                             oplock_request,
+                             got_level2_oplock,
+                             got_a_none_oplock);
+
+       /*
+        * We have the share entry *locked*.....
+        */
 
        /* Delete streams if create_disposition requires it */
        if (!new_file_created && clear_ads(create_disposition) &&
@@ -3549,7 +3447,7 @@ NTSTATUS open_streams_for_delete(connection_struct *conn,
 
 static NTSTATUS inherit_new_acl(files_struct *fsp)
 {
-       TALLOC_CTX *ctx = talloc_tos();
+       TALLOC_CTX *frame = talloc_stackframe();
        char *parent_name = NULL;
        struct security_descriptor *parent_desc = NULL;
        NTSTATUS status = NT_STATUS_OK;
@@ -3561,15 +3459,18 @@ static NTSTATUS inherit_new_acl(files_struct *fsp)
        bool inheritable_components = false;
        size_t size = 0;
 
-       if (!parent_dirname(ctx, fsp->fsp_name->base_name, &parent_name, NULL)) {
+       if (!parent_dirname(frame, fsp->fsp_name->base_name, &parent_name, NULL)) {
+               TALLOC_FREE(frame);
                return NT_STATUS_NO_MEMORY;
        }
 
        status = SMB_VFS_GET_NT_ACL(fsp->conn,
-                               parent_name,
-                               (SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL),
-                               &parent_desc);
+                                   parent_name,
+                                   (SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL),
+                                   frame,
+                                   &parent_desc);
        if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(frame);
                return status;
        }
 
@@ -3577,6 +3478,7 @@ static NTSTATUS inherit_new_acl(files_struct *fsp)
                                        fsp->is_directory);
 
        if (!inheritable_components && !inherit_owner) {
+               TALLOC_FREE(frame);
                /* Nothing to inherit and not setting owner. */
                return NT_STATUS_OK;
        }
@@ -3602,7 +3504,7 @@ static NTSTATUS inherit_new_acl(files_struct *fsp)
                group_sid = &fsp->conn->session_info->security_token->sids[PRIMARY_GROUP_SID_INDEX];
        }
 
-       status = se_create_child_secdesc(ctx,
+       status = se_create_child_secdesc(frame,
                        &psd,
                        &size,
                        parent_desc,
@@ -3610,6 +3512,7 @@ static NTSTATUS inherit_new_acl(files_struct *fsp)
                        group_sid,
                        fsp->is_directory);
        if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(frame);
                return status;
        }
 
@@ -3640,6 +3543,7 @@ static NTSTATUS inherit_new_acl(files_struct *fsp)
        if (inherit_owner) {
                unbecome_root();
        }
+       TALLOC_FREE(frame);
        return status;
 }