1998-08-17 11:40:06 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1998-08-17 11:40:06 +04:00
dos mode handling functions
Copyright ( C ) Andrew Tridgell 1992 - 1998
2006-03-23 02:49:09 +03:00
Copyright ( C ) James Peach 2006
2009-05-24 23:46:53 +04:00
1998-08-17 11:40:06 +04:00
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
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
1998-08-17 11:40:06 +04:00
( at your option ) any later version .
2009-05-24 23:46:53 +04:00
1998-08-17 11:40:06 +04:00
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 .
2009-05-24 23:46:53 +04:00
1998-08-17 11:40:06 +04:00
You should have received a copy of the GNU General Public License
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
1998-08-17 11:40:06 +04:00
*/
# include "includes.h"
2018-12-28 14:12:20 +03:00
# include "globals.h"
2011-02-26 01:20:06 +03:00
# include "system/filesys.h"
2009-11-18 01:55:02 +03:00
# include "librpc/gen_ndr/ndr_xattr.h"
2013-11-18 17:54:36 +04:00
# include "librpc/gen_ndr/ioctl.h"
2010-12-17 03:50:31 +03:00
# include "../libcli/security/security.h"
2011-03-22 18:57:01 +03:00
# include "smbd/smbd.h"
2012-07-23 06:47:01 +04:00
# include "lib/param/loadparm.h"
2018-03-15 17:21:53 +03:00
# include "lib/util/tevent_ntstatus.h"
1998-08-17 11:40:06 +04:00
2014-05-01 22:07:44 +04:00
static NTSTATUS get_file_handle_for_metadata ( connection_struct * conn ,
2016-03-26 01:32:09 +03:00
const struct smb_filename * smb_fname ,
2014-05-01 22:07:44 +04:00
files_struct * * ret_fsp ,
bool * need_close ) ;
2015-11-17 15:37:14 +03:00
static void dos_mode_debug_print ( const char * func , uint32_t mode )
2013-11-18 17:54:35 +04:00
{
2015-11-17 15:21:13 +03:00
fstring modestr ;
2015-11-17 15:49:30 +03:00
if ( DEBUGLEVEL < DBGLVL_INFO ) {
return ;
}
2015-11-17 15:21:13 +03:00
modestr [ 0 ] = ' \0 ' ;
2013-11-18 17:54:35 +04:00
if ( mode & FILE_ATTRIBUTE_HIDDEN ) {
2015-11-17 15:21:13 +03:00
fstrcat ( modestr , " h " ) ;
2013-11-18 17:54:35 +04:00
}
if ( mode & FILE_ATTRIBUTE_READONLY ) {
2015-11-17 15:21:13 +03:00
fstrcat ( modestr , " r " ) ;
2013-11-18 17:54:35 +04:00
}
if ( mode & FILE_ATTRIBUTE_SYSTEM ) {
2015-11-17 15:21:13 +03:00
fstrcat ( modestr , " s " ) ;
2013-11-18 17:54:35 +04:00
}
if ( mode & FILE_ATTRIBUTE_DIRECTORY ) {
2015-11-17 15:21:13 +03:00
fstrcat ( modestr , " d " ) ;
2013-11-18 17:54:35 +04:00
}
if ( mode & FILE_ATTRIBUTE_ARCHIVE ) {
2015-11-17 15:21:13 +03:00
fstrcat ( modestr , " a " ) ;
2013-11-18 17:54:35 +04:00
}
if ( mode & FILE_ATTRIBUTE_SPARSE ) {
2015-11-17 15:21:13 +03:00
fstrcat ( modestr , " [sparse] " ) ;
2013-11-18 17:54:35 +04:00
}
if ( mode & FILE_ATTRIBUTE_OFFLINE ) {
2015-11-17 15:21:13 +03:00
fstrcat ( modestr , " [offline] " ) ;
2013-11-18 17:54:35 +04:00
}
2013-11-18 17:54:36 +04:00
if ( mode & FILE_ATTRIBUTE_COMPRESSED ) {
2015-11-17 15:21:13 +03:00
fstrcat ( modestr , " [compressed] " ) ;
2013-11-18 17:54:36 +04:00
}
2013-11-18 17:54:35 +04:00
2015-11-17 15:44:30 +03:00
DBG_INFO ( " %s returning (0x%x): \" %s \" \n " , func , ( unsigned ) mode ,
modestr ) ;
2013-11-18 17:54:35 +04:00
}
2009-12-16 05:03:47 +03:00
static uint32_t filter_mode_by_protocol ( uint32_t mode )
{
if ( get_Protocol ( ) < = PROTOCOL_LANMAN2 ) {
DEBUG ( 10 , ( " filter_mode_by_protocol: "
" filtering result 0x%x to 0x%x \n " ,
( unsigned int ) mode ,
( unsigned int ) ( mode & 0x3f ) ) ) ;
mode & = 0x3f ;
}
return mode ;
}
2008-11-06 00:40:03 +03:00
static int set_link_read_only_flag ( const SMB_STRUCT_STAT * const sbuf )
{
# ifdef S_ISLNK
# if LINKS_READ_ONLY
if ( S_ISLNK ( sbuf - > st_mode ) & & S_ISDIR ( sbuf - > st_mode ) )
2011-04-29 05:36:14 +04:00
return FILE_ATTRIBUTE_READONLY ;
2008-11-06 00:40:03 +03:00
# endif
# endif
return 0 ;
}
1998-08-17 11:40:06 +04:00
/****************************************************************************
2004-04-01 02:46:15 +04:00
Change a dos mode to a unix mode .
Base permission for files :
2006-12-27 13:57:59 +03:00
if creating file and inheriting ( i . e . parent_dir ! = NULL )
2000-01-14 04:41:04 +03:00
apply read / write bits from parent directory .
else
everybody gets read bit set
1998-08-17 11:40:06 +04:00
dos readonly is represented in unix by removing everyone ' s write bit
dos archive is represented in unix by the user ' s execute bit
dos system is represented in unix by the group ' s execute bit
dos hidden is represented in unix by the other ' s execute bit
2000-01-14 04:41:04 +03:00
if ! inheriting {
Then apply create mask ,
then add force bits .
}
2004-04-01 02:46:15 +04:00
Base permission for directories :
1998-08-17 11:40:06 +04:00
dos directory is represented in unix by unix ' s dir bit and the exec bit
2000-01-14 04:41:04 +03:00
if ! inheriting {
Then apply create mask ,
then add force bits .
}
1998-08-17 11:40:06 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-04-01 02:46:15 +04:00
2009-07-08 06:20:22 +04:00
mode_t unix_mode ( connection_struct * conn , int dosmode ,
const struct smb_filename * smb_fname ,
2006-12-27 13:57:59 +03:00
const char * inherit_from_dir )
1998-08-17 11:40:06 +04:00
{
2004-04-02 22:46:19 +04:00
mode_t result = ( S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH ) ;
2006-12-27 13:57:59 +03:00
mode_t dir_mode = 0 ; /* Mode of the inherit_from directory if
* inheriting . */
2004-04-01 02:46:15 +04:00
2004-04-02 22:46:19 +04:00
if ( ! lp_store_dos_attributes ( SNUM ( conn ) ) & & IS_DOS_READONLY ( dosmode ) ) {
result & = ~ ( S_IWUSR | S_IWGRP | S_IWOTH ) ;
}
2004-04-01 02:46:15 +04:00
2014-02-04 06:09:10 +04:00
if ( ( inherit_from_dir ! = NULL ) & & lp_inherit_permissions ( SNUM ( conn ) ) ) {
2013-04-15 13:30:50 +04:00
struct smb_filename * smb_fname_parent ;
2004-04-01 02:46:15 +04:00
2009-07-08 06:20:22 +04:00
DEBUG ( 2 , ( " unix_mode(%s) inheriting from %s \n " ,
smb_fname_str_dbg ( smb_fname ) ,
2006-12-27 13:57:59 +03:00
inherit_from_dir ) ) ;
2009-07-08 06:20:22 +04:00
2016-03-19 07:19:38 +03:00
smb_fname_parent = synthetic_smb_fname ( talloc_tos ( ) ,
inherit_from_dir ,
NULL ,
NULL ,
smb_fname - > flags ) ;
2013-04-15 13:30:50 +04:00
if ( smb_fname_parent = = NULL ) {
DEBUG ( 1 , ( " unix_mode(%s) failed, [dir %s]: No memory \n " ,
2009-07-08 06:20:22 +04:00
smb_fname_str_dbg ( smb_fname ) ,
2013-04-15 13:30:50 +04:00
inherit_from_dir ) ) ;
2009-07-08 06:20:22 +04:00
return ( 0 ) ;
}
if ( SMB_VFS_STAT ( conn , smb_fname_parent ) ! = 0 ) {
DEBUG ( 4 , ( " unix_mode(%s) failed, [dir %s]: %s \n " ,
smb_fname_str_dbg ( smb_fname ) ,
2006-12-27 13:57:59 +03:00
inherit_from_dir , strerror ( errno ) ) ) ;
2009-07-08 06:20:22 +04:00
TALLOC_FREE ( smb_fname_parent ) ;
2004-04-01 02:46:15 +04:00
return ( 0 ) ; /* *** shouldn't happen! *** */
}
/* Save for later - but explicitly remove setuid bit for safety. */
2009-07-08 06:20:22 +04:00
dir_mode = smb_fname_parent - > st . st_ex_mode & ~ S_ISUID ;
DEBUG ( 2 , ( " unix_mode(%s) inherit mode %o \n " ,
smb_fname_str_dbg ( smb_fname ) , ( int ) dir_mode ) ) ;
2004-04-01 02:46:15 +04:00
/* Clear "result" */
result = 0 ;
2009-07-08 06:20:22 +04:00
TALLOC_FREE ( smb_fname_parent ) ;
2004-04-01 02:46:15 +04:00
}
if ( IS_DOS_DIR ( dosmode ) ) {
/* We never make directories read only for the owner as under DOS a user
can always create a file in a read - only directory . */
result | = ( S_IFDIR | S_IWUSR ) ;
if ( dir_mode ) {
/* Inherit mode of parent directory. */
result | = dir_mode ;
} else {
/* Provisionally add all 'x' bits */
result | = ( S_IXUSR | S_IXGRP | S_IXOTH ) ;
/* Apply directory mask */
2014-02-02 17:59:30 +04:00
result & = lp_directory_mask ( SNUM ( conn ) ) ;
2004-04-01 02:46:15 +04:00
/* Add in force bits */
2014-02-03 05:48:28 +04:00
result | = lp_force_directory_mode ( SNUM ( conn ) ) ;
2004-04-01 02:46:15 +04:00
}
} else {
if ( lp_map_archive ( SNUM ( conn ) ) & & IS_DOS_ARCHIVE ( dosmode ) )
result | = S_IXUSR ;
if ( lp_map_system ( SNUM ( conn ) ) & & IS_DOS_SYSTEM ( dosmode ) )
result | = S_IXGRP ;
2009-05-24 23:46:53 +04:00
2004-04-01 02:46:15 +04:00
if ( lp_map_hidden ( SNUM ( conn ) ) & & IS_DOS_HIDDEN ( dosmode ) )
result | = S_IXOTH ;
if ( dir_mode ) {
/* Inherit 666 component of parent directory mode */
result | = dir_mode & ( S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH ) ;
} else {
/* Apply mode mask */
result & = lp_create_mask ( SNUM ( conn ) ) ;
/* Add in force bits */
result | = lp_force_create_mode ( SNUM ( conn ) ) ;
}
}
2015-07-09 00:40:25 +03:00
DBG_INFO ( " unix_mode(%s) returning 0%o \n " ,
smb_fname_str_dbg ( smb_fname ) , ( int ) result ) ;
2004-04-01 02:46:15 +04:00
return ( result ) ;
1998-08-17 11:40:06 +04:00
}
/****************************************************************************
2004-04-01 02:46:15 +04:00
Change a unix mode to a dos mode .
1998-08-17 11:40:06 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-03-20 02:46:48 +03:00
2015-05-03 07:01:14 +03:00
static uint32_t dos_mode_from_sbuf ( connection_struct * conn ,
2009-07-08 23:24:03 +04:00
const struct smb_filename * smb_fname )
1998-08-17 11:40:06 +04:00
{
2002-08-17 19:27:10 +04:00
int result = 0 ;
2005-10-14 05:09:37 +04:00
enum mapreadonly_options ro_opts = ( enum mapreadonly_options ) lp_map_readonly ( SNUM ( conn ) ) ;
1998-08-17 11:40:06 +04:00
2012-07-04 02:33:41 +04:00
# if defined(UF_IMMUTABLE) && defined(SF_IMMUTABLE)
/* if we can find out if a file is immutable we should report it r/o */
if ( smb_fname - > st . st_ex_flags & ( UF_IMMUTABLE | SF_IMMUTABLE ) ) {
result | = FILE_ATTRIBUTE_READONLY ;
}
# endif
2005-10-14 05:09:37 +04:00
if ( ro_opts = = MAP_READONLY_YES ) {
/* Original Samba method - map inverse of user "w" bit. */
2009-07-08 23:24:03 +04:00
if ( ( smb_fname - > st . st_ex_mode & S_IWUSR ) = = 0 ) {
2011-04-29 05:36:14 +04:00
result | = FILE_ATTRIBUTE_READONLY ;
2005-10-14 05:09:37 +04:00
}
} else if ( ro_opts = = MAP_READONLY_PERMISSIONS ) {
2009-07-08 23:24:03 +04:00
/* Check actual permissions for read-only. */
if ( ! can_write_to_file ( conn , smb_fname ) ) {
2011-04-29 05:36:14 +04:00
result | = FILE_ATTRIBUTE_READONLY ;
2005-05-19 03:37:35 +04:00
}
2005-10-14 05:09:37 +04:00
} /* Else never set the readonly bit. */
2005-05-19 03:37:35 +04:00
2009-07-08 23:24:03 +04:00
if ( MAP_ARCHIVE ( conn ) & & ( ( smb_fname - > st . st_ex_mode & S_IXUSR ) ! = 0 ) )
2011-04-29 06:00:57 +04:00
result | = FILE_ATTRIBUTE_ARCHIVE ;
1998-08-17 11:40:06 +04:00
2009-07-08 23:24:03 +04:00
if ( MAP_SYSTEM ( conn ) & & ( ( smb_fname - > st . st_ex_mode & S_IXGRP ) ! = 0 ) )
2011-04-29 07:23:14 +04:00
result | = FILE_ATTRIBUTE_SYSTEM ;
2009-05-24 23:46:53 +04:00
2009-07-08 23:24:03 +04:00
if ( MAP_HIDDEN ( conn ) & & ( ( smb_fname - > st . st_ex_mode & S_IXOTH ) ! = 0 ) )
2011-04-29 05:43:35 +04:00
result | = FILE_ATTRIBUTE_HIDDEN ;
2009-05-24 23:46:53 +04:00
2009-07-08 23:24:03 +04:00
if ( S_ISDIR ( smb_fname - > st . st_ex_mode ) )
2011-04-29 05:57:02 +04:00
result = FILE_ATTRIBUTE_DIRECTORY | ( result & FILE_ATTRIBUTE_READONLY ) ;
2002-08-17 19:27:10 +04:00
2009-07-08 23:24:03 +04:00
result | = set_link_read_only_flag ( & smb_fname - > st ) ;
1998-08-17 11:40:06 +04:00
2015-11-17 15:41:29 +03:00
dos_mode_debug_print ( __func__ , result ) ;
2004-03-20 02:46:48 +03:00
return result ;
}
2004-04-02 22:46:19 +04:00
/****************************************************************************
Get DOS attributes from an EA .
2009-11-18 01:55:02 +03:00
This can also pull the create time into the stat struct inside smb_fname .
2004-04-02 22:46:19 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2018-03-15 12:56:28 +03:00
NTSTATUS parse_dos_attribute_blob ( struct smb_filename * smb_fname ,
DATA_BLOB blob ,
uint32_t * pattr )
{
struct xattr_DOSATTRIB dosattrib ;
enum ndr_err_code ndr_err ;
uint32_t dosattr ;
ndr_err = ndr_pull_struct_blob ( & blob , talloc_tos ( ) , & dosattrib ,
( ndr_pull_flags_fn_t ) ndr_pull_xattr_DOSATTRIB ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
DBG_WARNING ( " bad ndr decode "
" from EA on file %s: Error = %s \n " ,
smb_fname_str_dbg ( smb_fname ) ,
ndr_errstr ( ndr_err ) ) ;
return ndr_map_error2ntstatus ( ndr_err ) ;
}
DBG_DEBUG ( " %s attr = %s \n " ,
smb_fname_str_dbg ( smb_fname ) , dosattrib . attrib_hex ) ;
switch ( dosattrib . version ) {
case 0xFFFF :
dosattr = dosattrib . info . compatinfoFFFF . attrib ;
break ;
case 1 :
dosattr = dosattrib . info . info1 . attrib ;
if ( ! null_nttime ( dosattrib . info . info1 . create_time ) ) {
struct timespec create_time =
nt_time_to_unix_timespec (
dosattrib . info . info1 . create_time ) ;
update_stat_ex_create_time ( & smb_fname - > st ,
create_time ) ;
DBG_DEBUG ( " file %s case 1 set btime %s \n " ,
smb_fname_str_dbg ( smb_fname ) ,
time_to_asc ( convert_timespec_to_time_t (
create_time ) ) ) ;
}
break ;
case 2 :
dosattr = dosattrib . info . oldinfo2 . attrib ;
/* Don't know what flags to check for this case. */
break ;
case 3 :
dosattr = dosattrib . info . info3 . attrib ;
if ( ( dosattrib . info . info3 . valid_flags & XATTR_DOSINFO_CREATE_TIME ) & &
! null_nttime ( dosattrib . info . info3 . create_time ) ) {
struct timespec create_time =
nt_time_to_unix_timespec (
dosattrib . info . info3 . create_time ) ;
update_stat_ex_create_time ( & smb_fname - > st ,
create_time ) ;
DBG_DEBUG ( " file %s case 3 set btime %s \n " ,
smb_fname_str_dbg ( smb_fname ) ,
time_to_asc ( convert_timespec_to_time_t (
create_time ) ) ) ;
}
break ;
default :
DBG_WARNING ( " Badly formed DOSATTRIB on file %s - %s \n " ,
smb_fname_str_dbg ( smb_fname ) , blob . data ) ;
/* Should this be INTERNAL_ERROR? */
return NT_STATUS_INVALID_PARAMETER ;
}
if ( S_ISDIR ( smb_fname - > st . st_ex_mode ) ) {
dosattr | = FILE_ATTRIBUTE_DIRECTORY ;
}
/* FILE_ATTRIBUTE_SPARSE is valid on get but not on set. */
* pattr | = ( uint32_t ) ( dosattr & ( SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_SPARSE ) ) ;
dos_mode_debug_print ( __func__ , * pattr ) ;
return NT_STATUS_OK ;
}
2016-03-26 01:32:09 +03:00
NTSTATUS get_ea_dos_attribute ( connection_struct * conn ,
struct smb_filename * smb_fname ,
uint32_t * pattr )
2004-04-02 22:46:19 +04:00
{
2009-11-18 01:55:02 +03:00
DATA_BLOB blob ;
2004-04-02 22:46:19 +04:00
ssize_t sizeret ;
fstring attrstr ;
2018-03-15 12:56:28 +03:00
NTSTATUS status ;
2004-04-02 22:46:19 +04:00
if ( ! lp_store_dos_attributes ( SNUM ( conn ) ) ) {
2016-03-26 01:32:09 +03:00
return NT_STATUS_NOT_IMPLEMENTED ;
2004-04-02 22:46:19 +04:00
}
2005-11-28 20:03:50 +03:00
/* Don't reset pattr to zero as we may already have filename-based attributes we
need to preserve . */
2004-04-02 22:46:19 +04:00
2017-05-26 02:42:04 +03:00
sizeret = SMB_VFS_GETXATTR ( conn , smb_fname ,
2009-07-08 23:24:03 +04:00
SAMBA_XATTR_DOS_ATTRIB , attrstr ,
sizeof ( attrstr ) ) ;
2017-06-08 20:10:20 +03:00
if ( sizeret = = - 1 & & errno = = EACCES ) {
int saved_errno = 0 ;
/*
* According to MS - FSA 2.1 .5 .1 .2 .1 " Algorithm to Check Access to
* an Existing File " FILE_LIST_DIRECTORY on a directory implies
* FILE_READ_ATTRIBUTES for directory entries . Being able to
* stat ( ) a file implies FILE_LIST_DIRECTORY for the directory
* containing the file .
*/
if ( ! VALID_STAT ( smb_fname - > st ) ) {
/*
* Safety net : dos_mode ( ) already checks this , but as we
* become root based on this , add an additional layer of
* defense .
*/
DBG_ERR ( " Rejecting root override, invalid stat [%s] \n " ,
smb_fname_str_dbg ( smb_fname ) ) ;
return NT_STATUS_ACCESS_DENIED ;
}
become_root ( ) ;
sizeret = SMB_VFS_GETXATTR ( conn , smb_fname ,
SAMBA_XATTR_DOS_ATTRIB ,
attrstr ,
sizeof ( attrstr ) ) ;
if ( sizeret = = - 1 ) {
saved_errno = errno ;
}
unbecome_root ( ) ;
if ( saved_errno ! = 0 ) {
errno = saved_errno ;
}
}
2004-04-02 22:46:19 +04:00
if ( sizeret = = - 1 ) {
2015-12-27 08:17:58 +03:00
DBG_INFO ( " Cannot get attribute "
2015-12-24 09:10:11 +03:00
" from EA on file %s: Error = %s \n " ,
smb_fname_str_dbg ( smb_fname ) , strerror ( errno ) ) ;
2016-03-26 01:32:09 +03:00
return map_nt_error_from_unix ( errno ) ;
2004-04-02 22:46:19 +04:00
}
2009-11-18 01:55:02 +03:00
blob . data = ( uint8_t * ) attrstr ;
blob . length = sizeret ;
2018-03-15 12:56:28 +03:00
status = parse_dos_attribute_blob ( smb_fname , blob , pattr ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2010-01-26 04:38:55 +03:00
}
2016-03-26 01:32:09 +03:00
return NT_STATUS_OK ;
2004-04-02 22:46:19 +04:00
}
/****************************************************************************
Set DOS attributes in an EA .
2009-11-18 01:55:02 +03:00
Also sets the create time .
2004-04-02 22:46:19 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2016-03-26 01:32:09 +03:00
NTSTATUS set_ea_dos_attribute ( connection_struct * conn ,
const struct smb_filename * smb_fname ,
uint32_t dosmode )
2004-04-02 22:46:19 +04:00
{
2009-11-18 01:55:02 +03:00
struct xattr_DOSATTRIB dosattrib ;
enum ndr_err_code ndr_err ;
DATA_BLOB blob ;
2017-10-12 16:41:01 +03:00
int ret ;
2004-04-02 22:46:19 +04:00
2016-03-26 01:32:09 +03:00
if ( ! lp_store_dos_attributes ( SNUM ( conn ) ) ) {
return NT_STATUS_NOT_IMPLEMENTED ;
}
2016-09-11 13:39:13 +03:00
/*
* Don ' t store FILE_ATTRIBUTE_OFFLINE , it ' s dealt with in
* vfs_default via DMAPI if that is enabled .
*/
dosmode & = ~ FILE_ATTRIBUTE_OFFLINE ;
2009-11-18 01:55:02 +03:00
ZERO_STRUCT ( dosattrib ) ;
ZERO_STRUCT ( blob ) ;
dosattrib . version = 3 ;
dosattrib . info . info3 . valid_flags = XATTR_DOSINFO_ATTRIB |
XATTR_DOSINFO_CREATE_TIME ;
dosattrib . info . info3 . attrib = dosmode ;
2014-06-18 16:21:06 +04:00
dosattrib . info . info3 . create_time = unix_timespec_to_nt_time (
2009-11-18 01:55:02 +03:00
smb_fname - > st . st_ex_btime ) ;
2010-02-02 06:21:35 +03:00
DEBUG ( 10 , ( " set_ea_dos_attributes: set attribute 0x%x, btime = %s on file %s \n " ,
( unsigned int ) dosmode ,
time_to_asc ( convert_timespec_to_time_t ( smb_fname - > st . st_ex_btime ) ) ,
smb_fname_str_dbg ( smb_fname ) ) ) ;
2009-11-18 01:55:02 +03:00
ndr_err = ndr_push_struct_blob (
2010-05-10 02:42:06 +04:00
& blob , talloc_tos ( ) , & dosattrib ,
2009-11-18 01:55:02 +03:00
( ndr_push_flags_fn_t ) ndr_push_xattr_DOSATTRIB ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
DEBUG ( 5 , ( " create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s \n " ,
ndr_errstr ( ndr_err ) ) ) ;
2016-03-26 01:32:09 +03:00
return ndr_map_error2ntstatus ( ndr_err ) ;
2009-11-18 01:55:02 +03:00
}
if ( blob . data = = NULL | | blob . length = = 0 ) {
2016-03-26 01:32:09 +03:00
/* Should this be INTERNAL_ERROR? */
return NT_STATUS_INVALID_PARAMETER ;
2009-11-18 01:55:02 +03:00
}
2017-10-12 16:41:01 +03:00
ret = SMB_VFS_SETXATTR ( conn , smb_fname ,
SAMBA_XATTR_DOS_ATTRIB ,
blob . data , blob . length , 0 ) ;
if ( ret ! = 0 ) {
2016-03-26 01:32:09 +03:00
NTSTATUS status = NT_STATUS_OK ;
2014-05-01 22:07:44 +04:00
bool need_close = false ;
2011-04-15 21:49:34 +04:00
files_struct * fsp = NULL ;
2017-08-29 16:55:19 +03:00
bool set_dosmode_ok = false ;
2011-04-15 21:49:34 +04:00
2017-10-12 16:41:01 +03:00
if ( ( errno ! = EPERM ) & & ( errno ! = EACCES ) ) {
2015-12-27 08:17:58 +03:00
DBG_INFO ( " Cannot set "
2015-12-24 09:10:11 +03:00
" attribute EA on file %s: Error = %s \n " ,
smb_fname_str_dbg ( smb_fname ) , strerror ( errno ) ) ;
2016-03-26 01:32:09 +03:00
return map_nt_error_from_unix ( errno ) ;
2004-04-02 22:46:19 +04:00
}
/* We want DOS semantics, ie allow non owner with write permission to change the
2007-03-06 02:40:03 +03:00
bits on a file . Just like file_ntimes below .
2004-04-02 22:46:19 +04:00
*/
/* Check if we have write access. */
2017-08-29 16:55:19 +03:00
if ( ! CAN_WRITE ( conn ) ) {
2016-03-26 01:32:09 +03:00
return NT_STATUS_ACCESS_DENIED ;
2017-08-29 16:55:19 +03:00
}
2004-04-02 22:46:19 +04:00
2017-08-29 16:55:19 +03:00
status = smbd_check_access_rights ( conn , smb_fname , false ,
FILE_WRITE_ATTRIBUTES ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
set_dosmode_ok = true ;
}
if ( ! set_dosmode_ok & & lp_dos_filemode ( SNUM ( conn ) ) ) {
set_dosmode_ok = can_write_to_file ( conn , smb_fname ) ;
}
if ( ! set_dosmode_ok ) {
2016-03-26 01:32:09 +03:00
return NT_STATUS_ACCESS_DENIED ;
2013-04-26 01:06:03 +04:00
}
2004-04-02 22:46:19 +04:00
/*
2014-05-01 22:07:44 +04:00
* We need to get an open file handle to do the
* metadata operation under root .
2004-04-02 22:46:19 +04:00
*/
2016-03-26 01:32:09 +03:00
status = get_file_handle_for_metadata ( conn ,
2014-05-01 22:07:44 +04:00
smb_fname ,
& fsp ,
2016-03-26 01:32:09 +03:00
& need_close ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2014-05-01 22:07:44 +04:00
}
2004-04-02 22:46:19 +04:00
become_root ( ) ;
2017-10-12 16:41:01 +03:00
ret = SMB_VFS_FSETXATTR ( fsp ,
SAMBA_XATTR_DOS_ATTRIB ,
blob . data , blob . length , 0 ) ;
if ( ret = = 0 ) {
2016-03-26 01:32:09 +03:00
status = NT_STATUS_OK ;
2004-04-02 22:46:19 +04:00
}
unbecome_root ( ) ;
2014-05-01 22:07:44 +04:00
if ( need_close ) {
close_file ( NULL , fsp , NORMAL_CLOSE ) ;
}
2016-03-26 01:32:09 +03:00
return status ;
2004-04-02 22:46:19 +04:00
}
2009-11-18 01:55:02 +03:00
DEBUG ( 10 , ( " set_ea_dos_attribute: set EA 0x%x on file %s \n " ,
( unsigned int ) dosmode ,
smb_fname_str_dbg ( smb_fname ) ) ) ;
2016-03-26 01:32:09 +03:00
return NT_STATUS_OK ;
2004-04-02 22:46:19 +04:00
}
2006-07-04 01:07:46 +04:00
/****************************************************************************
Change a unix mode to a dos mode for an ms dfs link .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-05-03 07:01:14 +03:00
uint32_t dos_mode_msdfs ( connection_struct * conn ,
2009-07-08 23:24:03 +04:00
const struct smb_filename * smb_fname )
2006-07-04 01:07:46 +04:00
{
2015-05-03 07:01:14 +03:00
uint32_t result = 0 ;
2006-07-04 01:07:46 +04:00
2009-07-08 23:24:03 +04:00
DEBUG ( 8 , ( " dos_mode_msdfs: %s \n " , smb_fname_str_dbg ( smb_fname ) ) ) ;
2006-07-04 01:07:46 +04:00
2009-07-08 23:24:03 +04:00
if ( ! VALID_STAT ( smb_fname - > st ) ) {
2006-07-04 01:07:46 +04:00
return 0 ;
}
/* First do any modifications that depend on the path name. */
/* hide files with a name starting with a . */
if ( lp_hide_dot_files ( SNUM ( conn ) ) ) {
2009-07-08 23:24:03 +04:00
const char * p = strrchr_m ( smb_fname - > base_name , ' / ' ) ;
2006-07-04 01:07:46 +04:00
if ( p ) {
p + + ;
} else {
2009-07-08 23:24:03 +04:00
p = smb_fname - > base_name ;
2006-07-04 01:07:46 +04:00
}
2009-03-31 02:05:39 +04:00
/* Only . and .. are not hidden. */
if ( p [ 0 ] = = ' . ' & & ! ( ( p [ 1 ] = = ' \0 ' ) | |
( p [ 1 ] = = ' . ' & & p [ 2 ] = = ' \0 ' ) ) ) {
2011-04-29 05:43:35 +04:00
result | = FILE_ATTRIBUTE_HIDDEN ;
2006-07-04 01:07:46 +04:00
}
}
2009-05-24 23:46:53 +04:00
2009-07-08 23:24:03 +04:00
result | = dos_mode_from_sbuf ( conn , smb_fname ) ;
2006-07-04 01:07:46 +04:00
/* Optimization : Only call is_hidden_path if it's not already
hidden . */
2011-04-29 05:43:35 +04:00
if ( ! ( result & FILE_ATTRIBUTE_HIDDEN ) & &
2009-11-23 18:33:53 +03:00
IS_HIDDEN_PATH ( conn , smb_fname - > base_name ) ) {
2011-04-29 05:43:35 +04:00
result | = FILE_ATTRIBUTE_HIDDEN ;
2006-07-04 01:07:46 +04:00
}
2009-12-16 05:03:47 +03:00
if ( result = = 0 ) {
result = FILE_ATTRIBUTE_NORMAL ;
2009-11-05 02:25:15 +03:00
}
2009-12-16 05:03:47 +03:00
result = filter_mode_by_protocol ( result ) ;
2013-08-18 18:34:31 +04:00
/*
* Add in that it is a reparse point
*/
result | = FILE_ATTRIBUTE_REPARSE_POINT ;
2015-11-17 15:37:14 +03:00
dos_mode_debug_print ( __func__ , result ) ;
2006-07-04 01:07:46 +04:00
return ( result ) ;
}
2013-11-18 17:54:36 +04:00
/*
* check whether a file or directory is flagged as compressed .
*/
static NTSTATUS dos_mode_check_compressed ( connection_struct * conn ,
struct smb_filename * smb_fname ,
bool * is_compressed )
{
NTSTATUS status ;
uint16_t compression_fmt ;
TALLOC_CTX * tmp_ctx = talloc_new ( NULL ) ;
if ( tmp_ctx = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto err_out ;
}
status = SMB_VFS_GET_COMPRESSION ( conn , tmp_ctx , NULL , smb_fname ,
& compression_fmt ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto err_ctx_free ;
}
if ( compression_fmt = = COMPRESSION_FORMAT_LZNT1 ) {
* is_compressed = true ;
} else {
* is_compressed = false ;
}
status = NT_STATUS_OK ;
err_ctx_free :
talloc_free ( tmp_ctx ) ;
err_out :
return status ;
}
2016-06-23 13:23:33 +03:00
static uint32_t dos_mode_from_name ( connection_struct * conn ,
2016-06-23 17:40:15 +03:00
const struct smb_filename * smb_fname ,
uint32_t dosmode )
2016-06-23 13:23:33 +03:00
{
const char * p = NULL ;
2016-06-23 17:40:15 +03:00
uint32_t result = dosmode ;
2016-06-23 13:23:33 +03:00
2016-06-23 17:40:15 +03:00
if ( ! ( result & FILE_ATTRIBUTE_HIDDEN ) & &
lp_hide_dot_files ( SNUM ( conn ) ) )
{
2016-06-23 13:23:33 +03:00
p = strrchr_m ( smb_fname - > base_name , ' / ' ) ;
if ( p ) {
p + + ;
} else {
p = smb_fname - > base_name ;
}
/* Only . and .. are not hidden. */
if ( ( p [ 0 ] = = ' . ' ) & &
! ( ( p [ 1 ] = = ' \0 ' ) | | ( p [ 1 ] = = ' . ' & & p [ 2 ] = = ' \0 ' ) ) )
{
result | = FILE_ATTRIBUTE_HIDDEN ;
}
}
2016-06-23 18:14:55 +03:00
if ( ! ( result & FILE_ATTRIBUTE_HIDDEN ) & &
IS_HIDDEN_PATH ( conn , smb_fname - > base_name ) )
{
result | = FILE_ATTRIBUTE_HIDDEN ;
}
2016-06-23 13:23:33 +03:00
return result ;
}
2018-07-25 18:15:46 +03:00
static uint32_t dos_mode_post ( uint32_t dosmode ,
connection_struct * conn ,
struct smb_filename * smb_fname ,
const char * func )
2004-03-20 02:46:48 +03:00
{
2018-07-25 18:15:46 +03:00
NTSTATUS status ;
2005-09-21 00:20:51 +04:00
2018-04-11 21:05:14 +03:00
/*
* According to MS - FSA a stream name does not have
* separate DOS attribute metadata , so we must return
* the DOS attribute from the base filename . With one caveat ,
* a non - default stream name can never be a directory .
*
* As this is common to all streams data stores , we handle
* it here instead of inside all stream VFS modules .
*
* BUG : https : //bugzilla.samba.org/show_bug.cgi?id=13380
*/
if ( is_ntfs_stream_smb_fname ( smb_fname ) ) {
/* is_ntfs_stream_smb_fname() returns false for a POSIX path. */
if ( ! is_ntfs_default_stream_smb_fname ( smb_fname ) ) {
/*
* Non - default stream name , not a posix path .
*/
2018-07-25 18:15:46 +03:00
dosmode & = ~ ( FILE_ATTRIBUTE_DIRECTORY ) ;
2018-04-11 21:05:14 +03:00
}
}
2013-11-18 17:54:36 +04:00
if ( conn - > fs_capabilities & FILE_FILE_COMPRESSION ) {
bool compressed = false ;
2018-07-25 18:15:46 +03:00
2016-03-26 01:32:09 +03:00
status = dos_mode_check_compressed ( conn , smb_fname ,
& compressed ) ;
2013-11-18 17:54:36 +04:00
if ( NT_STATUS_IS_OK ( status ) & & compressed ) {
2018-07-25 18:15:46 +03:00
dosmode | = FILE_ATTRIBUTE_COMPRESSED ;
2013-11-18 17:54:36 +04:00
}
}
2018-07-25 18:15:46 +03:00
dosmode | = dos_mode_from_name ( conn , smb_fname , dosmode ) ;
2016-06-23 17:40:15 +03:00
2016-11-18 21:20:41 +03:00
if ( S_ISDIR ( smb_fname - > st . st_ex_mode ) ) {
2018-07-25 18:15:46 +03:00
dosmode | = FILE_ATTRIBUTE_DIRECTORY ;
} else if ( dosmode = = 0 ) {
dosmode = FILE_ATTRIBUTE_NORMAL ;
2009-11-05 02:25:15 +03:00
}
2018-07-25 18:15:46 +03:00
dosmode = filter_mode_by_protocol ( dosmode ) ;
2009-12-16 05:03:47 +03:00
2018-07-25 18:15:46 +03:00
dos_mode_debug_print ( func , dosmode ) ;
return dosmode ;
}
/****************************************************************************
Change a unix mode to a dos mode .
May also read the create timespec into the stat struct in smb_fname
if " store dos attributes " is true .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
uint32_t dos_mode ( connection_struct * conn , struct smb_filename * smb_fname )
{
uint32_t result = 0 ;
NTSTATUS status = NT_STATUS_OK ;
DEBUG ( 8 , ( " dos_mode: %s \n " , smb_fname_str_dbg ( smb_fname ) ) ) ;
if ( ! VALID_STAT ( smb_fname - > st ) ) {
return 0 ;
}
/* Get the DOS attributes via the VFS if we can */
status = SMB_VFS_GET_DOS_ATTRIBUTES ( conn , smb_fname , & result ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
/*
* Only fall back to using UNIX modes if we get NOT_IMPLEMENTED .
*/
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NOT_IMPLEMENTED ) ) {
result | = dos_mode_from_sbuf ( conn , smb_fname ) ;
}
}
2002-08-17 19:27:10 +04:00
2018-07-25 18:15:46 +03:00
result = dos_mode_post ( result , conn , smb_fname , __func__ ) ;
2013-11-18 17:54:35 +04:00
return result ;
1998-08-17 11:40:06 +04:00
}
2018-03-15 17:21:53 +03:00
struct dos_mode_at_state {
files_struct * dir_fsp ;
struct smb_filename * smb_fname ;
uint32_t dosmode ;
} ;
static void dos_mode_at_vfs_get_dosmode_done ( struct tevent_req * subreq ) ;
struct tevent_req * dos_mode_at_send ( TALLOC_CTX * mem_ctx ,
2018-12-28 14:16:27 +03:00
struct tevent_context * ev ,
2018-03-15 17:21:53 +03:00
files_struct * dir_fsp ,
struct smb_filename * smb_fname )
{
struct tevent_req * req = NULL ;
struct dos_mode_at_state * state = NULL ;
struct tevent_req * subreq = NULL ;
DBG_DEBUG ( " %s \n " , smb_fname_str_dbg ( smb_fname ) ) ;
req = tevent_req_create ( mem_ctx , & state ,
struct dos_mode_at_state ) ;
if ( req = = NULL ) {
return NULL ;
}
* state = ( struct dos_mode_at_state ) {
. dir_fsp = dir_fsp ,
. smb_fname = smb_fname ,
} ;
if ( ! VALID_STAT ( smb_fname - > st ) ) {
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
}
subreq = SMB_VFS_GET_DOS_ATTRIBUTES_SEND ( state ,
2018-12-28 14:12:20 +03:00
ev ,
2018-03-15 17:21:53 +03:00
dir_fsp ,
smb_fname ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , dos_mode_at_vfs_get_dosmode_done , req ) ;
return req ;
}
static void dos_mode_at_vfs_get_dosmode_done ( struct tevent_req * subreq )
{
struct tevent_req * req =
tevent_req_callback_data ( subreq ,
struct tevent_req ) ;
struct dos_mode_at_state * state =
tevent_req_data ( req ,
struct dos_mode_at_state ) ;
char * path = NULL ;
struct smb_filename * smb_path = NULL ;
struct vfs_aio_state aio_state ;
NTSTATUS status ;
status = SMB_VFS_GET_DOS_ATTRIBUTES_RECV ( subreq ,
& aio_state ,
& state - > dosmode ) ;
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
/*
* Both the sync dos_mode ( ) as well as the async
* dos_mode_at_ [ send | recv ] have no real error return , the only
* unhandled error is when the stat info in smb_fname is not
* valid ( cf the checks in dos_mode ( ) and dos_mode_at_send ( ) .
*
* If SMB_VFS_GET_DOS_ATTRIBUTES [ _SEND | _RECV ] fails we must call
* dos_mode_post ( ) which also does the mapping of a last ressort
* from S_IFMT ( st_mode ) .
*
* Only if we get NT_STATUS_NOT_IMPLEMENTED from a stacked VFS
* module we must fallback to sync processing .
*/
if ( ! NT_STATUS_EQUAL ( status , NT_STATUS_NOT_IMPLEMENTED ) ) {
/*
* state - > dosmode should still be 0 , but reset
* it to be sure .
*/
state - > dosmode = 0 ;
status = NT_STATUS_OK ;
}
}
if ( NT_STATUS_IS_OK ( status ) ) {
state - > dosmode = dos_mode_post ( state - > dosmode ,
state - > dir_fsp - > conn ,
state - > smb_fname ,
__func__ ) ;
tevent_req_done ( req ) ;
return ;
}
/*
* Fall back to sync dos_mode ( ) if we got NOT_IMPLEMENTED .
*/
path = talloc_asprintf ( state ,
" %s/%s " ,
state - > dir_fsp - > fsp_name - > base_name ,
state - > smb_fname - > base_name ) ;
if ( tevent_req_nomem ( path , req ) ) {
return ;
}
smb_path = synthetic_smb_fname ( state , path , NULL , NULL , 0 ) ;
if ( tevent_req_nomem ( path , req ) ) {
return ;
}
state - > dosmode = dos_mode ( state - > dir_fsp - > conn , smb_path ) ;
tevent_req_done ( req ) ;
return ;
}
NTSTATUS dos_mode_at_recv ( struct tevent_req * req , uint32_t * dosmode )
{
struct dos_mode_at_state * state =
tevent_req_data ( req ,
struct dos_mode_at_state ) ;
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
tevent_req_received ( req ) ;
return status ;
}
* dosmode = state - > dosmode ;
tevent_req_received ( req ) ;
return NT_STATUS_OK ;
}
1998-08-17 11:40:06 +04:00
/*******************************************************************
2004-04-01 02:46:15 +04:00
chmod a file - but preserve some bits .
2009-11-18 01:55:02 +03:00
If " store dos attributes " is also set it will store the create time
from the stat struct in smb_fname ( in NTTIME format ) in the EA
attribute also .
1998-08-17 11:40:06 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-11-26 02:25:42 +03:00
2009-07-07 01:36:16 +04:00
int file_set_dosmode ( connection_struct * conn , struct smb_filename * smb_fname ,
2015-05-03 07:01:14 +03:00
uint32_t dosmode , const char * parent_dir , bool newfile )
1998-08-17 11:40:06 +04:00
{
2001-01-09 23:34:37 +03:00
int mask = 0 ;
mode_t tmp ;
mode_t unixmode ;
2008-01-16 12:17:03 +03:00
int ret = - 1 , lret = - 1 ;
2013-04-26 01:00:42 +04:00
files_struct * fsp = NULL ;
2014-05-01 22:07:44 +04:00
bool need_close = false ;
NTSTATUS status ;
2001-01-09 23:34:37 +03:00
2013-04-26 00:59:22 +04:00
if ( ! CAN_WRITE ( conn ) ) {
errno = EROFS ;
return - 1 ;
}
2016-09-11 13:39:13 +03:00
dosmode & = SAMBA_ATTRIBUTES_MASK ;
2005-11-14 09:29:48 +03:00
2009-07-07 01:36:16 +04:00
DEBUG ( 10 , ( " file_set_dosmode: setting dos mode 0x%x on file %s \n " ,
dosmode , smb_fname_str_dbg ( smb_fname ) ) ) ;
2007-12-27 23:31:08 +03:00
2009-07-07 01:36:16 +04:00
unixmode = smb_fname - > st . st_ex_mode ;
2007-12-27 23:31:08 +03:00
2017-05-24 03:11:18 +03:00
get_acl_group_bits ( conn , smb_fname ,
& smb_fname - > st . st_ex_mode ) ;
2003-11-26 02:25:42 +03:00
2009-07-07 01:36:16 +04:00
if ( S_ISDIR ( smb_fname - > st . st_ex_mode ) )
2011-04-29 05:57:02 +04:00
dosmode | = FILE_ATTRIBUTE_DIRECTORY ;
2002-03-05 04:43:50 +03:00
else
2011-04-29 05:57:02 +04:00
dosmode & = ~ FILE_ATTRIBUTE_DIRECTORY ;
1998-08-17 11:40:06 +04:00
2004-04-02 22:46:19 +04:00
/* Store the DOS attributes in an EA by preference. */
2016-03-26 01:32:09 +03:00
status = SMB_VFS_SET_DOS_ATTRIBUTES ( conn , smb_fname , dosmode ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
2007-11-01 01:45:45 +03:00
if ( ! newfile ) {
notify_fname ( conn , NOTIFY_ACTION_MODIFIED ,
2016-03-26 01:32:09 +03:00
FILE_NOTIFY_CHANGE_ATTRIBUTES ,
smb_fname - > base_name ) ;
2007-11-01 01:45:45 +03:00
}
2009-07-07 01:36:16 +04:00
smb_fname - > st . st_ex_mode = unixmode ;
2004-04-02 22:46:19 +04:00
return 0 ;
2016-03-26 01:32:09 +03:00
} else {
/*
* Only fall back to using UNIX modes if
* we get NOT_IMPLEMENTED .
*/
if ( ! NT_STATUS_EQUAL ( status , NT_STATUS_NOT_IMPLEMENTED ) ) {
errno = map_errno_from_nt_status ( status ) ;
return - 1 ;
}
2004-04-02 22:46:19 +04:00
}
2016-03-26 01:32:09 +03:00
/* Fall back to UNIX modes. */
2009-07-08 06:20:22 +04:00
unixmode = unix_mode ( conn , dosmode , smb_fname , parent_dir ) ;
1998-08-17 11:40:06 +04:00
2013-02-19 16:27:10 +04:00
/* preserve the file type bits */
mask | = S_IFMT ;
2001-01-09 23:34:37 +03:00
/* preserve the s bits */
mask | = ( S_ISUID | S_ISGID ) ;
1998-08-17 11:40:06 +04:00
2001-01-09 23:34:37 +03:00
/* preserve the t bit */
1998-08-17 11:40:06 +04:00
# ifdef S_ISVTX
2001-01-09 23:34:37 +03:00
mask | = S_ISVTX ;
1998-08-17 11:40:06 +04:00
# endif
2001-01-09 23:34:37 +03:00
/* possibly preserve the x bits */
if ( ! MAP_ARCHIVE ( conn ) )
mask | = S_IXUSR ;
if ( ! MAP_SYSTEM ( conn ) )
mask | = S_IXGRP ;
if ( ! MAP_HIDDEN ( conn ) )
mask | = S_IXOTH ;
2009-07-07 01:36:16 +04:00
unixmode | = ( smb_fname - > st . st_ex_mode & mask ) ;
2001-01-09 23:34:37 +03:00
/* if we previously had any r bits set then leave them alone */
2009-07-07 01:36:16 +04:00
if ( ( tmp = smb_fname - > st . st_ex_mode & ( S_IRUSR | S_IRGRP | S_IROTH ) ) ) {
2001-01-09 23:34:37 +03:00
unixmode & = ~ ( S_IRUSR | S_IRGRP | S_IROTH ) ;
unixmode | = tmp ;
}
/* if we previously had any w bits set then leave them alone
whilst adding in the new w bits , if the new mode is not rdonly */
if ( ! IS_DOS_READONLY ( dosmode ) ) {
2009-07-07 01:36:16 +04:00
unixmode | = ( smb_fname - > st . st_ex_mode & ( S_IWUSR | S_IWGRP | S_IWOTH ) ) ;
2001-01-09 23:34:37 +03:00
}
2011-03-31 05:00:09 +04:00
/*
* From the chmod 2 man page :
*
* " If the calling process is not privileged, and the group of the file
* does not match the effective group ID of the process or one of its
* supplementary group IDs , the S_ISGID bit will be turned off , but
* this will not cause an error to be returned . "
*
* Simply refuse to do the chmod in this case .
*/
if ( S_ISDIR ( smb_fname - > st . st_ex_mode ) & & ( unixmode & S_ISGID ) & &
geteuid ( ) ! = sec_initial_uid ( ) & &
! current_user_in_group ( conn , smb_fname - > st . st_ex_gid ) ) {
DEBUG ( 3 , ( " file_set_dosmode: setgid bit cannot be "
" set for directory %s \n " ,
smb_fname_str_dbg ( smb_fname ) ) ) ;
errno = EPERM ;
return - 1 ;
}
2016-03-02 03:20:25 +03:00
ret = SMB_VFS_CHMOD ( conn , smb_fname , unixmode ) ;
2008-01-16 12:17:03 +03:00
if ( ret = = 0 ) {
if ( ! newfile | | ( lret ! = - 1 ) ) {
2007-11-01 01:45:45 +03:00
notify_fname ( conn , NOTIFY_ACTION_MODIFIED ,
2009-07-08 23:24:03 +04:00
FILE_NOTIFY_CHANGE_ATTRIBUTES ,
smb_fname - > base_name ) ;
2007-11-01 01:45:45 +03:00
}
2009-07-07 01:36:16 +04:00
smb_fname - > st . st_ex_mode = unixmode ;
2001-01-18 02:47:08 +03:00
return 0 ;
2007-01-17 19:23:45 +03:00
}
2001-01-09 23:34:37 +03:00
2001-01-18 02:47:08 +03:00
if ( ( errno ! = EPERM ) & & ( errno ! = EACCES ) )
2001-01-09 23:34:37 +03:00
return - 1 ;
if ( ! lp_dos_filemode ( SNUM ( conn ) ) )
return - 1 ;
/* We want DOS semantics, ie allow non owner with write permission to change the
2007-03-06 02:40:03 +03:00
bits on a file . Just like file_ntimes below .
2001-01-09 23:34:37 +03:00
*/
2013-04-26 01:02:24 +04:00
if ( ! can_write_to_file ( conn , smb_fname ) ) {
errno = EACCES ;
return - 1 ;
}
2013-04-26 01:00:42 +04:00
/*
2014-05-01 22:07:44 +04:00
* We need to get an open file handle to do the
* metadata operation under root .
2013-04-26 01:00:42 +04:00
*/
2014-05-01 22:07:44 +04:00
status = get_file_handle_for_metadata ( conn ,
smb_fname ,
& fsp ,
& need_close ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
errno = map_errno_from_nt_status ( status ) ;
2013-04-26 01:00:42 +04:00
return - 1 ;
2014-05-01 22:07:44 +04:00
}
2013-04-26 01:00:42 +04:00
become_root ( ) ;
ret = SMB_VFS_FCHMOD ( fsp , unixmode ) ;
unbecome_root ( ) ;
2014-05-01 22:07:44 +04:00
if ( need_close ) {
close_file ( NULL , fsp , NORMAL_CLOSE ) ;
}
2013-04-26 01:00:42 +04:00
if ( ! newfile ) {
notify_fname ( conn , NOTIFY_ACTION_MODIFIED ,
FILE_NOTIFY_CHANGE_ATTRIBUTES ,
smb_fname - > base_name ) ;
}
if ( ret = = 0 ) {
smb_fname - > st . st_ex_mode = unixmode ;
2001-01-09 23:34:37 +03:00
}
return ( ret ) ;
1998-08-17 11:40:06 +04:00
}
2010-12-14 12:03:07 +03:00
NTSTATUS file_set_sparse ( connection_struct * conn ,
2010-12-17 03:42:33 +03:00
files_struct * fsp ,
2010-12-14 12:03:07 +03:00
bool sparse )
{
uint32_t old_dosmode ;
uint32_t new_dosmode ;
2010-12-17 03:42:33 +03:00
NTSTATUS status ;
2010-12-14 12:03:07 +03:00
2010-12-17 03:50:31 +03:00
if ( ! CAN_WRITE ( conn ) ) {
DEBUG ( 9 , ( " file_set_sparse: fname[%s] set[%u] "
" on readonly share[%s] \n " ,
smb_fname_str_dbg ( fsp - > fsp_name ) ,
sparse ,
2012-07-18 09:37:23 +04:00
lp_servicename ( talloc_tos ( ) , SNUM ( conn ) ) ) ) ;
2010-12-17 03:50:31 +03:00
return NT_STATUS_MEDIA_WRITE_PROTECTED ;
}
2015-02-23 22:27:37 +03:00
/*
* Windows Server 2008 & 2012 permit FSCTL_SET_SPARSE if any of the
* following access flags are granted .
*/
if ( ( fsp - > access_mask & ( FILE_WRITE_DATA
| FILE_WRITE_ATTRIBUTES
| SEC_FILE_APPEND_DATA ) ) = = 0 ) {
2010-12-17 03:50:31 +03:00
DEBUG ( 9 , ( " file_set_sparse: fname[%s] set[%u] "
" access_mask[0x%08X] - access denied \n " ,
smb_fname_str_dbg ( fsp - > fsp_name ) ,
sparse ,
fsp - > access_mask ) ) ;
return NT_STATUS_ACCESS_DENIED ;
}
2014-08-27 17:42:00 +04:00
if ( fsp - > is_directory ) {
DEBUG ( 9 , ( " invalid attempt to %s sparse flag on dir %s \n " ,
( sparse ? " set " : " clear " ) ,
smb_fname_str_dbg ( fsp - > fsp_name ) ) ) ;
return NT_STATUS_INVALID_PARAMETER ;
}
if ( IS_IPC ( conn ) | | IS_PRINT ( conn ) ) {
DEBUG ( 9 , ( " attempt to %s sparse flag over invalid conn \n " ,
( sparse ? " set " : " clear " ) ) ) ;
return NT_STATUS_INVALID_PARAMETER ;
}
2010-12-14 12:03:07 +03:00
DEBUG ( 10 , ( " file_set_sparse: setting sparse bit %u on file %s \n " ,
2010-12-17 03:42:33 +03:00
sparse , smb_fname_str_dbg ( fsp - > fsp_name ) ) ) ;
2010-12-14 12:03:07 +03:00
if ( ! lp_store_dos_attributes ( SNUM ( conn ) ) ) {
return NT_STATUS_INVALID_DEVICE_REQUEST ;
}
2010-12-17 03:42:33 +03:00
status = vfs_stat_fsp ( fsp ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2010-12-14 12:03:07 +03:00
}
2010-12-17 03:42:33 +03:00
old_dosmode = dos_mode ( conn , fsp - > fsp_name ) ;
2010-12-14 12:03:07 +03:00
if ( sparse & & ! ( old_dosmode & FILE_ATTRIBUTE_SPARSE ) ) {
new_dosmode = old_dosmode | FILE_ATTRIBUTE_SPARSE ;
} else if ( ! sparse & & ( old_dosmode & FILE_ATTRIBUTE_SPARSE ) ) {
new_dosmode = old_dosmode & ~ FILE_ATTRIBUTE_SPARSE ;
} else {
return NT_STATUS_OK ;
}
/* Store the DOS attributes in an EA. */
2016-03-26 01:32:09 +03:00
status = SMB_VFS_FSET_DOS_ATTRIBUTES ( conn , fsp , new_dosmode ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2010-12-14 12:03:07 +03:00
}
notify_fname ( conn , NOTIFY_ACTION_MODIFIED ,
FILE_NOTIFY_CHANGE_ATTRIBUTES ,
2010-12-17 03:50:31 +03:00
fsp - > fsp_name - > base_name ) ;
2010-12-14 12:03:07 +03:00
2010-12-21 04:58:33 +03:00
fsp - > is_sparse = sparse ;
2010-12-14 12:03:07 +03:00
return NT_STATUS_OK ;
}
1998-08-17 17:11:34 +04:00
/*******************************************************************
2007-03-06 02:40:03 +03:00
Wrapper around the VFS ntimes that possibly allows DOS semantics rather
2004-04-01 02:46:15 +04:00
than POSIX .
1998-08-17 17:11:34 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-04-01 02:46:15 +04:00
2009-07-03 00:39:20 +04:00
int file_ntimes ( connection_struct * conn , const struct smb_filename * smb_fname ,
struct smb_file_time * ft )
1998-08-17 17:11:34 +04:00
{
2004-04-01 02:46:15 +04:00
int ret = - 1 ;
errno = 0 ;
2008-03-12 17:39:38 +03:00
DEBUG ( 6 , ( " file_ntime: actime: %s " ,
2009-01-24 01:40:19 +03:00
time_to_asc ( convert_timespec_to_time_t ( ft - > atime ) ) ) ) ;
2008-03-12 17:39:38 +03:00
DEBUG ( 6 , ( " file_ntime: modtime: %s " ,
2009-01-24 01:40:19 +03:00
time_to_asc ( convert_timespec_to_time_t ( ft - > mtime ) ) ) ) ;
2009-07-31 01:27:32 +04:00
DEBUG ( 6 , ( " file_ntime: ctime: %s " ,
time_to_asc ( convert_timespec_to_time_t ( ft - > ctime ) ) ) ) ;
2009-01-24 01:40:19 +03:00
DEBUG ( 6 , ( " file_ntime: createtime: %s " ,
time_to_asc ( convert_timespec_to_time_t ( ft - > create_time ) ) ) ) ;
2008-03-12 17:39:38 +03:00
2005-09-17 00:06:10 +04:00
/* Don't update the time on read-only shares */
/* We need this as set_filetime (which can be called on
close and other paths ) can end up calling this function
without the NEED_WRITE protection . Found by :
Leo Weppelman < leo @ wau . mis . ah . nl >
*/
if ( ! CAN_WRITE ( conn ) ) {
return 0 ;
}
2009-07-03 00:39:20 +04:00
if ( SMB_VFS_NTIMES ( conn , smb_fname , ft ) = = 0 ) {
2004-04-01 02:46:15 +04:00
return 0 ;
2007-03-06 02:40:03 +03:00
}
2004-04-01 02:46:15 +04:00
2007-03-06 02:40:03 +03:00
if ( ( errno ! = EPERM ) & & ( errno ! = EACCES ) ) {
2004-04-01 02:46:15 +04:00
return - 1 ;
2007-03-06 02:40:03 +03:00
}
2004-04-01 02:46:15 +04:00
2007-03-06 02:40:03 +03:00
if ( ! lp_dos_filetimes ( SNUM ( conn ) ) ) {
2004-04-01 02:46:15 +04:00
return - 1 ;
2007-03-06 02:40:03 +03:00
}
2004-04-01 02:46:15 +04:00
/* We have permission (given by the Samba admin) to
break POSIX semantics and allow a user to change
the time on a file they don ' t own but can write to
( as DOS does ) .
*/
/* Check if we have write access. */
2009-06-26 05:19:09 +04:00
if ( can_write_to_file ( conn , smb_fname ) ) {
2005-03-25 01:34:28 +03:00
/* We are allowed to become root and change the filetime. */
become_root ( ) ;
2009-07-03 00:39:20 +04:00
ret = SMB_VFS_NTIMES ( conn , smb_fname , ft ) ;
2005-03-25 01:34:28 +03:00
unbecome_root ( ) ;
2004-04-01 02:46:15 +04:00
}
return ret ;
1998-08-17 17:11:34 +04:00
}
2007-11-01 02:32:48 +03:00
2008-09-06 06:00:48 +04:00
/******************************************************************
Force a " sticky " write time on a pathname . This will always be
returned on all future write time queries and set on close .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-04-01 02:46:15 +04:00
2009-07-08 04:27:50 +04:00
bool set_sticky_write_time_path ( struct file_id fileid , struct timespec mtime )
1998-08-17 17:11:34 +04:00
{
2007-03-06 02:40:03 +03:00
if ( null_timespec ( mtime ) ) {
2008-03-12 17:39:38 +03:00
return true ;
2007-03-06 02:40:03 +03:00
}
1998-08-17 17:11:34 +04:00
2008-09-06 06:00:48 +04:00
if ( ! set_sticky_write_time ( fileid , mtime ) ) {
2008-03-12 17:39:38 +03:00
return false ;
2004-04-01 02:46:15 +04:00
}
2007-01-17 19:23:45 +03:00
2007-11-01 02:32:48 +03:00
return true ;
2007-03-06 02:40:03 +03:00
}
2008-03-12 17:39:38 +03:00
2008-09-06 06:00:48 +04:00
/******************************************************************
Force a " sticky " write time on an fsp . This will always be
returned on all future write time queries and set on close .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-07-08 04:27:50 +04:00
bool set_sticky_write_time_fsp ( struct files_struct * fsp , struct timespec mtime )
2008-03-12 17:39:38 +03:00
{
2009-11-18 01:55:02 +03:00
if ( null_timespec ( mtime ) ) {
return true ;
}
2008-09-06 06:00:48 +04:00
fsp - > write_time_forced = true ;
TALLOC_FREE ( fsp - > update_write_time_event ) ;
2009-07-02 21:27:01 +04:00
return set_sticky_write_time_path ( fsp - > file_id , mtime ) ;
2008-09-06 06:00:48 +04:00
}
2009-08-11 02:07:53 +04:00
/******************************************************************
2009-08-13 00:00:54 +04:00
Set a create time EA .
2009-08-11 02:07:53 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-08-13 00:00:54 +04:00
NTSTATUS set_create_timespec_ea ( connection_struct * conn ,
2009-11-18 01:55:02 +03:00
const struct smb_filename * psmb_fname ,
2009-08-13 00:00:54 +04:00
struct timespec create_time )
{
2013-04-15 13:36:30 +04:00
struct smb_filename * smb_fname ;
2009-11-18 01:55:02 +03:00
uint32_t dosmode ;
2009-08-13 00:00:54 +04:00
int ret ;
2009-11-18 01:55:02 +03:00
if ( ! lp_store_dos_attributes ( SNUM ( conn ) ) ) {
2009-08-13 00:00:54 +04:00
return NT_STATUS_OK ;
}
2016-03-19 07:19:38 +03:00
smb_fname = synthetic_smb_fname ( talloc_tos ( ) ,
psmb_fname - > base_name ,
NULL ,
& psmb_fname - > st ,
psmb_fname - > flags ) ;
2009-11-18 01:55:02 +03:00
2013-04-15 13:36:30 +04:00
if ( smb_fname = = NULL ) {
return NT_STATUS_NO_MEMORY ;
2009-08-13 00:00:54 +04:00
}
2009-11-18 01:55:02 +03:00
dosmode = dos_mode ( conn , smb_fname ) ;
smb_fname - > st . st_ex_btime = create_time ;
ret = file_set_dosmode ( conn , smb_fname , dosmode , NULL , false ) ;
2009-08-13 00:00:54 +04:00
if ( ret = = - 1 ) {
2016-03-24 07:56:30 +03:00
return map_nt_error_from_unix ( errno ) ;
2009-08-13 00:00:54 +04:00
}
2009-11-18 01:55:02 +03:00
2009-08-13 02:08:23 +04:00
DEBUG ( 10 , ( " set_create_timespec_ea: wrote create time EA for file %s \n " ,
smb_fname_str_dbg ( smb_fname ) ) ) ;
2009-08-13 00:00:54 +04:00
2009-11-18 01:55:02 +03:00
return NT_STATUS_OK ;
2009-08-13 00:00:54 +04:00
}
/******************************************************************
2009-11-18 01:55:02 +03:00
Return a create time .
2009-08-13 00:00:54 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct timespec get_create_timespec ( connection_struct * conn ,
struct files_struct * fsp ,
2009-08-11 02:07:53 +04:00
const struct smb_filename * smb_fname )
{
2009-11-18 01:55:02 +03:00
return smb_fname - > st . st_ex_btime ;
2009-08-11 02:07:53 +04:00
}
/******************************************************************
Return a change time ( may look at EA in future ) .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-08-13 00:00:54 +04:00
struct timespec get_change_timespec ( connection_struct * conn ,
struct files_struct * fsp ,
2009-08-11 02:07:53 +04:00
const struct smb_filename * smb_fname )
{
return smb_fname - > st . st_ex_mtime ;
}
2014-05-01 22:07:44 +04:00
/****************************************************************************
Get a real open file handle we can do meta - data operations on . As it ' s
going to be used under root access only on meta - data we should look for
any existing open file handle first , and use that in preference ( also to
avoid kernel self - oplock breaks ) . If not use an INTERNAL_OPEN_ONLY handle .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS get_file_handle_for_metadata ( connection_struct * conn ,
2016-03-26 01:32:09 +03:00
const struct smb_filename * smb_fname ,
2014-05-01 22:07:44 +04:00
files_struct * * ret_fsp ,
bool * need_close )
{
NTSTATUS status ;
files_struct * fsp ;
struct file_id file_id ;
2016-03-26 01:32:09 +03:00
struct smb_filename * smb_fname_cp = NULL ;
2014-05-01 22:07:44 +04:00
* need_close = false ;
if ( ! VALID_STAT ( smb_fname - > st ) ) {
return NT_STATUS_INVALID_PARAMETER ;
}
file_id = vfs_file_id_from_sbuf ( conn , & smb_fname - > st ) ;
for ( fsp = file_find_di_first ( conn - > sconn , file_id ) ;
fsp ;
fsp = file_find_di_next ( fsp ) ) {
if ( fsp - > fh - > fd ! = - 1 ) {
* ret_fsp = fsp ;
return NT_STATUS_OK ;
}
}
2016-03-26 01:32:09 +03:00
smb_fname_cp = cp_smb_filename ( talloc_tos ( ) ,
smb_fname ) ;
if ( smb_fname_cp = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2014-05-01 22:07:44 +04:00
/* Opens an INTERNAL_OPEN_ONLY write handle. */
status = SMB_VFS_CREATE_FILE (
conn , /* conn */
NULL , /* req */
0 , /* root_dir_fid */
2016-03-26 01:32:09 +03:00
smb_fname_cp , /* fname */
2017-08-29 17:08:06 +03:00
FILE_WRITE_ATTRIBUTES , /* access_mask */
2014-05-01 22:07:44 +04:00
( FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
FILE_SHARE_DELETE ) ,
FILE_OPEN , /* create_disposition*/
0 , /* create_options */
0 , /* file_attributes */
INTERNAL_OPEN_ONLY , /* oplock_request */
2013-08-21 17:56:14 +04:00
NULL , /* lease */
2014-05-01 22:07:44 +04:00
0 , /* allocation_size */
0 , /* private_flags */
NULL , /* sd */
NULL , /* ea_list */
ret_fsp , /* result */
2014-11-26 16:12:51 +03:00
NULL , /* pinfo */
NULL , NULL ) ; /* create context */
2014-05-01 22:07:44 +04:00
2016-03-26 01:32:09 +03:00
TALLOC_FREE ( smb_fname_cp ) ;
2014-05-01 22:07:44 +04:00
if ( NT_STATUS_IS_OK ( status ) ) {
* need_close = true ;
}
return status ;
}