diff options
author | Volker Lendecke <vl@sernet.de> | 2007-12-02 15:35:22 +0100 |
---|---|---|
committer | Volker Lendecke <vl@sernet.de> | 2007-12-05 13:45:12 +0100 |
commit | 188daba1a7eaa7201bc29bfa1a958fe7a20fc790 (patch) | |
tree | 32f08e5e178232175dc8f939a69353c8ddbf8a20 /source3/smbd | |
parent | 756ce14d4956aece62eab12f468fa47a521b1c4a (diff) | |
download | samba-188daba1a7eaa7201bc29bfa1a958fe7a20fc790.tar.gz samba-188daba1a7eaa7201bc29bfa1a958fe7a20fc790.tar.bz2 samba-188daba1a7eaa7201bc29bfa1a958fe7a20fc790.zip |
Move create_file to open.c
I'm checking in this long sequence of micro-checkins for review, the overall
patch from 3b057022a5 to this is not too large.
(This used to be commit 51db8d09a4652d626c093f7bacf075c1c168fc33)
Diffstat (limited to 'source3/smbd')
-rw-r--r-- | source3/smbd/nttrans.c | 477 | ||||
-rw-r--r-- | source3/smbd/open.c | 475 |
2 files changed, 475 insertions, 477 deletions
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index 15306ee590..8a177c8e76 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -278,52 +278,6 @@ bool is_ntfs_stream_name(const char *fname) return (strchr_m(fname, ':') != NULL) ? True : False; } -struct case_semantics_state { - connection_struct *conn; - bool case_sensitive; - bool case_preserve; - bool short_case_preserve; -}; - -/**************************************************************************** - Restore case semantics. -****************************************************************************/ -static int restore_case_semantics(struct case_semantics_state *state) -{ - state->conn->case_sensitive = state->case_sensitive; - state->conn->case_preserve = state->case_preserve; - state->conn->short_case_preserve = state->short_case_preserve; - return 0; -} - -/**************************************************************************** - Save case semantics. -****************************************************************************/ -static struct case_semantics_state *set_posix_case_semantics(TALLOC_CTX *mem_ctx, - connection_struct *conn) -{ - struct case_semantics_state *result; - - if (!(result = talloc(mem_ctx, struct case_semantics_state))) { - DEBUG(0, ("talloc failed\n")); - return NULL; - } - - result->conn = conn; - result->case_sensitive = conn->case_sensitive; - result->case_preserve = conn->case_preserve; - result->short_case_preserve = conn->short_case_preserve; - - /* Set to POSIX. */ - conn->case_sensitive = True; - conn->case_preserve = True; - conn->short_case_preserve = True; - - talloc_set_destructor(result, restore_case_semantics); - - return result; -} - /**************************************************************************** Reply to an NT create and X call on a pipe ****************************************************************************/ @@ -452,437 +406,6 @@ static void do_ntcreate_pipe_open(connection_struct *conn, chain_reply(req); } -static NTSTATUS create_file(connection_struct *conn, - struct smb_request *req, - uint16_t root_dir_fid, - char *fname, - uint32_t flags, - uint32_t access_mask, - uint32_t file_attributes, - uint32_t share_access, - uint32_t create_disposition, - uint32_t create_options, - int oplock_request, - SMB_BIG_UINT allocation_size, - struct security_descriptor *sd, - struct ea_list *ea_list, - - files_struct **result, - int *pinfo, - uint8_t *poplock_granted, - SMB_STRUCT_STAT *psbuf) -{ - TALLOC_CTX *frame = talloc_stackframe(); - struct case_semantics_state *case_state = NULL; - SMB_STRUCT_STAT sbuf; - int info = FILE_WAS_OPENED; - files_struct *fsp = NULL; - uint8_t oplock_granted = NO_OPLOCK_RETURN; - NTSTATUS status; - - DEBUG(10,("create_file: flags = 0x%x, access_mask = 0x%x " - "file_attributes = 0x%x, share_access = 0x%x, " - "create_disposition = 0x%x create_options = 0x%x " - "root_dir_fid = 0x%x, ea_list = 0x%x, sd = 0x%x, " - "fname = %s\n", - (unsigned int)flags, - (unsigned int)access_mask, - (unsigned int)file_attributes, - (unsigned int)share_access, - (unsigned int)create_disposition, - (unsigned int)create_options, - (unsigned int)root_dir_fid, - (unsigned int)ea_list, - (unsigned int)sd, - fname)); - - SET_STAT_INVALID(sbuf); - - if (create_options & FILE_OPEN_BY_FILE_ID) { - status = NT_STATUS_NOT_SUPPORTED; - goto fail; - } - - /* - * Get the file name. - */ - - if (root_dir_fid != 0) { - /* - * This filename is relative to a directory fid. - */ - char *parent_fname = NULL; - files_struct *dir_fsp = file_fsp(root_dir_fid); - - if (dir_fsp == NULL) { - status = NT_STATUS_INVALID_HANDLE; - goto fail; - } - - if (!dir_fsp->is_directory) { - - /* - * Check to see if this is a mac fork of some kind. - */ - - if (is_ntfs_stream_name(fname)) { - status = NT_STATUS_OBJECT_PATH_NOT_FOUND; - goto fail; - } - - /* - we need to handle the case when we get a - relative open relative to a file and the - pathname is blank - this is a reopen! - (hint from demyn plantenberg) - */ - - status = NT_STATUS_INVALID_HANDLE; - goto fail; - } - - if (ISDOT(dir_fsp->fsp_name)) { - /* - * We're at the toplevel dir, the final file name - * must not contain ./, as this is filtered out - * normally by srvstr_get_path and unix_convert - * explicitly rejects paths containing ./. - */ - parent_fname = talloc_strdup(talloc_tos(), ""); - if (parent_fname == NULL) { - status = NT_STATUS_NO_MEMORY; - goto fail; - } - } else { - size_t dir_name_len = strlen(dir_fsp->fsp_name); - - /* - * Copy in the base directory name. - */ - - parent_fname = TALLOC_ARRAY(talloc_tos(), char, - dir_name_len+2); - if (parent_fname == NULL) { - status = NT_STATUS_NO_MEMORY; - goto fail; - } - memcpy(parent_fname, dir_fsp->fsp_name, - dir_name_len+1); - - /* - * Ensure it ends in a '/'. - * We used TALLOC_SIZE +2 to add space for the '/'. - */ - - if(dir_name_len - && (parent_fname[dir_name_len-1] != '\\') - && (parent_fname[dir_name_len-1] != '/')) { - parent_fname[dir_name_len] = '/'; - parent_fname[dir_name_len+1] = '\0'; - } - } - - fname = talloc_asprintf(talloc_tos(), "%s%s", parent_fname, - fname); - if (fname == NULL) { - status = NT_STATUS_NO_MEMORY; - goto fail; - } - } else { - /* - * Check to see if this is a mac fork of some kind. - */ - - if (is_ntfs_stream_name(fname)) { - enum FAKE_FILE_TYPE fake_file_type; - - fake_file_type = is_fake_file(fname); - - if (fake_file_type == FAKE_FILE_TYPE_NONE) { - return NT_STATUS_OBJECT_PATH_NOT_FOUND; - } - - /* - * Here we go! support for changing the disk quotas - * --metze - * - * We need to fake up to open this MAGIC QUOTA file - * and return a valid FID. - * - * w2k close this file directly after openening xp - * also tries a QUERY_FILE_INFO on the file and then - * close it - */ - status = open_fake_file(conn, fake_file_type, fname, - access_mask, &fsp); - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } - - goto done; - } - } - - oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0; - if (oplock_request) { - oplock_request |= (flags & REQUEST_BATCH_OPLOCK) - ? BATCH_OPLOCK : 0; - } - - status = resolve_dfspath( - talloc_tos(), conn, req->flags2 & FLAGS2_DFS_PATHNAMES, - fname, &fname); - - if (!NT_STATUS_IS_OK(status)) { - /* - * For PATH_NOT_COVERED we had - * reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, - * ERRSRV, ERRbadpath); - * Need to fix in callers - */ - goto fail; - } - - /* - * Ordinary file or directory. - */ - - /* - * Check if POSIX semantics are wanted. - */ - - if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) { - case_state = set_posix_case_semantics(talloc_tos(), conn); - file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS; - } - - status = unix_convert(talloc_tos(), conn, fname, False, &fname, NULL, - &sbuf); - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } - - /* All file access must go through check_name() */ - - status = check_name(conn, fname); - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } - - /* This is the correct thing to do (check every time) but can_delete - * is expensive (it may have to read the parent directory - * permissions). So for now we're not doing it unless we have a strong - * hint the client is really going to delete this file. If the client - * is forcing FILE_CREATE let the filesystem take care of the - * permissions. */ - - /* Setting FILE_SHARE_DELETE is the hint. */ - - if (lp_acl_check_permissions(SNUM(conn)) - && (create_disposition != FILE_CREATE) - && (share_access & FILE_SHARE_DELETE) - && (access_mask & DELETE_ACCESS) - && (((dos_mode(conn, fname, &sbuf) & FILE_ATTRIBUTE_READONLY) - && !lp_delete_readonly(SNUM(conn))) - || !can_delete_file_in_directory(conn, fname))) { - status = NT_STATUS_ACCESS_DENIED; - goto fail; - } - -#if 0 - /* We need to support SeSecurityPrivilege for this. */ - if ((access_mask & SEC_RIGHT_SYSTEM_SECURITY) && - !user_has_privileges(current_user.nt_user_token, - &se_security)) { - status = NT_STATUS_PRIVILEGE_NOT_HELD; - goto fail; - } -#endif - - /* - * If it's a request for a directory open, deal with it separately. - */ - - if (create_options & FILE_DIRECTORY_FILE) { - - /* Can't open a temp directory. IFS kit test. */ - if (file_attributes & FILE_ATTRIBUTE_TEMPORARY) { - status = NT_STATUS_INVALID_PARAMETER; - goto fail; - } - - /* - * We will get a create directory here if the Win32 - * app specified a security descriptor in the - * CreateDirectory() call. - */ - - oplock_request = 0; - status = open_directory( - conn, req, fname, &sbuf, access_mask, share_access, - create_disposition, create_options, file_attributes, - &info, &fsp); - } else { - - /* - * Ordinary file case. - */ - - status = open_file_ntcreate( - conn, req, fname, &sbuf, access_mask, share_access, - create_disposition, create_options, file_attributes, - oplock_request, &info, &fsp); - - if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) { - - /* - * Fail the open if it was explicitly a non-directory - * file. - */ - - if (create_options & FILE_NON_DIRECTORY_FILE) { - status = NT_STATUS_FILE_IS_A_DIRECTORY; - goto fail; - } - - oplock_request = 0; - status = open_directory( - conn, req, fname, &sbuf, access_mask, - share_access, create_disposition, - create_options, file_attributes, - &info, &fsp); - } - } - - TALLOC_FREE(case_state); - - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } - - /* - * According to the MS documentation, the only time the security - * descriptor is applied to the opened file is iff we *created* the - * file; an existing file stays the same. - * - * Also, it seems (from observation) that you can open the file with - * any access mask but you can still write the sd. We need to override - * the granted access before we call set_sd - * Patch for bug #2242 from Tom Lackemann <cessnatomny@yahoo.com>. - */ - - if ((sd != NULL) && (info == FILE_WAS_CREATED) - && lp_nt_acl_support(SNUM(conn))) { - - uint32_t sec_info_sent = ALL_SECURITY_INFORMATION; - uint32_t saved_access_mask = fsp->access_mask; - - if (sd->owner_sid==0) { - sec_info_sent &= ~OWNER_SECURITY_INFORMATION; - } - if (sd->group_sid==0) { - sec_info_sent &= ~GROUP_SECURITY_INFORMATION; - } - if (sd->sacl==0) { - sec_info_sent &= ~SACL_SECURITY_INFORMATION; - } - if (sd->dacl==0) { - sec_info_sent &= ~DACL_SECURITY_INFORMATION; - } - - fsp->access_mask = FILE_GENERIC_ALL; - - status = SMB_VFS_FSET_NT_ACL( - fsp, fsp->fh->fd, sec_info_sent, sd); - - fsp->access_mask = saved_access_mask; - - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } - } - - if ((ea_list != NULL) && (info == FILE_WAS_CREATED)) { - status = set_ea(conn, fsp, fname, ea_list); - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } - } - - if (!fsp->is_directory && S_ISDIR(sbuf.st_mode)) { - status = NT_STATUS_ACCESS_DENIED; - goto fail; - } - - /* Save the requested allocation size. */ - if ((info == FILE_WAS_CREATED) || (info == FILE_WAS_OVERWRITTEN)) { - if (allocation_size - && (allocation_size > sbuf.st_size)) { - fsp->initial_allocation_size = smb_roundup( - fsp->conn, allocation_size); - if (fsp->is_directory) { - /* Can't set allocation size on a directory. */ - status = NT_STATUS_ACCESS_DENIED; - goto fail; - } - if (vfs_allocate_file_space( - fsp, fsp->initial_allocation_size) == -1) { - status = NT_STATUS_DISK_FULL; - goto fail; - } - } else { - fsp->initial_allocation_size = smb_roundup( - fsp->conn, (SMB_BIG_UINT)sbuf.st_size); - } - } - - /* - * If the caller set the extended oplock request bit - * and we granted one (by whatever means) - set the - * correct bit for extended oplock reply. - */ - - if (oplock_request && - (lp_fake_oplocks(SNUM(conn)) - || EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))) { - - /* - * Exclusive oplock granted - */ - - if (flags & REQUEST_BATCH_OPLOCK) { - oplock_granted = BATCH_OPLOCK_RETURN; - } else { - oplock_granted = EXCLUSIVE_OPLOCK_RETURN; - } - } else if (fsp->oplock_type == LEVEL_II_OPLOCK) { - oplock_granted = LEVEL_II_OPLOCK_RETURN; - } else { - oplock_granted = NO_OPLOCK_RETURN; - } - - done: - DEBUG(10, ("create_file: info=%d, oplock_granted=%d\n", - info, (int)oplock_granted)); - - *result = fsp; - *pinfo = info; - *poplock_granted = oplock_granted; - *psbuf = sbuf; - TALLOC_FREE(frame); - return NT_STATUS_OK; - - fail: - DEBUG(10, ("create_file: %s\n", nt_errstr(status))); - - if (fsp != NULL) { - close_file(fsp, ERROR_CLOSE); - fsp = NULL; - } - TALLOC_FREE(frame); - return status; -} - /**************************************************************************** Reply to an NT create and X call. ****************************************************************************/ diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 6dc979cf3b..0a142cd416 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -2393,3 +2393,478 @@ void msg_file_was_renamed(struct messaging_context *msg, } } } + +struct case_semantics_state { + connection_struct *conn; + bool case_sensitive; + bool case_preserve; + bool short_case_preserve; +}; + +/**************************************************************************** + Restore case semantics. +****************************************************************************/ +static int restore_case_semantics(struct case_semantics_state *state) +{ + state->conn->case_sensitive = state->case_sensitive; + state->conn->case_preserve = state->case_preserve; + state->conn->short_case_preserve = state->short_case_preserve; + return 0; +} + +/**************************************************************************** + Save case semantics. +****************************************************************************/ +static struct case_semantics_state *set_posix_case_semantics(TALLOC_CTX *mem_ctx, + connection_struct *conn) +{ + struct case_semantics_state *result; + + if (!(result = talloc(mem_ctx, struct case_semantics_state))) { + DEBUG(0, ("talloc failed\n")); + return NULL; + } + + result->conn = conn; + result->case_sensitive = conn->case_sensitive; + result->case_preserve = conn->case_preserve; + result->short_case_preserve = conn->short_case_preserve; + + /* Set to POSIX. */ + conn->case_sensitive = True; + conn->case_preserve = True; + conn->short_case_preserve = True; + + talloc_set_destructor(result, restore_case_semantics); + + return result; +} + +/* + * Wrapper around open_file_ntcreate and open_directory + */ + +NTSTATUS create_file(connection_struct *conn, + struct smb_request *req, + uint16_t root_dir_fid, + char *fname, + uint32_t flags, + uint32_t access_mask, + uint32_t file_attributes, + uint32_t share_access, + uint32_t create_disposition, + uint32_t create_options, + int oplock_request, + SMB_BIG_UINT allocation_size, + struct security_descriptor *sd, + struct ea_list *ea_list, + + files_struct **result, + int *pinfo, + uint8_t *poplock_granted, + SMB_STRUCT_STAT *psbuf) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct case_semantics_state *case_state = NULL; + SMB_STRUCT_STAT sbuf; + int info = FILE_WAS_OPENED; + files_struct *fsp = NULL; + uint8_t oplock_granted = NO_OPLOCK_RETURN; + NTSTATUS status; + + DEBUG(10,("create_file: flags = 0x%x, access_mask = 0x%x " + "file_attributes = 0x%x, share_access = 0x%x, " + "create_disposition = 0x%x create_options = 0x%x " + "root_dir_fid = 0x%x, ea_list = 0x%p, sd = 0x%p, " + "fname = %s\n", + (unsigned int)flags, + (unsigned int)access_mask, + (unsigned int)file_attributes, + (unsigned int)share_access, + (unsigned int)create_disposition, + (unsigned int)create_options, + (unsigned int)root_dir_fid, + ea_list, sd, fname)); + + SET_STAT_INVALID(sbuf); + + if (create_options & FILE_OPEN_BY_FILE_ID) { + status = NT_STATUS_NOT_SUPPORTED; + goto fail; + } + + /* + * Get the file name. + */ + + if (root_dir_fid != 0) { + /* + * This filename is relative to a directory fid. + */ + char *parent_fname = NULL; + files_struct *dir_fsp = file_fsp(root_dir_fid); + + if (dir_fsp == NULL) { + status = NT_STATUS_INVALID_HANDLE; + goto fail; + } + + if (!dir_fsp->is_directory) { + + /* + * Check to see if this is a mac fork of some kind. + */ + + if (is_ntfs_stream_name(fname)) { + status = NT_STATUS_OBJECT_PATH_NOT_FOUND; + goto fail; + } + + /* + we need to handle the case when we get a + relative open relative to a file and the + pathname is blank - this is a reopen! + (hint from demyn plantenberg) + */ + + status = NT_STATUS_INVALID_HANDLE; + goto fail; + } + + if (ISDOT(dir_fsp->fsp_name)) { + /* + * We're at the toplevel dir, the final file name + * must not contain ./, as this is filtered out + * normally by srvstr_get_path and unix_convert + * explicitly rejects paths containing ./. + */ + parent_fname = talloc_strdup(talloc_tos(), ""); + if (parent_fname == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + } else { + size_t dir_name_len = strlen(dir_fsp->fsp_name); + + /* + * Copy in the base directory name. + */ + + parent_fname = TALLOC_ARRAY(talloc_tos(), char, + dir_name_len+2); + if (parent_fname == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + memcpy(parent_fname, dir_fsp->fsp_name, + dir_name_len+1); + + /* + * Ensure it ends in a '/'. + * We used TALLOC_SIZE +2 to add space for the '/'. + */ + + if(dir_name_len + && (parent_fname[dir_name_len-1] != '\\') + && (parent_fname[dir_name_len-1] != '/')) { + parent_fname[dir_name_len] = '/'; + parent_fname[dir_name_len+1] = '\0'; + } + } + + fname = talloc_asprintf(talloc_tos(), "%s%s", parent_fname, + fname); + if (fname == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + } else { + /* + * Check to see if this is a mac fork of some kind. + */ + + if (is_ntfs_stream_name(fname)) { + enum FAKE_FILE_TYPE fake_file_type; + + fake_file_type = is_fake_file(fname); + + if (fake_file_type == FAKE_FILE_TYPE_NONE) { + return NT_STATUS_OBJECT_PATH_NOT_FOUND; + } + + /* + * Here we go! support for changing the disk quotas + * --metze + * + * We need to fake up to open this MAGIC QUOTA file + * and return a valid FID. + * + * w2k close this file directly after openening xp + * also tries a QUERY_FILE_INFO on the file and then + * close it + */ + status = open_fake_file(conn, fake_file_type, fname, + access_mask, &fsp); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + goto done; + } + } + + oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0; + if (oplock_request) { + oplock_request |= (flags & REQUEST_BATCH_OPLOCK) + ? BATCH_OPLOCK : 0; + } + + status = resolve_dfspath( + talloc_tos(), conn, req->flags2 & FLAGS2_DFS_PATHNAMES, + fname, &fname); + + if (!NT_STATUS_IS_OK(status)) { + /* + * For PATH_NOT_COVERED we had + * reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, + * ERRSRV, ERRbadpath); + * Need to fix in callers + */ + goto fail; + } + + /* + * Check if POSIX semantics are wanted. + */ + + if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) { + case_state = set_posix_case_semantics(talloc_tos(), conn); + file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS; + } + + status = unix_convert(talloc_tos(), conn, fname, False, &fname, NULL, + &sbuf); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* All file access must go through check_name() */ + + status = check_name(conn, fname); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* This is the correct thing to do (check every time) but can_delete + * is expensive (it may have to read the parent directory + * permissions). So for now we're not doing it unless we have a strong + * hint the client is really going to delete this file. If the client + * is forcing FILE_CREATE let the filesystem take care of the + * permissions. */ + + /* Setting FILE_SHARE_DELETE is the hint. */ + + if (lp_acl_check_permissions(SNUM(conn)) + && (create_disposition != FILE_CREATE) + && (share_access & FILE_SHARE_DELETE) + && (access_mask & DELETE_ACCESS) + && (((dos_mode(conn, fname, &sbuf) & FILE_ATTRIBUTE_READONLY) + && !lp_delete_readonly(SNUM(conn))) + || !can_delete_file_in_directory(conn, fname))) { + status = NT_STATUS_ACCESS_DENIED; + goto fail; + } + +#if 0 + /* We need to support SeSecurityPrivilege for this. */ + if ((access_mask & SEC_RIGHT_SYSTEM_SECURITY) && + !user_has_privileges(current_user.nt_user_token, + &se_security)) { + status = NT_STATUS_PRIVILEGE_NOT_HELD; + goto fail; + } +#endif + + /* + * If it's a request for a directory open, deal with it separately. + */ + + if (create_options & FILE_DIRECTORY_FILE) { + + /* Can't open a temp directory. IFS kit test. */ + if (file_attributes & FILE_ATTRIBUTE_TEMPORARY) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + /* + * We will get a create directory here if the Win32 + * app specified a security descriptor in the + * CreateDirectory() call. + */ + + oplock_request = 0; + status = open_directory( + conn, req, fname, &sbuf, access_mask, share_access, + create_disposition, create_options, file_attributes, + &info, &fsp); + } else { + + /* + * Ordinary file case. + */ + + status = open_file_ntcreate( + conn, req, fname, &sbuf, access_mask, share_access, + create_disposition, create_options, file_attributes, + oplock_request, &info, &fsp); + + if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) { + + /* + * Fail the open if it was explicitly a non-directory + * file. + */ + + if (create_options & FILE_NON_DIRECTORY_FILE) { + status = NT_STATUS_FILE_IS_A_DIRECTORY; + goto fail; + } + + oplock_request = 0; + status = open_directory( + conn, req, fname, &sbuf, access_mask, + share_access, create_disposition, + create_options, file_attributes, + &info, &fsp); + } + } + + TALLOC_FREE(case_state); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* + * According to the MS documentation, the only time the security + * descriptor is applied to the opened file is iff we *created* the + * file; an existing file stays the same. + * + * Also, it seems (from observation) that you can open the file with + * any access mask but you can still write the sd. We need to override + * the granted access before we call set_sd + * Patch for bug #2242 from Tom Lackemann <cessnatomny@yahoo.com>. + */ + + if ((sd != NULL) && (info == FILE_WAS_CREATED) + && lp_nt_acl_support(SNUM(conn))) { + + uint32_t sec_info_sent = ALL_SECURITY_INFORMATION; + uint32_t saved_access_mask = fsp->access_mask; + + if (sd->owner_sid==0) { + sec_info_sent &= ~OWNER_SECURITY_INFORMATION; + } + if (sd->group_sid==0) { + sec_info_sent &= ~GROUP_SECURITY_INFORMATION; + } + if (sd->sacl==0) { + sec_info_sent &= ~SACL_SECURITY_INFORMATION; + } + if (sd->dacl==0) { + sec_info_sent &= ~DACL_SECURITY_INFORMATION; + } + + fsp->access_mask = FILE_GENERIC_ALL; + + status = SMB_VFS_FSET_NT_ACL( + fsp, fsp->fh->fd, sec_info_sent, sd); + + fsp->access_mask = saved_access_mask; + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + } + + if ((ea_list != NULL) && (info == FILE_WAS_CREATED)) { + status = set_ea(conn, fsp, fname, ea_list); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + } + + if (!fsp->is_directory && S_ISDIR(sbuf.st_mode)) { + status = NT_STATUS_ACCESS_DENIED; + goto fail; + } + + /* Save the requested allocation size. */ + if ((info == FILE_WAS_CREATED) || (info == FILE_WAS_OVERWRITTEN)) { + if (allocation_size + && (allocation_size > sbuf.st_size)) { + fsp->initial_allocation_size = smb_roundup( + fsp->conn, allocation_size); + if (fsp->is_directory) { + /* Can't set allocation size on a directory. */ + status = NT_STATUS_ACCESS_DENIED; + goto fail; + } + if (vfs_allocate_file_space( + fsp, fsp->initial_allocation_size) == -1) { + status = NT_STATUS_DISK_FULL; + goto fail; + } + } else { + fsp->initial_allocation_size = smb_roundup( + fsp->conn, (SMB_BIG_UINT)sbuf.st_size); + } + } + + /* + * If the caller set the extended oplock request bit + * and we granted one (by whatever means) - set the + * correct bit for extended oplock reply. + */ + + if (oplock_request && + (lp_fake_oplocks(SNUM(conn)) + || EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))) { + + /* + * Exclusive oplock granted + */ + + if (flags & REQUEST_BATCH_OPLOCK) { + oplock_granted = BATCH_OPLOCK_RETURN; + } else { + oplock_granted = EXCLUSIVE_OPLOCK_RETURN; + } + } else if (fsp->oplock_type == LEVEL_II_OPLOCK) { + oplock_granted = LEVEL_II_OPLOCK_RETURN; + } else { + oplock_granted = NO_OPLOCK_RETURN; + } + + done: + DEBUG(10, ("create_file: info=%d, oplock_granted=%d\n", + info, (int)oplock_granted)); + + *result = fsp; + *pinfo = info; + *poplock_granted = oplock_granted; + *psbuf = sbuf; + TALLOC_FREE(frame); + return NT_STATUS_OK; + + fail: + DEBUG(10, ("create_file: %s\n", nt_errstr(status))); + + if (fsp != NULL) { + close_file(fsp, ERROR_CLOSE); + fsp = NULL; + } + TALLOC_FREE(frame); + return status; +} |