return status;
}
+static NTSTATUS check_parent_access(struct connection_struct *conn,
+ struct smb_filename *smb_fname,
+ uint32_t access_mask,
+ char **pp_parent_dir,
+ struct security_descriptor **pp_parent_sd)
+{
+ NTSTATUS status;
+ char *parent_dir = NULL;
+ struct security_descriptor *parent_sd = NULL;
+ uint32_t access_granted = 0;
+
+ if (!parent_dirname(talloc_tos(),
+ smb_fname->base_name,
+ &parent_dir,
+ NULL)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = SMB_VFS_GET_NT_ACL(conn,
+ parent_dir,
+ SECINFO_DACL,
+ &parent_sd);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5,("check_parent_access: SMB_VFS_GET_NT_ACL failed for "
+ "%s with error %s\n",
+ parent_dir,
+ nt_errstr(status)));
+ return status;
+ }
+
+ status = smb1_file_se_access_check(conn,
+ parent_sd,
+ get_current_nttok(conn),
+ access_mask,
+ &access_granted);
+ if(!NT_STATUS_IS_OK(status)) {
+ DEBUG(5,("check_parent_access: access check "
+ "on directory %s for "
+ "path %s for mask 0x%x returned (0x%x) %s\n",
+ parent_dir,
+ smb_fname->base_name,
+ access_mask,
+ access_granted,
+ nt_errstr(status) ));
+ return status;
+ }
+
+ if (pp_parent_dir) {
+ *pp_parent_dir = parent_dir;
+ }
+ if (pp_parent_sd) {
+ *pp_parent_sd = parent_sd;
+ }
+ return NT_STATUS_OK;
+}
+
/****************************************************************************
fd support routines - attempt to do a dos_open.
****************************************************************************/
}
} else {
+ uint32_t access_granted = 0;
+
fsp->fh->fd = -1; /* What we used to call a stat open. */
- if (file_existed) {
- uint32_t access_granted = 0;
+ if (!file_existed) {
+ /* File must exist for a stat open. */
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
- status = smbd_check_open_rights(conn,
- smb_fname,
- access_mask,
- &access_granted);
- if (!NT_STATUS_IS_OK(status)) {
- if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
- /*
- * On NT_STATUS_ACCESS_DENIED, access_granted
- * contains the denied bits.
- */
-
- if ((access_mask & FILE_WRITE_ATTRIBUTES) &&
- (access_granted & FILE_WRITE_ATTRIBUTES) &&
- (lp_map_readonly(SNUM(conn)) ||
- lp_map_archive(SNUM(conn)) ||
- lp_map_hidden(SNUM(conn)) ||
- lp_map_system(SNUM(conn)))) {
- access_granted &= ~FILE_WRITE_ATTRIBUTES;
-
- DEBUG(10,("open_file: "
- "overrode "
- "FILE_WRITE_"
- "ATTRIBUTES "
- "on file %s\n",
- smb_fname_str_dbg(
- smb_fname)));
- }
+ status = smbd_check_open_rights(conn,
+ smb_fname,
+ access_mask,
+ &access_granted);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+ /*
+ * On NT_STATUS_ACCESS_DENIED, access_granted
+ * contains the denied bits.
+ */
- if ((access_mask & DELETE_ACCESS) &&
- (access_granted & DELETE_ACCESS) &&
- can_delete_file_in_directory(conn,
- smb_fname)) {
- /* Were we trying to do a stat open
- * for delete and didn't get DELETE
- * access (only) ? Check if the
- * directory allows DELETE_CHILD.
- * See here:
- * http://blogs.msdn.com/oldnewthing/archive/2004/06/04/148426.aspx
- * for details. */
-
- access_granted &= ~DELETE_ACCESS;
-
- DEBUG(10,("open_file: "
- "overrode "
- "DELETE_ACCESS on "
- "file %s\n",
- smb_fname_str_dbg(
- smb_fname)));
- }
+ if ((access_mask & FILE_WRITE_ATTRIBUTES) &&
+ (access_granted & FILE_WRITE_ATTRIBUTES) &&
+ (lp_map_readonly(SNUM(conn)) ||
+ lp_map_archive(SNUM(conn)) ||
+ lp_map_hidden(SNUM(conn)) ||
+ lp_map_system(SNUM(conn)))) {
+ access_granted &= ~FILE_WRITE_ATTRIBUTES;
- if (access_granted != 0) {
- DEBUG(10,("open_file: Access "
- "denied on file "
- "%s\n",
- smb_fname_str_dbg(
- smb_fname)));
- return status;
- }
- } else if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
- fsp->posix_open &&
- S_ISLNK(smb_fname->st.st_ex_mode)) {
- /* This is a POSIX stat open for delete
- * or rename on a symlink that points
- * nowhere. Allow. */
- DEBUG(10,("open_file: allowing POSIX "
- "open on bad symlink %s\n",
+ DEBUG(10,("open_file: "
+ "overrode "
+ "FILE_WRITE_"
+ "ATTRIBUTES "
+ "on file %s\n",
smb_fname_str_dbg(
smb_fname)));
- } else {
+ }
+
+ if ((access_mask & DELETE_ACCESS) &&
+ (access_granted & DELETE_ACCESS) &&
+ can_delete_file_in_directory(conn,
+ smb_fname)) {
+ /* Were we trying to do a stat open
+ * for delete and didn't get DELETE
+ * access (only) ? Check if the
+ * directory allows DELETE_CHILD.
+ * See here:
+ * http://blogs.msdn.com/oldnewthing/archive/2004/06/04/148426.aspx
+ * for details. */
+
+ access_granted &= ~DELETE_ACCESS;
+
DEBUG(10,("open_file: "
- "smbd_check_open_rights on file "
- "%s returned %s\n",
- smb_fname_str_dbg(smb_fname),
- nt_errstr(status) ));
+ "overrode "
+ "DELETE_ACCESS on "
+ "file %s\n",
+ smb_fname_str_dbg(
+ smb_fname)));
+ }
+
+ if (access_granted != 0) {
+ DEBUG(10,("open_file: Access "
+ "denied on file "
+ "%s\n",
+ smb_fname_str_dbg(
+ smb_fname)));
return status;
}
+ } else if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
+ fsp->posix_open &&
+ S_ISLNK(smb_fname->st.st_ex_mode)) {
+ /* This is a POSIX stat open for delete
+ * or rename on a symlink that points
+ * nowhere. Allow. */
+ DEBUG(10,("open_file: allowing POSIX "
+ "open on bad symlink %s\n",
+ smb_fname_str_dbg(
+ smb_fname)));
+ } else {
+ DEBUG(10,("open_file: "
+ "smbd_check_open_rights on file "
+ "%s returned %s\n",
+ smb_fname_str_dbg(smb_fname),
+ nt_errstr(status) ));
+ return status;
}
}
}
uint32 file_attributes)
{
mode_t mode;
- char *parent_dir;
+ char *parent_dir = NULL;
NTSTATUS status;
bool posix_open = false;
bool need_re_stat = false;
+ uint32_t access_mask = SEC_DIR_ADD_SUBDIR;
- if(!CAN_WRITE(conn)) {
- DEBUG(5,("mkdir_internal: failing create on read-only share "
+ if(access_mask & ~(conn->share_access)) {
+ DEBUG(5,("mkdir_internal: failing share access "
"%s\n", lp_servicename(SNUM(conn))));
return NT_STATUS_ACCESS_DENIED;
}
mode = unix_mode(conn, FILE_ATTRIBUTE_DIRECTORY, smb_dname, parent_dir);
}
+ status = check_parent_access(conn,
+ smb_dname,
+ access_mask,
+ &parent_dir,
+ NULL);
+ if(!NT_STATUS_IS_OK(status)) {
+ DEBUG(5,("mkdir_internal: check_parent_access "
+ "on directory %s for path %s returned %s\n",
+ parent_dir,
+ smb_dname->base_name,
+ nt_errstr(status) ));
+ return status;
+ }
+
if (SMB_VFS_MKDIR(conn, smb_dname->base_name, mode) != 0) {
return map_nt_error_from_unix(errno);
}
}
if (!S_ISDIR(smb_dname->st.st_ex_mode)) {
- DEBUG(0, ("Directory just '%s' created is not a directory\n",
+ DEBUG(0, ("Directory '%s' just created is not a directory !\n",
smb_fname_str_dbg(smb_dname)));
- return NT_STATUS_ACCESS_DENIED;
+ return NT_STATUS_NOT_A_DIRECTORY;
}
if (lp_store_dos_attributes(SNUM(conn))) {
/* If directory exists error. If directory doesn't
* exist create. */
+ if (dir_existed) {
+ status = NT_STATUS_OBJECT_NAME_COLLISION;
+ DEBUG(2, ("open_directory: unable to create "
+ "%s. Error was %s\n",
+ smb_fname_str_dbg(smb_dname),
+ nt_errstr(status)));
+ return status;
+ }
+
status = mkdir_internal(conn, smb_dname,
file_attributes);
* exist create.
*/
- status = mkdir_internal(conn, smb_dname,
+ if (dir_existed) {
+ status = NT_STATUS_OK;
+ info = FILE_WAS_OPENED;
+ } else {
+ status = mkdir_internal(conn, smb_dname,
file_attributes);
- if (NT_STATUS_IS_OK(status)) {
- info = FILE_WAS_CREATED;
+ if (NT_STATUS_IS_OK(status)) {
+ info = FILE_WAS_CREATED;
+ } else {
+ /* Cope with create race. */
+ if (!NT_STATUS_EQUAL(status,
+ NT_STATUS_OBJECT_NAME_COLLISION)) {
+ DEBUG(2, ("open_directory: unable to create "
+ "%s. Error was %s\n",
+ smb_fname_str_dbg(smb_dname),
+ nt_errstr(status)));
+ return status;
+ }
+ info = FILE_WAS_OPENED;
+ }
}
- if (NT_STATUS_EQUAL(status,
- NT_STATUS_OBJECT_NAME_COLLISION)) {
- info = FILE_WAS_OPENED;
- status = NT_STATUS_OK;
- }
break;
case FILE_SUPERSEDE:
TALLOC_CTX *frame = talloc_stackframe();
NTSTATUS status;
- status = SMB_VFS_STREAMINFO(conn, NULL, fname, talloc_tos(),
- &num_streams, &stream_info);
+ status = vfs_streaminfo(conn, NULL, fname, talloc_tos(),
+ &num_streams, &stream_info);
if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)
|| NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
}
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(10, ("SMB_VFS_STREAMINFO failed: %s\n",
+ DEBUG(10, ("vfs_streaminfo failed: %s\n",
nt_errstr(status)));
goto fail;
}