2007-10-26 21:50:55 +04:00
/*
Unix SMB / CIFS implementation .
Check access to files based on security descriptors .
Copyright ( C ) Jeremy Allison 2005 - 2006.
Copyright ( C ) Michael Adam 2007.
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
2011-02-26 01:20:06 +03:00
# include "system/filesys.h"
2010-10-12 08:27:50 +04:00
# include "../libcli/security/security.h"
2010-05-28 04:19:32 +04:00
# include "../librpc/gen_ndr/ndr_security.h"
2011-03-22 18:57:01 +03:00
# include "smbd/smbd.h"
2007-10-26 21:50:55 +04:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_ACLS
/****************************************************************************
Actually emulate the in - kernel access checking for delete access . We need
this to successfully return ACCESS_DENIED on a file open for delete access .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-06-16 01:14:31 +04:00
bool can_delete_file_in_directory ( connection_struct * conn ,
2011-11-05 02:39:55 +04:00
const struct smb_filename * smb_fname )
2007-10-26 21:50:55 +04:00
{
TALLOC_CTX * ctx = talloc_tos ( ) ;
char * dname = NULL ;
2009-06-23 02:26:56 +04:00
struct smb_filename * smb_fname_parent = NULL ;
NTSTATUS status ;
bool ret ;
2007-10-26 21:50:55 +04:00
if ( ! CAN_WRITE ( conn ) ) {
return False ;
}
2011-06-24 02:06:16 +04:00
if ( ! lp_acl_check_permissions ( SNUM ( conn ) ) ) {
/* This option means don't check. */
return true ;
}
2007-10-26 21:50:55 +04:00
/* Get the parent directory permission mask and owners. */
2009-06-16 01:14:31 +04:00
if ( ! parent_dirname ( ctx , smb_fname - > base_name , & dname , NULL ) ) {
2007-10-26 21:50:55 +04:00
return False ;
}
2009-06-23 02:26:56 +04:00
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 ;
2007-10-26 21:50:55 +04:00
}
/* fast paths first */
2009-06-23 02:26:56 +04:00
if ( ! S_ISDIR ( smb_fname_parent - > st . st_ex_mode ) ) {
ret = false ;
goto out ;
2007-10-26 21:50:55 +04:00
}
2010-03-15 22:13:30 +03:00
if ( get_current_uid ( conn ) = = ( uid_t ) 0 ) {
2007-10-26 21:50:55 +04:00
/* I'm sorry sir, I didn't know you were root... */
2009-06-23 02:26:56 +04:00
ret = true ;
goto out ;
2007-10-26 21:50:55 +04:00
}
# ifdef S_ISVTX
2009-06-11 23:51:45 +04:00
/* sticky bit means delete only by owner of file or by root or
* by owner of directory . */
2009-06-23 02:26:56 +04:00
if ( smb_fname_parent - > st . st_ex_mode & S_ISVTX ) {
2011-11-05 02:39:55 +04:00
if ( ! VALID_STAT ( smb_fname - > st ) ) {
/* If the file doesn't already exist then
* yes we ' ll be able to delete it . */
ret = true ;
2009-06-23 02:26:56 +04:00
goto out ;
2007-10-26 21:50:55 +04:00
}
2009-06-16 01:14:31 +04:00
2007-10-26 21:50:55 +04:00
/*
* Patch from SATOH Fumiyasu < fumiyas @ miraclelinux . com >
* for bug # 3348. Don ' t assume owning sticky bit
* directory means write access allowed .
2009-06-11 23:51:45 +04:00
* Fail to delete if we ' re not the owner of the file ,
* or the owner of the directory as we have no possible
* chance of deleting . Otherwise , go on and check the ACL .
2007-10-26 21:50:55 +04:00
*/
2010-03-15 22:13:30 +03:00
if ( ( get_current_uid ( conn ) ! =
2009-06-23 02:26:56 +04:00
smb_fname_parent - > st . st_ex_uid ) & &
2010-03-15 22:13:30 +03:00
( get_current_uid ( conn ) ! = smb_fname - > st . st_ex_uid ) ) {
2009-06-11 23:51:45 +04:00
DEBUG ( 10 , ( " can_delete_file_in_directory: not "
2009-06-16 01:14:31 +04:00
" owner of file %s or directory %s " ,
2009-06-23 02:26:56 +04:00
smb_fname_str_dbg ( smb_fname ) ,
smb_fname_str_dbg ( smb_fname_parent ) ) ) ;
ret = false ;
goto out ;
2007-10-26 21:50:55 +04:00
}
}
# endif
/* now for ACL checks */
2008-06-19 16:53:46 +04:00
/*
* There ' s two ways to get the permission to delete a file : First by
* having the DELETE bit on the file itself and second if that does
* not help , by the DELETE_CHILD bit on the containing directory .
*
2009-02-03 04:10:27 +03:00
* Here we only check the directory permissions , we will
* check the file DELETE permission separately .
2008-06-19 16:53:46 +04:00
*/
2011-11-05 02:55:11 +04:00
ret = NT_STATUS_IS_OK ( smbd_check_access_rights ( conn ,
smb_fname_parent ,
FILE_DELETE_CHILD ) ) ;
2009-06-23 02:26:56 +04:00
out :
TALLOC_FREE ( dname ) ;
TALLOC_FREE ( smb_fname_parent ) ;
return ret ;
2007-10-26 21:50:55 +04:00
}
/****************************************************************************
Userspace check for write access .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-06-26 05:19:09 +04:00
bool can_write_to_file ( connection_struct * conn ,
const struct smb_filename * smb_fname )
2007-10-26 21:50:55 +04:00
{
2011-11-05 02:45:13 +04:00
return NT_STATUS_IS_OK ( smbd_check_access_rights ( conn ,
smb_fname ,
FILE_WRITE_DATA ) ) ;
2007-10-26 21:50:55 +04:00
}
2008-05-02 21:09:00 +04:00
/****************************************************************************
Check for an existing default Windows ACL on a directory .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool directory_has_default_acl ( connection_struct * conn , const char * fname )
{
/* returns talloced off tos. */
struct security_descriptor * secdesc = NULL ;
unsigned int i ;
NTSTATUS status = SMB_VFS_GET_NT_ACL ( conn , fname ,
2010-06-03 01:35:44 +04:00
SECINFO_DACL , & secdesc ) ;
2008-05-02 21:09:00 +04:00
2012-03-29 02:09:47 +04:00
if ( ! NT_STATUS_IS_OK ( status ) | |
secdesc = = NULL | |
secdesc - > dacl = = NULL ) {
TALLOC_FREE ( secdesc ) ;
2008-05-02 21:09:00 +04:00
return false ;
}
for ( i = 0 ; i < secdesc - > dacl - > num_aces ; i + + ) {
struct security_ace * psa = & secdesc - > dacl - > aces [ i ] ;
if ( psa - > flags & ( SEC_ACE_FLAG_OBJECT_INHERIT |
SEC_ACE_FLAG_CONTAINER_INHERIT ) ) {
TALLOC_FREE ( secdesc ) ;
return true ;
}
}
TALLOC_FREE ( secdesc ) ;
return false ;
}
2011-12-13 19:01:59 +04:00
/****************************************************************************
Check if setting delete on close is allowed on this fsp .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS can_set_delete_on_close ( files_struct * fsp , uint32 dosmode )
{
/*
* Only allow delete on close for writable files .
*/
if ( ( dosmode & FILE_ATTRIBUTE_READONLY ) & &
! lp_delete_readonly ( SNUM ( fsp - > conn ) ) ) {
DEBUG ( 10 , ( " can_set_delete_on_close: file %s delete on close "
" flag set but file attribute is readonly. \n " ,
fsp_str_dbg ( fsp ) ) ) ;
return NT_STATUS_CANNOT_DELETE ;
}
/*
* Only allow delete on close for writable shares .
*/
if ( ! CAN_WRITE ( fsp - > conn ) ) {
DEBUG ( 10 , ( " can_set_delete_on_close: file %s delete on "
" close flag set but write access denied on share. \n " ,
fsp_str_dbg ( fsp ) ) ) ;
return NT_STATUS_ACCESS_DENIED ;
}
/*
* Only allow delete on close for files / directories opened with delete
* intent .
*/
if ( ! ( fsp - > access_mask & DELETE_ACCESS ) ) {
DEBUG ( 10 , ( " can_set_delete_on_close: file %s delete on "
" close flag set but delete access denied. \n " ,
fsp_str_dbg ( fsp ) ) ) ;
return NT_STATUS_ACCESS_DENIED ;
}
/* Don't allow delete on close for non-empty directories. */
if ( fsp - > is_directory ) {
SMB_ASSERT ( ! is_ntfs_stream_smb_fname ( fsp - > fsp_name ) ) ;
/* Or the root of a share. */
if ( ISDOT ( fsp - > fsp_name - > base_name ) ) {
DEBUG ( 10 , ( " can_set_delete_on_close: can't set delete on "
" close for the root of a share. \n " ) ) ;
return NT_STATUS_ACCESS_DENIED ;
}
return can_delete_directory ( fsp - > conn ,
fsp - > fsp_name - > base_name ) ;
}
return NT_STATUS_OK ;
}