X-Git-Url: http://git.samba.org/samba.git/?p=kai%2Fsamba.git;a=blobdiff_plain;f=source3%2Fsmbd%2Fopen.c;h=d736f4f795bb05d935afff6060f326e9e7c5761d;hp=8c24ef9ff108ab51b66ac2ff4f6ff49dd022a2bc;hb=b3eb78c4f7123ccad6af50379c29d0939590d1ff;hpb=cc58a19565870d62b3d3476b4b718fcd1ff94a46 diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 8c24ef9ff10..d736f4f795b 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -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, @@ -678,7 +691,8 @@ static NTSTATUS open_file(files_struct *fsp, DEBUG(3,("Permission denied opening %s\n", smb_fname_str_dbg(smb_fname))); return NT_STATUS_ACCESS_DENIED; - } else if(flags & O_CREAT) { + } + if (flags & O_CREAT) { /* We don't want to write - but we must make sure that O_CREAT doesn't create the file if we have write access into the directory. @@ -1010,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", @@ -1036,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; @@ -1570,7 +1586,8 @@ static NTSTATUS fcb_or_dos_open(struct smb_request *req, (unsigned int)fsp->fh->private_options, (unsigned int)fsp->access_mask )); - if (fsp->fh->fd != -1 && + if (fsp != fsp_to_dup_into && + fsp->fh->fd != -1 && fsp->vuid == vuid && fsp->file_pid == file_pid && (fsp->fh->private_options & (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | @@ -1681,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)) { /* @@ -1698,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, @@ -1873,8 +1897,7 @@ static int calculate_open_access_flags(uint32_t access_mask, int oplock_request, uint32_t private_flags) { - int flags; - bool need_write; + bool need_write, need_read; /* * Note that we ignore the append flag as append does not @@ -1892,14 +1915,16 @@ static int calculate_open_access_flags(uint32_t access_mask, /* DENY_DOS opens are always underlying read-write on the file handle, no matter what the requested access mask says. */ - if ((private_flags & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS) || - access_mask & (FILE_READ_ATTRIBUTES|FILE_READ_DATA| - FILE_READ_EA|FILE_EXECUTE)) { - flags = O_RDWR; - } else { - flags = O_WRONLY; + + need_read = + ((private_flags & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS) || + access_mask & (FILE_READ_ATTRIBUTES|FILE_READ_DATA| + FILE_READ_EA|FILE_EXECUTE)); + + if (!need_read) { + return O_WRONLY; } - return flags; + return O_RDWR; } /**************************************************************************** @@ -1926,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; @@ -1937,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) { /* @@ -2026,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; } } @@ -2182,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. */ @@ -2211,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. */ @@ -2433,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); @@ -2465,120 +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 . 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 . 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; + } + + /* 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); - /* 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; + } + + /* 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; } } - if (!NT_STATUS_IS_OK(status)) { + /* + * 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; - /* 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... */ - - if (req != NULL) { - defer_open(lck, request_time, timeval_zero(), + if ((req != NULL) + && !request_timed_out(request_time, + timeout)) { + defer_open(lck, request_time, timeout, req, &state); } - TALLOC_FREE(lck); - fd_close(fsp); - return status; } - grant_fsp_oplock_type(fsp, - oplock_request, - got_level2_oplock, - got_a_none_oplock); - - /* - * We exit this block with the share entry *locked*..... - */ - + TALLOC_FREE(lck); + fd_close(fsp); + 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; } - 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) && @@ -2813,7 +2821,7 @@ static NTSTATUS mkdir_internal(connection_struct *conn, bool need_re_stat = false; uint32_t access_mask = SEC_DIR_ADD_SUBDIR; - if(access_mask & ~(conn->share_access)) { + if (!CAN_WRITE(conn) || (access_mask & ~(conn->share_access))) { DEBUG(5,("mkdir_internal: failing share access " "%s\n", lp_servicename(talloc_tos(), SNUM(conn)))); return NT_STATUS_ACCESS_DENIED; @@ -3439,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; @@ -3451,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; } @@ -3467,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; } @@ -3492,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, @@ -3500,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; } @@ -3530,6 +3543,7 @@ static NTSTATUS inherit_new_acl(files_struct *fsp) if (inherit_owner) { unbecome_root(); } + TALLOC_FREE(frame); return status; }