diff options
Diffstat (limited to 'source3/smbd/file_access.c')
-rw-r--r-- | source3/smbd/file_access.c | 123 |
1 files changed, 83 insertions, 40 deletions
diff --git a/source3/smbd/file_access.c b/source3/smbd/file_access.c index 195f722471..87d45c5e7f 100644 --- a/source3/smbd/file_access.c +++ b/source3/smbd/file_access.c @@ -27,18 +27,26 @@ * Security descriptor / NT Token level access check function. */ bool can_access_file_acl(struct connection_struct *conn, - const char * fname, - uint32_t access_mask) + const struct smb_filename *smb_fname, + uint32_t access_mask) { NTSTATUS status; uint32_t access_granted; struct security_descriptor *secdesc = NULL; + char *fname = NULL; + bool ret; if (conn->server_info->utok.uid == 0 || conn->admin_user) { /* I'm sorry sir, I didn't know you were root... */ return true; } + status = get_full_smb_filename(talloc_tos(), smb_fname, &fname); + if (!NT_STATUS_IS_OK(status)) { + ret = false; + goto out; + } + status = SMB_VFS_GET_NT_ACL(conn, fname, (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | @@ -46,13 +54,17 @@ bool can_access_file_acl(struct connection_struct *conn, &secdesc); if (!NT_STATUS_IS_OK(status)) { DEBUG(5, ("Could not get acl: %s\n", nt_errstr(status))); - return false; + ret = false; + goto out; } status = se_access_check(secdesc, conn->server_info->ptok, access_mask, &access_granted); + ret = NT_STATUS_IS_OK(status); + out: + TALLOC_FREE(fname); TALLOC_FREE(secdesc); - return NT_STATUS_IS_OK(status); + return ret; } /**************************************************************************** @@ -61,11 +73,13 @@ bool can_access_file_acl(struct connection_struct *conn, ****************************************************************************/ bool can_delete_file_in_directory(connection_struct *conn, - const struct smb_filename *smb_fname) + struct smb_filename *smb_fname) { - SMB_STRUCT_STAT sbuf; TALLOC_CTX *ctx = talloc_tos(); char *dname = NULL; + struct smb_filename *smb_fname_parent = NULL; + NTSTATUS status; + bool ret; if (!CAN_WRITE(conn)) { return False; @@ -75,47 +89,49 @@ bool can_delete_file_in_directory(connection_struct *conn, if (!parent_dirname(ctx, smb_fname->base_name, &dname, NULL)) { return False; } - if(SMB_VFS_STAT(conn, dname, &sbuf) != 0) { - return False; + + status = create_synthetic_smb_fname(ctx, dname, NULL, NULL, + &smb_fname_parent); + if (!NT_STATUS_IS_OK(status)) { + ret = false; + goto out; + } + + if(SMB_VFS_STAT(conn, smb_fname_parent) != 0) { + ret = false; + goto out; } /* fast paths first */ - if (!S_ISDIR(sbuf.st_ex_mode)) { - return False; + if (!S_ISDIR(smb_fname_parent->st.st_ex_mode)) { + ret = false; + goto out; } if (conn->server_info->utok.uid == 0 || conn->admin_user) { /* I'm sorry sir, I didn't know you were root... */ - return True; + ret = true; + goto out; } #ifdef S_ISVTX /* sticky bit means delete only by owner of file or by root or * by owner of directory. */ - if (sbuf.st_ex_mode & S_ISVTX) { - SMB_STRUCT_STAT sbuf_file; - char *fname = NULL; - NTSTATUS status; - - status = get_full_smb_filename(talloc_tos(), smb_fname, - &fname); - if (!NT_STATUS_IS_OK(status)) { - return false; - } - if(SMB_VFS_STAT(conn, fname, &sbuf_file) != 0) { - TALLOC_FREE(fname); + if (smb_fname_parent->st.st_ex_mode & S_ISVTX) { + if(SMB_VFS_STAT(conn, smb_fname) != 0) { if (errno == ENOENT) { /* If the file doesn't already exist then * yes we'll be able to delete it. */ - return True; + ret = true; + goto out; } DEBUG(10,("can_delete_file_in_directory: can't " "stat file %s (%s)", smb_fname_str_dbg(smb_fname), strerror(errno) )); - return False; + ret = false; + goto out; } - TALLOC_FREE(fname); /* * Patch from SATOH Fumiyasu <fumiyas@miraclelinux.com> @@ -125,12 +141,15 @@ bool can_delete_file_in_directory(connection_struct *conn, * or the owner of the directory as we have no possible * chance of deleting. Otherwise, go on and check the ACL. */ - if ((conn->server_info->utok.uid != sbuf.st_ex_uid) && - (conn->server_info->utok.uid != sbuf_file.st_ex_uid)) { + if ((conn->server_info->utok.uid != + smb_fname_parent->st.st_ex_uid) && + (conn->server_info->utok.uid != smb_fname->st.st_ex_uid)) { DEBUG(10,("can_delete_file_in_directory: not " "owner of file %s or directory %s", - smb_fname_str_dbg(smb_fname), dname)); - return False; + smb_fname_str_dbg(smb_fname), + smb_fname_str_dbg(smb_fname_parent))); + ret = false; + goto out; } } #endif @@ -146,7 +165,11 @@ bool can_delete_file_in_directory(connection_struct *conn, * check the file DELETE permission separately. */ - return can_access_file_acl(conn, dname, FILE_DELETE_CHILD); + ret = can_access_file_acl(conn, smb_fname_parent, FILE_DELETE_CHILD); + out: + TALLOC_FREE(dname); + TALLOC_FREE(smb_fname_parent); + return ret; } /**************************************************************************** @@ -155,7 +178,9 @@ bool can_delete_file_in_directory(connection_struct *conn, Note this doesn't take into account share write permissions. ****************************************************************************/ -bool can_access_file_data(connection_struct *conn, const char *fname, const SMB_STRUCT_STAT *psbuf, uint32 access_mask) +bool can_access_file_data(connection_struct *conn, + const struct smb_filename *smb_fname, + uint32 access_mask) { if (!(access_mask & (FILE_READ_DATA|FILE_WRITE_DATA))) { return False; @@ -165,27 +190,31 @@ bool can_access_file_data(connection_struct *conn, const char *fname, const SMB_ /* some fast paths first */ DEBUG(10,("can_access_file_data: requesting 0x%x on file %s\n", - (unsigned int)access_mask, fname )); + (unsigned int)access_mask, smb_fname_str_dbg(smb_fname))); if (conn->server_info->utok.uid == 0 || conn->admin_user) { /* I'm sorry sir, I didn't know you were root... */ return True; } - SMB_ASSERT(psbuf && VALID_STAT(*psbuf)); + SMB_ASSERT(VALID_STAT(smb_fname->st)); /* Check primary owner access. */ - if (conn->server_info->utok.uid == psbuf->st_ex_uid) { + if (conn->server_info->utok.uid == smb_fname->st.st_ex_uid) { switch (access_mask) { case FILE_READ_DATA: - return (psbuf->st_ex_mode & S_IRUSR) ? True : False; + return (smb_fname->st.st_ex_mode & S_IRUSR) ? + True : False; case FILE_WRITE_DATA: - return (psbuf->st_ex_mode & S_IWUSR) ? True : False; + return (smb_fname->st.st_ex_mode & S_IWUSR) ? + True : False; default: /* FILE_READ_DATA|FILE_WRITE_DATA */ - if ((psbuf->st_ex_mode & (S_IWUSR|S_IRUSR)) == (S_IWUSR|S_IRUSR)) { + if ((smb_fname->st.st_ex_mode & + (S_IWUSR|S_IRUSR)) == + (S_IWUSR|S_IRUSR)) { return True; } else { return False; @@ -195,7 +224,7 @@ bool can_access_file_data(connection_struct *conn, const char *fname, const SMB_ /* now for ACL checks */ - return can_access_file_acl(conn, fname, access_mask); + return can_access_file_acl(conn, smb_fname, access_mask); } /**************************************************************************** @@ -205,7 +234,21 @@ bool can_access_file_data(connection_struct *conn, const char *fname, const SMB_ bool can_write_to_file(connection_struct *conn, const char *fname, const SMB_STRUCT_STAT *psbuf) { - return can_access_file_data(conn, fname, psbuf, FILE_WRITE_DATA); + struct smb_filename *smb_fname; + NTSTATUS status; + bool ret; + + status = create_synthetic_smb_fname_split(talloc_tos(), fname, psbuf, + &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + return false; + } + + ret = can_access_file_data(conn, smb_fname, FILE_WRITE_DATA); + + TALLOC_FREE(smb_fname); + + return ret; } /**************************************************************************** |