diff options
author | bubulle <bubulle@alioth.debian.org> | 2010-04-04 16:44:16 +0000 |
---|---|---|
committer | bubulle <bubulle@alioth.debian.org> | 2010-04-04 16:44:16 +0000 |
commit | 9e2f5a6ab663f7a111832217c527508c75ddae8a (patch) | |
tree | 2e74616febbb3fb658ce2dcc5f9cff00ad4fdb4a /source3/smbd/file_access.c | |
parent | b5556af8f75a4f74db404dd43ee7abafa2be6ca4 (diff) | |
download | samba-9e2f5a6ab663f7a111832217c527508c75ddae8a.tar.gz |
Merge 3.5.1 from experimental
git-svn-id: svn://svn.debian.org/svn/pkg-samba/trunk/samba@3414 fc4039ab-9d04-0410-8cac-899223bdd6b0
Diffstat (limited to 'source3/smbd/file_access.c')
-rw-r--r-- | source3/smbd/file_access.c | 112 |
1 files changed, 71 insertions, 41 deletions
diff --git a/source3/smbd/file_access.c b/source3/smbd/file_access.c index 1c0124ecbc..7d0a552956 100644 --- a/source3/smbd/file_access.c +++ b/source3/smbd/file_access.c @@ -27,32 +27,36 @@ * 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; + 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 = SMB_VFS_GET_NT_ACL(conn, fname, + status = SMB_VFS_GET_NT_ACL(conn, smb_fname->base_name, (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION), &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(secdesc); - return NT_STATUS_IS_OK(status); + return ret; } /**************************************************************************** @@ -60,50 +64,67 @@ bool can_access_file_acl(struct connection_struct *conn, this to successfully return ACCESS_DENIED on a file open for delete access. ****************************************************************************/ -bool can_delete_file_in_directory(connection_struct *conn, const char *fname) +bool can_delete_file_in_directory(connection_struct *conn, + 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; } /* Get the parent directory permission mask and owners. */ - if (!parent_dirname(ctx, fname, &dname, NULL)) { + 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_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_mode & S_ISVTX) { - SMB_STRUCT_STAT sbuf_file; - if(SMB_VFS_STAT(conn, fname, &sbuf_file) != 0) { + 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)", - fname, strerror(errno) )); - return False; + "stat file %s (%s)", + smb_fname_str_dbg(smb_fname), + strerror(errno) )); + ret = false; + goto out; } + /* * Patch from SATOH Fumiyasu <fumiyas@miraclelinux.com> * for bug #3348. Don't assume owning sticky bit @@ -112,12 +133,15 @@ bool can_delete_file_in_directory(connection_struct *conn, const char *fname) * 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_uid) && - (conn->server_info->utok.uid != sbuf_file.st_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", - fname, dname)); - return False; + "owner of file %s or directory %s", + smb_fname_str_dbg(smb_fname), + smb_fname_str_dbg(smb_fname_parent))); + ret = false; + goto out; } } #endif @@ -133,7 +157,11 @@ bool can_delete_file_in_directory(connection_struct *conn, const char *fname) * 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; } /**************************************************************************** @@ -142,7 +170,9 @@ bool can_delete_file_in_directory(connection_struct *conn, const char *fname) Note this doesn't take into account share write permissions. ****************************************************************************/ -bool can_access_file_data(connection_struct *conn, const char *fname, 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; @@ -152,32 +182,31 @@ bool can_access_file_data(connection_struct *conn, const char *fname, SMB_STRUCT /* 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; } - if (!VALID_STAT(*psbuf)) { - /* Get the file permission mask and owners. */ - if(SMB_VFS_STAT(conn, fname, psbuf) != 0) { - return False; - } - } + SMB_ASSERT(VALID_STAT(smb_fname->st)); /* Check primary owner access. */ - if (conn->server_info->utok.uid == psbuf->st_uid) { + if (conn->server_info->utok.uid == smb_fname->st.st_ex_uid) { switch (access_mask) { case FILE_READ_DATA: - return (psbuf->st_mode & S_IRUSR) ? True : False; + return (smb_fname->st.st_ex_mode & S_IRUSR) ? + True : False; case FILE_WRITE_DATA: - return (psbuf->st_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_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; @@ -187,7 +216,7 @@ bool can_access_file_data(connection_struct *conn, const char *fname, SMB_STRUCT /* now for ACL checks */ - return can_access_file_acl(conn, fname, access_mask); + return can_access_file_acl(conn, smb_fname, access_mask); } /**************************************************************************** @@ -195,9 +224,10 @@ bool can_access_file_data(connection_struct *conn, const char *fname, SMB_STRUCT Note this doesn't take into account share write permissions. ****************************************************************************/ -bool can_write_to_file(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf) +bool can_write_to_file(connection_struct *conn, + const struct smb_filename *smb_fname) { - return can_access_file_data(conn, fname, psbuf, FILE_WRITE_DATA); + return can_access_file_data(conn, smb_fname, FILE_WRITE_DATA); } /**************************************************************************** |