2007-08-31 01:46:42 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1998-08-17 11:40:06 +04:00
filename handling routines
Copyright ( C ) Andrew Tridgell 1992 - 1998
2007-09-08 00:57:01 +04:00
Copyright ( C ) Jeremy Allison 1999 - 2007
2000-01-27 00:25:35 +03:00
Copyright ( C ) Ying Chen 2000
2007-07-12 02:39:11 +04:00
Copyright ( C ) Volker Lendecke 2007
2007-08-31 01:46:42 +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 .
2007-08-31 01:46:42 +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 .
2007-08-31 01:46:42 +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
*/
2000-01-27 00:25:35 +03:00
/*
* New hash table stat cache code added by Ying Chen .
*/
1998-08-17 11:40:06 +04:00
# include "includes.h"
2011-02-26 01:20:06 +03:00
# include "system/filesys.h"
2010-08-18 18:44:47 +04:00
# include "fake_file.h"
2011-03-22 18:57:01 +03:00
# include "smbd/smbd.h"
2012-05-23 15:22:47 +04:00
# include "smbd/globals.h"
1998-08-17 11:40:06 +04:00
2017-05-18 21:56:39 +03:00
uint32_t ucf_flags_from_smb_request ( struct smb_request * req )
2016-10-13 13:42:59 +03:00
{
uint32_t ucf_flags = 0 ;
2017-05-18 22:18:58 +03:00
if ( req ! = NULL ) {
if ( req - > posix_pathnames ) {
ucf_flags | = UCF_POSIX_PATHNAMES ;
}
if ( req - > flags2 & FLAGS2_DFS_PATHNAMES ) {
ucf_flags | = UCF_DFS_PATHNAME ;
}
2017-05-18 23:24:26 +03:00
if ( req - > flags2 & FLAGS2_REPARSE_PATH ) {
ucf_flags | = UCF_GMT_PATHNAME ;
}
2016-10-13 13:42:59 +03:00
}
2017-05-18 21:56:39 +03:00
return ucf_flags ;
}
uint32_t filename_create_ucf_flags ( struct smb_request * req , uint32_t create_disposition )
{
uint32_t ucf_flags = 0 ;
ucf_flags | = ucf_flags_from_smb_request ( req ) ;
2016-10-13 13:42:59 +03:00
switch ( create_disposition ) {
case FILE_OPEN :
case FILE_OVERWRITE :
break ;
case FILE_SUPERSEDE :
case FILE_CREATE :
case FILE_OPEN_IF :
case FILE_OVERWRITE_IF :
ucf_flags | = UCF_PREP_CREATEFILE ;
break ;
}
return ucf_flags ;
}
2008-01-20 01:25:36 +03:00
static NTSTATUS build_stream_path ( TALLOC_CTX * mem_ctx ,
connection_struct * conn ,
s3: Change unix_convert (and its callers) to use struct smb_filename
This is the first of a series of patches that change path based
operations to operate on a struct smb_filename instead of a char *.
This same concept already exists in source4.
My goals for this series of patches are to eventually:
1) Solve the stream vs. posix filename that contains a colon ambiguity
that currently exists.
2) Make unix_convert the only function that parses the stream name.
3) Clean up the unix_convert API.
4) Change all path based vfs operation to take a struct smb_filename.
5) Make is_ntfs_stream_name() a constant operation that can simply
check the state of struct smb_filename rather than re-parse the
filename.
6) Eliminate the need for split_ntfs_stream_name() to exist.
My strategy is to start from the inside at unix_convert() and work my
way out through the vfs layer, call by call. This first patch does
just that, by changing unix_convert and all of its callers to operate
on struct smb_filename. Since this is such a large change, I plan on
pushing the patches in phases, where each phase keeps full
compatibility and passes make test.
The API of unix_convert has been simplified from:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
bool allow_wcard_last_component,
char **pp_conv_path,
char **pp_saved_last_component,
SMB_STRUCT_STAT *pst)
to:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
struct smb_filename *smb_fname,
uint32_t ucf_flags)
Currently the smb_filename struct looks like:
struct smb_filename {
char *base_name;
char *stream_name;
char *original_lcomp;
SMB_STRUCT_STAT st;
};
One key point here is the decision to break up the base_name and
stream_name. I have introduced a helper function called
get_full_smb_filename() that takes an smb_filename struct and
allocates the full_name. I changed the callers of unix_convert() to
subsequently call get_full_smb_filename() for the time being, but I
plan to eventually eliminate get_full_smb_filename().
2009-04-08 00:39:57 +04:00
struct smb_filename * smb_fname ) ;
1998-08-17 11:40:06 +04:00
/****************************************************************************
1998-08-28 00:38:53 +04:00
Mangle the 2 nd name and check if it is then equal to the first name .
1998-08-17 11:40:06 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-07-15 14:35:28 +04:00
2007-10-19 04:40:25 +04:00
static bool mangled_equal ( const char * name1 ,
2007-08-31 01:46:42 +04:00
const char * name2 ,
const struct share_params * p )
1998-08-17 11:40:06 +04:00
{
2007-09-08 00:57:01 +04:00
char mname [ 13 ] ;
2007-08-31 01:46:42 +04:00
2007-09-08 00:57:01 +04:00
if ( ! name_to_8_3 ( name2 , mname , False , p ) ) {
return False ;
}
return strequal ( name1 , mname ) ;
1998-08-17 11:40:06 +04:00
}
2007-01-13 04:29:10 +03:00
/****************************************************************************
Cope with the differing wildcard and non - wildcard error cases .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-08-31 01:46:42 +04:00
static NTSTATUS determine_path_error ( const char * name ,
2015-12-12 01:36:33 +03:00
bool allow_wcard_last_component ,
bool posix_pathnames )
2007-01-13 04:29:10 +03:00
{
const char * p ;
2015-12-12 01:36:33 +03:00
bool name_has_wild = false ;
2007-01-13 04:29:10 +03:00
if ( ! allow_wcard_last_component ) {
/* Error code within a pathname. */
return NT_STATUS_OBJECT_PATH_NOT_FOUND ;
}
/* We're terminating here so we
* can be a little slower and get
* the error code right . Windows
* treats the last part of the pathname
* separately I think , so if the last
* component is a wildcard then we treat
* this . / as " end of component " */
p = strchr ( name , ' / ' ) ;
2015-12-12 01:36:33 +03:00
if ( ! posix_pathnames ) {
name_has_wild = ms_has_wild ( name ) ;
}
if ( ! p & & ( name_has_wild | | ISDOT ( name ) ) ) {
2007-01-13 04:29:10 +03:00
/* Error code at the end of a pathname. */
return NT_STATUS_OBJECT_NAME_INVALID ;
} else {
/* Error code within a pathname. */
return NT_STATUS_OBJECT_PATH_NOT_FOUND ;
}
}
2007-08-31 01:46:42 +04:00
2009-11-26 00:17:56 +03:00
static NTSTATUS check_for_dot_component ( const struct smb_filename * smb_fname )
{
/* Ensure we catch all names with in "/."
this is disallowed under Windows and
in POSIX they ' ve already been removed . */
const char * p = strstr ( smb_fname - > base_name , " /. " ) ; /*mb safe*/
if ( p ) {
if ( p [ 2 ] = = ' / ' ) {
/* Error code within a pathname. */
return NT_STATUS_OBJECT_PATH_NOT_FOUND ;
} else if ( p [ 2 ] = = ' \0 ' ) {
/* Error code at the end of a pathname. */
return NT_STATUS_OBJECT_NAME_INVALID ;
}
}
return NT_STATUS_OK ;
}
2010-09-11 10:28:15 +04:00
/****************************************************************************
Optimization for common case where the missing part
is in the last component and the client already
sent the correct case .
Returns NT_STATUS_OK to mean continue the tree walk
( possibly with modified start pointer ) .
Any other NT_STATUS_XXX error means terminate the path
lookup here .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS check_parent_exists ( TALLOC_CTX * ctx ,
connection_struct * conn ,
bool posix_pathnames ,
2011-04-04 21:15:16 +04:00
const struct smb_filename * smb_fname ,
2010-09-11 10:28:15 +04:00
char * * pp_dirpath ,
2021-05-11 21:31:55 +03:00
char * * pp_start ,
int * p_parent_stat_errno )
2010-09-11 10:28:15 +04:00
{
2020-04-29 16:43:30 +03:00
char * parent_name = NULL ;
struct smb_filename * parent_fname = NULL ;
2010-09-11 10:28:15 +04:00
const char * last_component = NULL ;
NTSTATUS status ;
int ret ;
if ( ! parent_dirname ( ctx , smb_fname - > base_name ,
2020-04-29 16:43:30 +03:00
& parent_name ,
2010-09-11 10:28:15 +04:00
& last_component ) ) {
return NT_STATUS_NO_MEMORY ;
}
2015-12-12 01:38:49 +03:00
if ( ! posix_pathnames ) {
2020-04-29 16:43:30 +03:00
if ( ms_has_wild ( parent_name ) ) {
2018-08-22 19:15:12 +03:00
goto no_optimization_out ;
}
2015-12-12 01:38:49 +03:00
}
2010-09-11 10:28:15 +04:00
/*
* If there was no parent component in
2018-08-22 19:15:12 +03:00
* smb_fname - > base_name then don ' t do this
2010-09-11 10:28:15 +04:00
* optimization .
*/
2018-08-22 19:15:12 +03:00
if ( smb_fname - > base_name = = last_component ) {
goto no_optimization_out ;
2010-09-11 10:28:15 +04:00
}
2020-04-29 16:43:30 +03:00
parent_fname = synthetic_smb_fname ( ctx ,
parent_name ,
NULL ,
NULL ,
2020-04-30 12:48:32 +03:00
smb_fname - > twrp ,
2020-04-29 16:43:30 +03:00
smb_fname - > flags ) ;
if ( parent_fname = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2010-09-11 10:28:15 +04:00
if ( posix_pathnames ) {
2020-04-29 16:43:30 +03:00
ret = SMB_VFS_LSTAT ( conn , parent_fname ) ;
2010-09-11 10:28:15 +04:00
} else {
2020-04-29 16:43:30 +03:00
ret = SMB_VFS_STAT ( conn , parent_fname ) ;
2010-09-11 10:28:15 +04:00
}
/* If the parent stat failed, just continue
with the normal tree walk . */
if ( ret = = - 1 ) {
2021-05-11 21:31:55 +03:00
/*
* Optimization . Preserving the
* errno from the STAT / LSTAT here
* will allow us to save a duplicate
* STAT / LSTAT system call of the parent
* pathname in a hot code path in the caller .
*/
if ( p_parent_stat_errno ! = NULL ) {
* p_parent_stat_errno = errno ;
}
2018-08-22 19:15:12 +03:00
goto no_optimization_out ;
2010-09-11 10:28:15 +04:00
}
2020-04-29 16:43:30 +03:00
status = check_for_dot_component ( parent_fname ) ;
2010-09-11 10:28:15 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
/* Parent exists - set "start" to be the
2015-03-23 17:38:35 +03:00
* last component to shorten the tree walk . */
2010-09-11 10:28:15 +04:00
/*
2011-05-06 03:19:49 +04:00
* Safe to use discard_const_p
2010-09-11 10:28:15 +04:00
* here as last_component points
* into our smb_fname - > base_name .
*/
2011-05-05 21:41:59 +04:00
* pp_start = discard_const_p ( char , last_component ) ;
2010-09-11 10:28:15 +04:00
/* Update dirpath. */
TALLOC_FREE ( * pp_dirpath ) ;
2020-04-29 16:43:30 +03:00
* pp_dirpath = talloc_strdup ( ctx , parent_fname - > base_name ) ;
2010-09-11 10:33:18 +04:00
if ( ! * pp_dirpath ) {
return NT_STATUS_NO_MEMORY ;
}
2010-09-11 10:28:15 +04:00
DEBUG ( 5 , ( " check_parent_exists: name "
" = %s, dirpath = %s, "
" start = %s \n " ,
smb_fname - > base_name ,
* pp_dirpath ,
* pp_start ) ) ;
return NT_STATUS_OK ;
2018-08-22 19:15:12 +03:00
no_optimization_out :
2018-08-22 23:37:04 +03:00
/*
* We must still return an * pp_dirpath
* initialized to " . " , and a * pp_start
* pointing at smb_fname - > base_name .
*/
2020-04-29 16:43:30 +03:00
TALLOC_FREE ( parent_name ) ;
TALLOC_FREE ( parent_fname ) ;
2018-08-22 23:37:04 +03:00
* pp_dirpath = talloc_strdup ( ctx , " . " ) ;
if ( * pp_dirpath = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
/*
* Safe to use discard_const_p
* here as by convention smb_fname - > base_name
* is allocated off ctx .
*/
* pp_start = discard_const_p ( char , smb_fname - > base_name ) ;
2018-08-22 19:15:12 +03:00
return NT_STATUS_OK ;
2010-09-11 10:28:15 +04:00
}
2017-01-12 03:30:38 +03:00
/*
* Re - order a known good @ GMT - token path .
*/
static NTSTATUS rearrange_snapshot_path ( struct smb_filename * smb_fname ,
char * startp ,
char * endp )
{
size_t endlen = 0 ;
size_t gmt_len = endp - startp ;
char gmt_store [ gmt_len + 1 ] ;
char * parent = NULL ;
const char * last_component = NULL ;
char * newstr ;
bool ret ;
DBG_DEBUG ( " |%s| -> " , smb_fname - > base_name ) ;
/* Save off the @GMT-token. */
memcpy ( gmt_store , startp , gmt_len ) ;
gmt_store [ gmt_len ] = ' \0 ' ;
if ( * endp = = ' / ' ) {
/* Remove any trailing '/' */
endp + + ;
}
if ( * endp = = ' \0 ' ) {
/*
* @ GMT - token was at end of path .
2019-08-29 23:39:39 +03:00
* Remove any preceding ' / '
2017-01-12 03:30:38 +03:00
*/
if ( startp > smb_fname - > base_name & & startp [ - 1 ] = = ' / ' ) {
startp - - ;
}
}
/* Remove @GMT-token from the path. */
endlen = strlen ( endp ) ;
memmove ( startp , endp , endlen + 1 ) ;
/* Split the remaining path into components. */
ret = parent_dirname ( smb_fname ,
smb_fname - > base_name ,
& parent ,
& last_component ) ;
if ( ret = = false ) {
/* Must terminate debug with \n */
DBG_DEBUG ( " NT_STATUS_NO_MEMORY \n " ) ;
return NT_STATUS_NO_MEMORY ;
}
if ( ISDOT ( parent ) ) {
if ( last_component [ 0 ] = = ' \0 ' ) {
newstr = talloc_strdup ( smb_fname ,
gmt_store ) ;
} else {
newstr = talloc_asprintf ( smb_fname ,
" %s/%s " ,
gmt_store ,
last_component ) ;
}
} else {
newstr = talloc_asprintf ( smb_fname ,
" %s/%s/%s " ,
gmt_store ,
parent ,
last_component ) ;
}
TALLOC_FREE ( parent ) ;
TALLOC_FREE ( smb_fname - > base_name ) ;
smb_fname - > base_name = newstr ;
DBG_DEBUG ( " |%s| \n " , newstr ) ;
return NT_STATUS_OK ;
}
/*
2020-05-04 22:53:21 +03:00
* Strip a valid @ GMT - token from any incoming filename path ,
* adding any NTTIME encoded in the pathname into the
* twrp field of the passed in smb_fname .
2017-01-12 03:30:38 +03:00
*
2020-05-04 22:53:21 +03:00
* Valid @ GMT - tokens look like @ GMT - YYYY - MM - DD - HH - MM - SS
* at the * start * of a pathname component .
2017-01-12 03:30:38 +03:00
*
2020-05-04 22:53:21 +03:00
* If twrp is passed in then smb_fname - > twrp is set to that
* value , and the @ GMT - token part of the filename is removed
* and does not change the stored smb_fname - > twrp .
2017-01-12 03:30:38 +03:00
*
*/
2020-05-02 13:55:33 +03:00
NTSTATUS canonicalize_snapshot_path ( struct smb_filename * smb_fname ,
2020-05-04 14:51:37 +03:00
uint32_t ucf_flags ,
2020-05-02 13:55:33 +03:00
NTTIME twrp )
2017-01-12 03:30:38 +03:00
{
2020-05-04 14:51:37 +03:00
char * startp = NULL ;
2017-01-12 03:30:38 +03:00
char * endp = NULL ;
2020-04-30 16:24:44 +03:00
char * tmp = NULL ;
2017-01-12 03:30:38 +03:00
struct tm tm ;
2020-04-30 16:17:11 +03:00
time_t t ;
2020-04-30 16:24:44 +03:00
NTTIME nt ;
2020-04-30 15:13:44 +03:00
NTSTATUS status ;
2017-01-12 03:30:38 +03:00
2020-04-30 17:04:54 +03:00
if ( twrp ! = 0 ) {
smb_fname - > twrp = twrp ;
2020-04-30 16:14:36 +03:00
}
2020-05-04 14:51:37 +03:00
if ( ! ( ucf_flags & UCF_GMT_PATHNAME ) ) {
return NT_STATUS_OK ;
}
startp = strchr_m ( smb_fname - > base_name , ' @ ' ) ;
2017-01-12 03:30:38 +03:00
if ( startp = = NULL ) {
/* No @ */
return NT_STATUS_OK ;
}
startp = strstr_m ( startp , " @GMT- " ) ;
if ( startp = = NULL ) {
/* No @ */
return NT_STATUS_OK ;
}
if ( ( startp > smb_fname - > base_name ) & & ( startp [ - 1 ] ! = ' / ' ) ) {
/* the GMT-token does not start a path-component */
return NT_STATUS_OK ;
}
endp = strptime ( startp , GMT_FORMAT , & tm ) ;
if ( endp = = NULL ) {
/* Not a valid timestring. */
return NT_STATUS_OK ;
}
2020-04-30 15:13:44 +03:00
if ( endp [ 0 ] ! = ' \0 ' & & endp [ 0 ] ! = ' / ' ) {
2017-01-12 03:30:38 +03:00
/*
* It is not a complete path component , i . e . the path
* component continues after the gmt - token .
*/
return NT_STATUS_OK ;
}
2020-04-30 15:13:44 +03:00
status = rearrange_snapshot_path ( smb_fname , startp , endp ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2020-04-30 16:24:44 +03:00
startp = smb_fname - > base_name + GMT_NAME_LEN ;
if ( startp [ 0 ] = = ' / ' ) {
startp + + ;
}
tmp = talloc_strdup ( smb_fname , startp ) ;
if ( tmp = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
TALLOC_FREE ( smb_fname - > base_name ) ;
smb_fname - > base_name = tmp ;
if ( smb_fname - > twrp = = 0 ) {
tm . tm_isdst = - 1 ;
t = timegm ( & tm ) ;
unix_to_nt_time ( & nt , t ) ;
smb_fname - > twrp = nt ;
}
2020-04-30 16:17:11 +03:00
2020-04-30 15:13:44 +03:00
return NT_STATUS_OK ;
2017-01-12 03:30:38 +03:00
}
2020-03-26 22:35:26 +03:00
/*
* Utility function to normalize case on an incoming client filename
* if required on this connection struct .
* Performs an in - place case conversion guaranteed to stay the same size .
*/
static NTSTATUS normalize_filename_case ( connection_struct * conn , char * filename )
{
bool ok ;
if ( ! conn - > case_sensitive ) {
return NT_STATUS_OK ;
}
if ( conn - > case_preserve ) {
return NT_STATUS_OK ;
}
if ( conn - > short_case_preserve ) {
return NT_STATUS_OK ;
}
ok = strnorm ( filename , lp_default_case ( SNUM ( conn ) ) ) ;
if ( ! ok ) {
return NT_STATUS_INVALID_PARAMETER ;
}
return NT_STATUS_OK ;
}
1998-08-17 11:40:06 +04:00
/****************************************************************************
This routine is called to convert names from the dos namespace to unix
s3: Change unix_convert (and its callers) to use struct smb_filename
This is the first of a series of patches that change path based
operations to operate on a struct smb_filename instead of a char *.
This same concept already exists in source4.
My goals for this series of patches are to eventually:
1) Solve the stream vs. posix filename that contains a colon ambiguity
that currently exists.
2) Make unix_convert the only function that parses the stream name.
3) Clean up the unix_convert API.
4) Change all path based vfs operation to take a struct smb_filename.
5) Make is_ntfs_stream_name() a constant operation that can simply
check the state of struct smb_filename rather than re-parse the
filename.
6) Eliminate the need for split_ntfs_stream_name() to exist.
My strategy is to start from the inside at unix_convert() and work my
way out through the vfs layer, call by call. This first patch does
just that, by changing unix_convert and all of its callers to operate
on struct smb_filename. Since this is such a large change, I plan on
pushing the patches in phases, where each phase keeps full
compatibility and passes make test.
The API of unix_convert has been simplified from:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
bool allow_wcard_last_component,
char **pp_conv_path,
char **pp_saved_last_component,
SMB_STRUCT_STAT *pst)
to:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
struct smb_filename *smb_fname,
uint32_t ucf_flags)
Currently the smb_filename struct looks like:
struct smb_filename {
char *base_name;
char *stream_name;
char *original_lcomp;
SMB_STRUCT_STAT st;
};
One key point here is the decision to break up the base_name and
stream_name. I have introduced a helper function called
get_full_smb_filename() that takes an smb_filename struct and
allocates the full_name. I changed the callers of unix_convert() to
subsequently call get_full_smb_filename() for the time being, but I
plan to eventually eliminate get_full_smb_filename().
2009-04-08 00:39:57 +04:00
namespace . It needs to handle any case conversions , mangling , format changes ,
streams etc .
1998-08-17 11:40:06 +04:00
We assume that we have already done a chdir ( ) to the right " root " directory
for this service .
2020-03-25 09:53:29 +03:00
Conversion to basic unix format is already done in check_path_syntax ( ) .
Names must be relative to the root of the service - any leading / . and
trailing / ' s should have been trimmed by check_path_syntax ( ) .
2007-08-31 01:46:42 +04:00
The function will return an NTSTATUS error if some part of the name except for
the last part cannot be resolved , else NT_STATUS_OK .
2007-01-13 02:47:16 +03:00
s3: Change unix_convert (and its callers) to use struct smb_filename
This is the first of a series of patches that change path based
operations to operate on a struct smb_filename instead of a char *.
This same concept already exists in source4.
My goals for this series of patches are to eventually:
1) Solve the stream vs. posix filename that contains a colon ambiguity
that currently exists.
2) Make unix_convert the only function that parses the stream name.
3) Clean up the unix_convert API.
4) Change all path based vfs operation to take a struct smb_filename.
5) Make is_ntfs_stream_name() a constant operation that can simply
check the state of struct smb_filename rather than re-parse the
filename.
6) Eliminate the need for split_ntfs_stream_name() to exist.
My strategy is to start from the inside at unix_convert() and work my
way out through the vfs layer, call by call. This first patch does
just that, by changing unix_convert and all of its callers to operate
on struct smb_filename. Since this is such a large change, I plan on
pushing the patches in phases, where each phase keeps full
compatibility and passes make test.
The API of unix_convert has been simplified from:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
bool allow_wcard_last_component,
char **pp_conv_path,
char **pp_saved_last_component,
SMB_STRUCT_STAT *pst)
to:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
struct smb_filename *smb_fname,
uint32_t ucf_flags)
Currently the smb_filename struct looks like:
struct smb_filename {
char *base_name;
char *stream_name;
char *original_lcomp;
SMB_STRUCT_STAT st;
};
One key point here is the decision to break up the base_name and
stream_name. I have introduced a helper function called
get_full_smb_filename() that takes an smb_filename struct and
allocates the full_name. I changed the callers of unix_convert() to
subsequently call get_full_smb_filename() for the time being, but I
plan to eventually eliminate get_full_smb_filename().
2009-04-08 00:39:57 +04:00
Note NT_STATUS_OK doesn ' t mean the name exists or is valid , just that we
didn ' t get any fatal errors that should immediately terminate the calling SMB
processing whilst resolving .
1998-08-17 11:40:06 +04:00
2020-09-29 06:10:32 +03:00
If UCF_ALWAYS_ALLOW_WCARD_LCOMP is passed in , then a MS wildcard
should be allowed in the last component of the path only .
2000-10-19 06:58:24 +04:00
s3: Change unix_convert (and its callers) to use struct smb_filename
This is the first of a series of patches that change path based
operations to operate on a struct smb_filename instead of a char *.
This same concept already exists in source4.
My goals for this series of patches are to eventually:
1) Solve the stream vs. posix filename that contains a colon ambiguity
that currently exists.
2) Make unix_convert the only function that parses the stream name.
3) Clean up the unix_convert API.
4) Change all path based vfs operation to take a struct smb_filename.
5) Make is_ntfs_stream_name() a constant operation that can simply
check the state of struct smb_filename rather than re-parse the
filename.
6) Eliminate the need for split_ntfs_stream_name() to exist.
My strategy is to start from the inside at unix_convert() and work my
way out through the vfs layer, call by call. This first patch does
just that, by changing unix_convert and all of its callers to operate
on struct smb_filename. Since this is such a large change, I plan on
pushing the patches in phases, where each phase keeps full
compatibility and passes make test.
The API of unix_convert has been simplified from:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
bool allow_wcard_last_component,
char **pp_conv_path,
char **pp_saved_last_component,
SMB_STRUCT_STAT *pst)
to:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
struct smb_filename *smb_fname,
uint32_t ucf_flags)
Currently the smb_filename struct looks like:
struct smb_filename {
char *base_name;
char *stream_name;
char *original_lcomp;
SMB_STRUCT_STAT st;
};
One key point here is the decision to break up the base_name and
stream_name. I have introduced a helper function called
get_full_smb_filename() that takes an smb_filename struct and
allocates the full_name. I changed the callers of unix_convert() to
subsequently call get_full_smb_filename() for the time being, but I
plan to eventually eliminate get_full_smb_filename().
2009-04-08 00:39:57 +04:00
If the orig_path was a stream , smb_filename - > base_name will point to the base
filename , and smb_filename - > stream_name will point to the stream name . If
orig_path was not a stream , then smb_filename - > stream_name will be NULL .
On exit from unix_convert , the smb_filename - > st stat struct will be populated
if the file exists and was found , if not this stat struct will be filled with
zeros ( and this can be detected by checking for nlinks = 0 , which can never be
true for any file ) .
1998-08-17 11:40:06 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2020-04-23 11:06:56 +03:00
struct uc_state {
TALLOC_CTX * mem_ctx ;
struct connection_struct * conn ;
struct smb_filename * smb_fname ;
const char * orig_path ;
uint32_t ucf_flags ;
char * name ;
char * end ;
char * dirpath ;
char * stream ;
bool component_was_mangled ;
bool name_has_wildcard ;
bool posix_pathnames ;
bool allow_wcard_last_component ;
bool done ;
} ;
2020-04-23 13:35:12 +03:00
static NTSTATUS unix_convert_step_search_fail ( struct uc_state * state )
{
char * unmangled ;
if ( state - > end ) {
/*
* An intermediate part of the name
* can ' t be found .
*/
DBG_DEBUG ( " Intermediate [%s] missing \n " ,
state - > name ) ;
* state - > end = ' / ' ;
/*
* We need to return the fact that the
* intermediate name resolution failed .
* This is used to return an error of
* ERRbadpath rather than ERRbadfile .
* Some Windows applications depend on
* the difference between these two
* errors .
*/
/*
* ENOENT , ENOTDIR and ELOOP all map
* to NT_STATUS_OBJECT_PATH_NOT_FOUND
* in the filename walk .
*/
if ( errno = = ENOENT | |
errno = = ENOTDIR | |
errno = = ELOOP )
{
return NT_STATUS_OBJECT_PATH_NOT_FOUND ;
}
return map_nt_error_from_unix ( errno ) ;
}
/*
* ENOENT / EACCESS are the only valid errors
* here .
*/
if ( errno = = EACCES ) {
if ( ( state - > ucf_flags & UCF_PREP_CREATEFILE ) = = 0 ) {
return NT_STATUS_ACCESS_DENIED ;
} else {
/*
* This is the dropbox
* behaviour . A dropbox is a
* directory with only - wx
* permissions , so
* get_real_filename fails
* with EACCESS , it needs to
* list the directory . We
* nevertheless want to allow
* users creating a file .
*/
errno = 0 ;
}
}
if ( ( errno ! = 0 ) & & ( errno ! = ENOENT ) ) {
/*
* ENOTDIR and ELOOP both map to
* NT_STATUS_OBJECT_PATH_NOT_FOUND
* in the filename walk .
*/
if ( errno = = ENOTDIR | | errno = = ELOOP ) {
return NT_STATUS_OBJECT_PATH_NOT_FOUND ;
}
return map_nt_error_from_unix ( errno ) ;
}
/*
* Just the last part of the name doesn ' t exist .
* We need to strupper ( ) or strlower ( ) it as
* this conversion may be used for file creation
* purposes . Fix inspired by
* Thomas Neumann < t . neumann @ iku - ag . de > .
*/
if ( ! state - > conn - > case_preserve | |
( mangle_is_8_3 ( state - > name , false ,
state - > conn - > params ) & &
! state - > conn - > short_case_preserve ) ) {
if ( ! strnorm ( state - > name ,
lp_default_case ( SNUM ( state - > conn ) ) ) ) {
DBG_DEBUG ( " strnorm %s failed \n " ,
state - > name ) ;
return NT_STATUS_INVALID_PARAMETER ;
}
}
/*
* check on the mangled stack to see if we can
* recover the base of the filename .
*/
if ( mangle_is_mangled ( state - > name , state - > conn - > params )
& & mangle_lookup_name_from_8_3 ( state - > mem_ctx ,
state - > name ,
& unmangled ,
state - > conn - > params ) ) {
char * tmp ;
size_t name_ofs =
state - > name - state - > smb_fname - > base_name ;
if ( ! ISDOT ( state - > dirpath ) ) {
tmp = talloc_asprintf (
state - > smb_fname , " %s/%s " ,
state - > dirpath , unmangled ) ;
TALLOC_FREE ( unmangled ) ;
}
else {
tmp = unmangled ;
}
if ( tmp = = NULL ) {
DBG_ERR ( " talloc failed \n " ) ;
return NT_STATUS_NO_MEMORY ;
}
TALLOC_FREE ( state - > smb_fname - > base_name ) ;
state - > smb_fname - > base_name = tmp ;
state - > name =
state - > smb_fname - > base_name + name_ofs ;
state - > end = state - > name + strlen ( state - > name ) ;
}
DBG_DEBUG ( " New file [%s] \n " , state - > name ) ;
state - > done = true ;
return NT_STATUS_OK ;
}
2020-04-23 12:40:25 +03:00
static NTSTATUS unix_convert_step_stat ( struct uc_state * state )
2020-04-23 12:16:36 +03:00
{
2020-04-30 17:22:19 +03:00
struct smb_filename dname ;
char dot [ 2 ] = " . " ;
2020-04-23 12:46:19 +03:00
char * found_name = NULL ;
2020-04-23 12:16:36 +03:00
int ret ;
/*
* Check if the name exists up to this point .
*/
2020-04-23 17:09:28 +03:00
DBG_DEBUG ( " smb_fname [%s] \n " , smb_fname_str_dbg ( state - > smb_fname ) ) ;
2020-11-25 14:29:40 +03:00
ret = vfs_stat ( state - > conn , state - > smb_fname ) ;
2020-04-23 12:16:36 +03:00
if ( ret = = 0 ) {
/*
* It exists . it must either be a directory or this must
* be the last part of the path for it to be OK .
*/
if ( state - > end & & ! S_ISDIR ( state - > smb_fname - > st . st_ex_mode ) ) {
/*
* An intermediate part of the name isn ' t
* a directory .
*/
DBG_DEBUG ( " Not a dir [%s] \n " , state - > name ) ;
* state - > end = ' / ' ;
/*
* We need to return the fact that the
* intermediate name resolution failed . This
* is used to return an error of ERRbadpath
* rather than ERRbadfile . Some Windows
* applications depend on the difference between
* these two errors .
*/
2020-04-23 13:18:29 +03:00
return NT_STATUS_OBJECT_PATH_NOT_FOUND ;
2020-04-23 12:16:36 +03:00
}
2020-04-23 12:46:19 +03:00
return NT_STATUS_OK ;
}
2020-04-23 12:16:36 +03:00
2020-04-23 12:46:19 +03:00
/* Stat failed - ensure we don't use it. */
SET_STAT_INVALID ( state - > smb_fname - > st ) ;
2020-04-23 12:16:36 +03:00
2020-04-23 12:46:19 +03:00
if ( state - > posix_pathnames ) {
/*
* For posix_pathnames , we ' re done .
* Don ' t blunder into the name_has_wildcard OR
* get_real_filename ( ) codepaths as they may
* be doing case insensitive lookups . So when
* creating a new POSIX directory Foo they might
* match on name foo .
*
* BUG : https : //bugzilla.samba.org/show_bug.cgi?id=13803
*/
if ( state - > end ! = NULL ) {
const char * morepath = NULL ;
2020-04-23 12:16:36 +03:00
/*
2020-04-23 12:46:19 +03:00
* If this is intermediate we must
* restore the full path .
2020-04-23 12:16:36 +03:00
*/
2020-04-23 12:46:19 +03:00
* state - > end = ' / ' ;
/*
* If there are any more components
* after the failed LSTAT we cannot
* continue .
*/
morepath = strchr ( state - > end + 1 , ' / ' ) ;
if ( morepath ! = NULL ) {
return NT_STATUS_OBJECT_PATH_NOT_FOUND ;
2020-04-23 12:16:36 +03:00
}
}
2020-04-23 12:46:19 +03:00
if ( errno = = ENOENT ) {
/* New file or directory. */
state - > done = true ;
return NT_STATUS_OK ;
}
if ( ( errno = = EACCES ) & &
( state - > ucf_flags & UCF_PREP_CREATEFILE ) ) {
/* POSIX Dropbox case. */
errno = 0 ;
state - > done = true ;
return NT_STATUS_OK ;
}
return map_nt_error_from_unix ( errno ) ;
}
2020-04-23 12:16:36 +03:00
2020-04-23 12:46:19 +03:00
/*
* Reset errno so we can detect
* directory open errors .
*/
errno = 0 ;
2020-04-23 12:16:36 +03:00
2020-04-23 12:46:19 +03:00
/*
* Try to find this part of the path in the directory .
*/
2020-04-23 12:16:36 +03:00
2020-04-23 13:35:12 +03:00
if ( state - > name_has_wildcard ) {
return unix_convert_step_search_fail ( state ) ;
}
2020-04-30 17:22:19 +03:00
dname = ( struct smb_filename ) {
. base_name = state - > dirpath ,
. twrp = state - > smb_fname - > twrp ,
} ;
/* handle null paths */
if ( ( dname . base_name = = NULL ) | | ( dname . base_name [ 0 ] = = ' \0 ' ) ) {
dname . base_name = dot ;
}
2020-04-23 13:35:12 +03:00
ret = get_real_filename ( state - > conn ,
2020-04-30 17:22:19 +03:00
& dname ,
2020-04-23 13:35:12 +03:00
state - > name ,
talloc_tos ( ) ,
& found_name ) ;
if ( ret ! = 0 ) {
return unix_convert_step_search_fail ( state ) ;
2020-04-23 12:46:19 +03:00
}
2020-04-23 12:16:36 +03:00
2020-04-23 12:46:19 +03:00
/*
* Restore the rest of the string . If the string was
* mangled the size may have changed .
*/
if ( state - > end ) {
char * tmp ;
size_t name_ofs =
state - > name - state - > smb_fname - > base_name ;
if ( ! ISDOT ( state - > dirpath ) ) {
tmp = talloc_asprintf ( state - > smb_fname ,
" %s/%s/%s " , state - > dirpath ,
found_name , state - > end + 1 ) ;
}
else {
tmp = talloc_asprintf ( state - > smb_fname ,
" %s/%s " , found_name ,
state - > end + 1 ) ;
2020-04-23 12:16:36 +03:00
}
2020-04-23 12:46:19 +03:00
if ( tmp = = NULL ) {
DBG_ERR ( " talloc_asprintf failed \n " ) ;
return NT_STATUS_NO_MEMORY ;
}
TALLOC_FREE ( state - > smb_fname - > base_name ) ;
state - > smb_fname - > base_name = tmp ;
state - > name = state - > smb_fname - > base_name + name_ofs ;
state - > end = state - > name + strlen ( found_name ) ;
* state - > end = ' \0 ' ;
} else {
char * tmp ;
size_t name_ofs =
state - > name - state - > smb_fname - > base_name ;
if ( ! ISDOT ( state - > dirpath ) ) {
tmp = talloc_asprintf ( state - > smb_fname ,
" %s/%s " , state - > dirpath ,
found_name ) ;
} else {
tmp = talloc_strdup ( state - > smb_fname ,
found_name ) ;
}
if ( tmp = = NULL ) {
DBG_ERR ( " talloc failed \n " ) ;
return NT_STATUS_NO_MEMORY ;
}
TALLOC_FREE ( state - > smb_fname - > base_name ) ;
state - > smb_fname - > base_name = tmp ;
state - > name = state - > smb_fname - > base_name + name_ofs ;
/*
* We just scanned for , and found the end of
* the path . We must return a valid stat struct
* if it exists . JRA .
*/
2020-04-23 12:16:36 +03:00
2020-11-25 14:29:40 +03:00
ret = vfs_stat ( state - > conn , state - > smb_fname ) ;
2020-04-23 12:46:19 +03:00
if ( ret ! = 0 ) {
SET_STAT_INVALID ( state - > smb_fname - > st ) ;
}
}
2020-04-23 12:16:36 +03:00
2020-04-23 12:46:19 +03:00
TALLOC_FREE ( found_name ) ;
2020-04-23 12:40:25 +03:00
return NT_STATUS_OK ;
}
static NTSTATUS unix_convert_step ( struct uc_state * state )
{
NTSTATUS status ;
/*
* Pinpoint the end of this section of the filename .
*/
/* mb safe. '/' can't be in any encoded char. */
state - > end = strchr ( state - > name , ' / ' ) ;
/*
* Chop the name at this point .
*/
2020-04-24 23:55:49 +03:00
if ( state - > end ! = NULL ) {
2020-04-23 12:40:25 +03:00
* state - > end = 0 ;
}
2020-04-23 17:09:28 +03:00
DBG_DEBUG ( " dirpath [%s] name [%s] \n " , state - > dirpath , state - > name ) ;
2020-04-23 12:40:25 +03:00
/* The name cannot have a component of "." */
if ( ISDOT ( state - > name ) ) {
2020-04-24 23:55:49 +03:00
if ( state - > end = = NULL ) {
2020-04-23 12:40:25 +03:00
/* Error code at the end of a pathname. */
return NT_STATUS_OBJECT_NAME_INVALID ;
}
return determine_path_error ( state - > end + 1 ,
state - > allow_wcard_last_component ,
state - > posix_pathnames ) ;
}
/* The name cannot have a wildcard if it's not
the last component . */
if ( ! state - > posix_pathnames ) {
state - > name_has_wildcard = ms_has_wild ( state - > name ) ;
}
/* Wildcards never valid within a pathname. */
2020-04-24 23:55:49 +03:00
if ( state - > name_has_wildcard & & state - > end ! = NULL ) {
2020-04-23 12:40:25 +03:00
return NT_STATUS_OBJECT_NAME_INVALID ;
}
/* Skip the stat call if it's a wildcard end. */
if ( state - > name_has_wildcard ) {
DBG_DEBUG ( " Wildcard [%s] \n " , state - > name ) ;
state - > done = true ;
return NT_STATUS_OK ;
}
status = unix_convert_step_stat ( state ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2020-04-28 09:04:41 +03:00
if ( state - > done ) {
return NT_STATUS_OK ;
}
2020-04-23 12:40:25 +03:00
2020-04-23 12:16:36 +03:00
/*
* Add to the dirpath that we have resolved so far .
*/
if ( ! ISDOT ( state - > dirpath ) ) {
char * tmp = talloc_asprintf ( state - > mem_ctx ,
" %s/%s " , state - > dirpath , state - > name ) ;
if ( ! tmp ) {
DBG_ERR ( " talloc_asprintf failed \n " ) ;
2020-04-23 13:18:29 +03:00
return NT_STATUS_NO_MEMORY ;
2020-04-23 12:16:36 +03:00
}
TALLOC_FREE ( state - > dirpath ) ;
state - > dirpath = tmp ;
}
else {
TALLOC_FREE ( state - > dirpath ) ;
if ( ! ( state - > dirpath = talloc_strdup ( state - > mem_ctx , state - > name ) ) ) {
DBG_ERR ( " talloc_strdup failed \n " ) ;
2020-04-23 13:18:29 +03:00
return NT_STATUS_NO_MEMORY ;
2020-04-23 12:16:36 +03:00
}
}
/*
* Cache the dirpath thus far . Don ' t cache a name with mangled
* or wildcard components as this can change the size .
*/
if ( ! state - > component_was_mangled & & ! state - > name_has_wildcard ) {
2020-05-05 14:00:00 +03:00
stat_cache_add ( state - > orig_path ,
state - > dirpath ,
2020-04-30 16:24:44 +03:00
state - > smb_fname - > twrp ,
2020-04-23 12:16:36 +03:00
state - > conn - > case_sensitive ) ;
}
/*
* Restore the / that we wiped out earlier .
*/
2020-04-24 23:55:49 +03:00
if ( state - > end ! = NULL ) {
2020-04-23 12:16:36 +03:00
* state - > end = ' / ' ;
}
return NT_STATUS_OK ;
}
2020-04-23 10:39:22 +03:00
NTSTATUS unix_convert ( TALLOC_CTX * mem_ctx ,
s3: Change unix_convert (and its callers) to use struct smb_filename
This is the first of a series of patches that change path based
operations to operate on a struct smb_filename instead of a char *.
This same concept already exists in source4.
My goals for this series of patches are to eventually:
1) Solve the stream vs. posix filename that contains a colon ambiguity
that currently exists.
2) Make unix_convert the only function that parses the stream name.
3) Clean up the unix_convert API.
4) Change all path based vfs operation to take a struct smb_filename.
5) Make is_ntfs_stream_name() a constant operation that can simply
check the state of struct smb_filename rather than re-parse the
filename.
6) Eliminate the need for split_ntfs_stream_name() to exist.
My strategy is to start from the inside at unix_convert() and work my
way out through the vfs layer, call by call. This first patch does
just that, by changing unix_convert and all of its callers to operate
on struct smb_filename. Since this is such a large change, I plan on
pushing the patches in phases, where each phase keeps full
compatibility and passes make test.
The API of unix_convert has been simplified from:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
bool allow_wcard_last_component,
char **pp_conv_path,
char **pp_saved_last_component,
SMB_STRUCT_STAT *pst)
to:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
struct smb_filename *smb_fname,
uint32_t ucf_flags)
Currently the smb_filename struct looks like:
struct smb_filename {
char *base_name;
char *stream_name;
char *original_lcomp;
SMB_STRUCT_STAT st;
};
One key point here is the decision to break up the base_name and
stream_name. I have introduced a helper function called
get_full_smb_filename() that takes an smb_filename struct and
allocates the full_name. I changed the callers of unix_convert() to
subsequently call get_full_smb_filename() for the time being, but I
plan to eventually eliminate get_full_smb_filename().
2009-04-08 00:39:57 +04:00
connection_struct * conn ,
const char * orig_path ,
2020-04-30 17:04:54 +03:00
NTTIME twrp ,
s3: Change unix_convert (and its callers) to use struct smb_filename
This is the first of a series of patches that change path based
operations to operate on a struct smb_filename instead of a char *.
This same concept already exists in source4.
My goals for this series of patches are to eventually:
1) Solve the stream vs. posix filename that contains a colon ambiguity
that currently exists.
2) Make unix_convert the only function that parses the stream name.
3) Clean up the unix_convert API.
4) Change all path based vfs operation to take a struct smb_filename.
5) Make is_ntfs_stream_name() a constant operation that can simply
check the state of struct smb_filename rather than re-parse the
filename.
6) Eliminate the need for split_ntfs_stream_name() to exist.
My strategy is to start from the inside at unix_convert() and work my
way out through the vfs layer, call by call. This first patch does
just that, by changing unix_convert and all of its callers to operate
on struct smb_filename. Since this is such a large change, I plan on
pushing the patches in phases, where each phase keeps full
compatibility and passes make test.
The API of unix_convert has been simplified from:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
bool allow_wcard_last_component,
char **pp_conv_path,
char **pp_saved_last_component,
SMB_STRUCT_STAT *pst)
to:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
struct smb_filename *smb_fname,
uint32_t ucf_flags)
Currently the smb_filename struct looks like:
struct smb_filename {
char *base_name;
char *stream_name;
char *original_lcomp;
SMB_STRUCT_STAT st;
};
One key point here is the decision to break up the base_name and
stream_name. I have introduced a helper function called
get_full_smb_filename() that takes an smb_filename struct and
allocates the full_name. I changed the callers of unix_convert() to
subsequently call get_full_smb_filename() for the time being, but I
plan to eventually eliminate get_full_smb_filename().
2009-04-08 00:39:57 +04:00
struct smb_filename * * smb_fname_out ,
uint32_t ucf_flags )
1998-08-17 11:40:06 +04:00
{
2020-04-23 11:06:56 +03:00
struct uc_state uc_state ;
struct uc_state * state = & uc_state ;
2009-07-22 20:52:09 +04:00
NTSTATUS status ;
2009-02-05 03:33:52 +03:00
int ret = - 1 ;
2002-07-15 14:35:28 +04:00
2020-04-23 11:06:56 +03:00
* state = ( struct uc_state ) {
. mem_ctx = mem_ctx ,
. conn = conn ,
. orig_path = orig_path ,
. ucf_flags = ucf_flags ,
. posix_pathnames = ( ucf_flags & UCF_POSIX_PATHNAMES ) ,
. allow_wcard_last_component = ( ucf_flags & UCF_ALWAYS_ALLOW_WCARD_LCOMP ) ,
} ;
s3: Change unix_convert (and its callers) to use struct smb_filename
This is the first of a series of patches that change path based
operations to operate on a struct smb_filename instead of a char *.
This same concept already exists in source4.
My goals for this series of patches are to eventually:
1) Solve the stream vs. posix filename that contains a colon ambiguity
that currently exists.
2) Make unix_convert the only function that parses the stream name.
3) Clean up the unix_convert API.
4) Change all path based vfs operation to take a struct smb_filename.
5) Make is_ntfs_stream_name() a constant operation that can simply
check the state of struct smb_filename rather than re-parse the
filename.
6) Eliminate the need for split_ntfs_stream_name() to exist.
My strategy is to start from the inside at unix_convert() and work my
way out through the vfs layer, call by call. This first patch does
just that, by changing unix_convert and all of its callers to operate
on struct smb_filename. Since this is such a large change, I plan on
pushing the patches in phases, where each phase keeps full
compatibility and passes make test.
The API of unix_convert has been simplified from:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
bool allow_wcard_last_component,
char **pp_conv_path,
char **pp_saved_last_component,
SMB_STRUCT_STAT *pst)
to:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
struct smb_filename *smb_fname,
uint32_t ucf_flags)
Currently the smb_filename struct looks like:
struct smb_filename {
char *base_name;
char *stream_name;
char *original_lcomp;
SMB_STRUCT_STAT st;
};
One key point here is the decision to break up the base_name and
stream_name. I have introduced a helper function called
get_full_smb_filename() that takes an smb_filename struct and
allocates the full_name. I changed the callers of unix_convert() to
subsequently call get_full_smb_filename() for the time being, but I
plan to eventually eliminate get_full_smb_filename().
2009-04-08 00:39:57 +04:00
* smb_fname_out = NULL ;
2020-04-23 11:06:56 +03:00
state - > smb_fname = talloc_zero ( state - > mem_ctx , struct smb_filename ) ;
if ( state - > smb_fname = = NULL ) {
s3: Change unix_convert (and its callers) to use struct smb_filename
This is the first of a series of patches that change path based
operations to operate on a struct smb_filename instead of a char *.
This same concept already exists in source4.
My goals for this series of patches are to eventually:
1) Solve the stream vs. posix filename that contains a colon ambiguity
that currently exists.
2) Make unix_convert the only function that parses the stream name.
3) Clean up the unix_convert API.
4) Change all path based vfs operation to take a struct smb_filename.
5) Make is_ntfs_stream_name() a constant operation that can simply
check the state of struct smb_filename rather than re-parse the
filename.
6) Eliminate the need for split_ntfs_stream_name() to exist.
My strategy is to start from the inside at unix_convert() and work my
way out through the vfs layer, call by call. This first patch does
just that, by changing unix_convert and all of its callers to operate
on struct smb_filename. Since this is such a large change, I plan on
pushing the patches in phases, where each phase keeps full
compatibility and passes make test.
The API of unix_convert has been simplified from:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
bool allow_wcard_last_component,
char **pp_conv_path,
char **pp_saved_last_component,
SMB_STRUCT_STAT *pst)
to:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
struct smb_filename *smb_fname,
uint32_t ucf_flags)
Currently the smb_filename struct looks like:
struct smb_filename {
char *base_name;
char *stream_name;
char *original_lcomp;
SMB_STRUCT_STAT st;
};
One key point here is the decision to break up the base_name and
stream_name. I have introduced a helper function called
get_full_smb_filename() that takes an smb_filename struct and
allocates the full_name. I changed the callers of unix_convert() to
subsequently call get_full_smb_filename() for the time being, but I
plan to eventually eliminate get_full_smb_filename().
2009-04-08 00:39:57 +04:00
return NT_STATUS_NO_MEMORY ;
2007-01-13 02:47:16 +03:00
}
2002-07-15 14:35:28 +04:00
2020-04-23 11:06:56 +03:00
if ( state - > conn - > printer ) {
2002-07-15 14:35:28 +04:00
/* we don't ever use the filenames on a printer share as a
filename - so don ' t convert them */
2020-06-15 13:16:36 +03:00
state - > smb_fname - > base_name = talloc_strdup (
state - > smb_fname , state - > orig_path ) ;
if ( state - > smb_fname - > base_name = = NULL ) {
2009-07-22 20:52:09 +04:00
status = NT_STATUS_NO_MEMORY ;
goto err ;
2007-09-08 00:57:01 +04:00
}
2009-07-22 20:52:09 +04:00
goto done ;
2002-07-15 14:35:28 +04:00
}
2020-04-23 11:06:56 +03:00
state - > smb_fname - > flags = state - > posix_pathnames ? SMB_FILENAME_POSIX_PATH : 0 ;
2016-03-18 02:20:17 +03:00
2020-04-23 11:06:56 +03:00
DBG_DEBUG ( " Called on file [%s] \n " , state - > orig_path ) ;
2002-07-15 14:35:28 +04:00
2020-04-23 11:06:56 +03:00
if ( state - > orig_path [ 0 ] = = ' / ' ) {
DBG_ERR ( " Path [%s] starts with '/' \n " , state - > orig_path ) ;
2020-03-25 09:56:37 +03:00
return NT_STATUS_OBJECT_NAME_INVALID ;
}
2002-07-15 14:35:28 +04:00
2020-05-05 05:29:17 +03:00
/* Start with the full orig_path as given by the caller. */
2020-06-15 13:16:36 +03:00
state - > smb_fname - > base_name = talloc_strdup (
state - > smb_fname , state - > orig_path ) ;
if ( state - > smb_fname - > base_name = = NULL ) {
2020-05-05 05:29:17 +03:00
DBG_ERR ( " talloc_strdup failed \n " ) ;
status = NT_STATUS_NO_MEMORY ;
goto err ;
}
/* Canonicalize any @GMT- paths. */
status = canonicalize_snapshot_path ( state - > smb_fname , ucf_flags , twrp ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto err ;
}
2002-07-15 14:35:28 +04:00
/*
* If we trimmed down to a single ' \0 ' character
* then we should use the " . " directory to avoid
* searching the cache , but not if we are in a
* printing share .
2004-03-03 23:55:59 +03:00
* As we know this is valid we can return true here .
2002-07-15 14:35:28 +04:00
*/
2020-05-05 05:29:17 +03:00
if ( state - > smb_fname - > base_name [ 0 ] = = ' \0 ' ) {
2020-06-15 13:16:36 +03:00
state - > smb_fname - > base_name = talloc_strdup ( state - > smb_fname , " . " ) ;
if ( state - > smb_fname - > base_name = = NULL ) {
2009-07-22 20:52:09 +04:00
status = NT_STATUS_NO_MEMORY ;
goto err ;
2007-07-12 02:39:11 +04:00
}
2020-04-23 11:06:56 +03:00
if ( SMB_VFS_STAT ( state - > conn , state - > smb_fname ) ! = 0 ) {
2009-07-22 20:52:09 +04:00
status = map_nt_error_from_unix ( errno ) ;
goto err ;
2004-05-14 05:22:17 +04:00
}
2020-03-25 21:00:32 +03:00
DBG_DEBUG ( " conversion finished [] -> [%s] \n " ,
2020-04-23 11:06:56 +03:00
state - > smb_fname - > base_name ) ;
2007-07-12 02:39:11 +04:00
goto done ;
2007-01-13 02:47:16 +03:00
}
2020-04-23 11:06:56 +03:00
if ( state - > orig_path [ 0 ] = = ' . ' & & ( state - > orig_path [ 1 ] = = ' / ' | |
state - > orig_path [ 1 ] = = ' \0 ' ) ) {
2007-01-13 02:47:16 +03:00
/* Start of pathname can't be "." only. */
2020-04-23 11:06:56 +03:00
if ( state - > orig_path [ 1 ] = = ' \0 ' | | state - > orig_path [ 2 ] = = ' \0 ' ) {
2009-07-22 20:52:09 +04:00
status = NT_STATUS_OBJECT_NAME_INVALID ;
2007-01-13 04:07:39 +03:00
} else {
2020-04-23 11:06:56 +03:00
status = determine_path_error ( & state - > orig_path [ 2 ] ,
state - > allow_wcard_last_component ,
state - > posix_pathnames ) ;
2007-01-13 04:07:39 +03:00
}
2009-07-22 20:52:09 +04:00
goto err ;
2002-07-15 14:35:28 +04:00
}
2008-11-18 21:57:54 +03:00
/*
* Large directory fix normalization . If we ' re case sensitive , and
* the case preserving parameters are set to " no " , normalize the case of
* the incoming filename from the client WHETHER IT EXISTS OR NOT !
* This is in conflict with the current ( 3.0 .20 ) man page , but is
* what people expect from the " large directory howto " . I ' ll update
* the man page . Thanks to jht @ samba . org for finding this . JRA .
*/
2020-04-23 11:06:56 +03:00
status = normalize_filename_case ( state - > conn , state - > smb_fname - > base_name ) ;
2020-03-26 22:35:26 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " normalize_filename_case %s failed \n " ,
2020-04-23 11:06:56 +03:00
state - > smb_fname - > base_name ) ;
2020-03-26 22:35:26 +03:00
goto err ;
2008-11-18 21:57:54 +03:00
}
2009-07-22 20:52:09 +04:00
/*
* Strip off the stream , and add it back when we ' re done with the
* base_name .
*/
2020-04-23 11:06:56 +03:00
if ( ! state - > posix_pathnames ) {
state - > stream = strchr_m ( state - > smb_fname - > base_name , ' : ' ) ;
2008-01-20 08:53:49 +03:00
2020-04-23 11:06:56 +03:00
if ( state - > stream ! = NULL ) {
char * tmp = talloc_strdup ( state - > smb_fname , state - > stream ) ;
2008-01-20 08:53:49 +03:00
if ( tmp = = NULL ) {
2009-07-22 20:52:09 +04:00
status = NT_STATUS_NO_MEMORY ;
goto err ;
2008-01-20 08:53:49 +03:00
}
2009-07-22 20:52:09 +04:00
/*
* Since this is actually pointing into
* smb_fname - > base_name this truncates base_name .
*/
2020-04-23 11:06:56 +03:00
* state - > stream = ' \0 ' ;
state - > stream = tmp ;
2015-09-16 22:03:34 +03:00
2020-04-23 11:06:56 +03:00
if ( state - > smb_fname - > base_name [ 0 ] = = ' \0 ' ) {
2015-09-16 22:03:34 +03:00
/*
* orig_name was just a stream name .
* This is a stream on the root of
* the share . Replace base_name with
* a " . "
*/
2020-04-23 11:06:56 +03:00
state - > smb_fname - > base_name =
talloc_strdup ( state - > smb_fname , " . " ) ;
if ( state - > smb_fname - > base_name = = NULL ) {
2015-09-16 22:03:34 +03:00
status = NT_STATUS_NO_MEMORY ;
goto err ;
}
2020-04-23 11:06:56 +03:00
if ( SMB_VFS_STAT ( state - > conn , state - > smb_fname ) ! = 0 ) {
2015-09-16 22:03:34 +03:00
status = map_nt_error_from_unix ( errno ) ;
goto err ;
}
2015-10-01 03:12:11 +03:00
/* dirpath must exist. */
2020-04-23 11:06:56 +03:00
state - > dirpath = talloc_strdup ( state - > mem_ctx , " . " ) ;
if ( state - > dirpath = = NULL ) {
2015-10-01 03:12:11 +03:00
status = NT_STATUS_NO_MEMORY ;
goto err ;
}
2020-03-25 21:00:32 +03:00
DBG_INFO ( " conversion finished [%s] -> [%s] \n " ,
2020-04-23 11:06:56 +03:00
state - > orig_path ,
state - > smb_fname - > base_name ) ;
2015-09-16 22:03:34 +03:00
goto done ;
}
2008-01-20 01:25:36 +03:00
}
}
2020-04-23 11:06:56 +03:00
state - > name = state - > smb_fname - > base_name ;
2002-07-15 14:35:28 +04:00
2009-07-22 20:52:09 +04:00
/*
2010-12-06 16:05:49 +03:00
* If we ' re providing case insensitive semantics or
2007-12-23 04:38:18 +03:00
* the underlying filesystem is case insensitive ,
* then a case - normalized hit in the stat - cache is
2020-06-13 16:32:31 +03:00
* authoritative . JRA .
2009-07-22 20:52:09 +04:00
*
* Note : We ' re only checking base_name . The stream_name will be
* added and verified in build_stream_path ( ) .
2007-12-23 04:38:18 +03:00
*/
2020-05-05 12:13:47 +03:00
if ( ! state - > conn - > case_sensitive | |
! ( state - > conn - > fs_capabilities & FILE_CASE_SENSITIVE_SEARCH ) )
{
bool found ;
found = stat_cache_lookup ( state - > conn ,
state - > posix_pathnames ,
& state - > smb_fname - > base_name ,
& state - > dirpath ,
& state - > name ,
2020-04-30 16:24:44 +03:00
state - > smb_fname - > twrp ,
2020-05-05 12:13:47 +03:00
& state - > smb_fname - > st ) ;
if ( found ) {
goto done ;
}
2007-07-12 02:39:11 +04:00
}
/*
* Make sure " dirpath " is an allocated string , we use this for
2010-12-06 16:05:49 +03:00
* building the directories with talloc_asprintf and free it .
2007-07-12 02:39:11 +04:00
*/
2020-06-15 13:16:36 +03:00
if ( state - > dirpath = = NULL ) {
state - > dirpath = talloc_strdup ( state - > mem_ctx , " . " ) ;
if ( state - > dirpath = = NULL ) {
DBG_ERR ( " talloc_strdup failed \n " ) ;
status = NT_STATUS_NO_MEMORY ;
goto err ;
}
2002-07-15 14:35:28 +04:00
}
2007-07-12 02:39:11 +04:00
/*
2009-11-26 00:17:56 +03:00
* If we have a wildcard we must walk the path to
* find where the error is , even if case sensitive
* is true .
2002-07-15 14:35:28 +04:00
*/
2020-04-23 11:06:56 +03:00
if ( ! state - > posix_pathnames ) {
2015-12-12 01:41:38 +03:00
/* POSIX pathnames have no wildcards. */
2020-04-23 11:06:56 +03:00
state - > name_has_wildcard = ms_has_wild ( state - > smb_fname - > base_name ) ;
if ( state - > name_has_wildcard & & ! state - > allow_wcard_last_component ) {
2015-12-12 01:41:38 +03:00
/* Wildcard not valid anywhere. */
status = NT_STATUS_OBJECT_NAME_INVALID ;
goto fail ;
}
2009-02-05 03:33:52 +03:00
}
2020-04-23 10:32:53 +03:00
DBG_DEBUG ( " Begin: name [%s] dirpath [%s] name [%s] \n " ,
2020-04-23 11:06:56 +03:00
state - > smb_fname - > base_name , state - > dirpath , state - > name ) ;
2009-11-26 00:17:56 +03:00
2020-04-23 11:06:56 +03:00
if ( ! state - > name_has_wildcard ) {
2009-11-26 00:17:56 +03:00
/*
* stat the name - if it exists then we can add the stream back ( if
* there was one ) and be done !
*/
2020-11-25 14:29:40 +03:00
ret = vfs_stat ( state - > conn , state - > smb_fname ) ;
2009-11-26 00:17:56 +03:00
if ( ret = = 0 ) {
2020-04-23 11:06:56 +03:00
status = check_for_dot_component ( state - > smb_fname ) ;
2009-11-26 00:17:56 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2007-07-15 13:42:43 +04:00
goto fail ;
2007-01-13 02:47:16 +03:00
}
2009-11-26 00:17:56 +03:00
/* Add the path (not including the stream) to the cache. */
2020-05-05 14:00:00 +03:00
stat_cache_add ( state - > orig_path ,
state - > smb_fname - > base_name ,
2020-04-30 16:24:44 +03:00
state - > smb_fname - > twrp ,
2020-04-23 11:06:56 +03:00
state - > conn - > case_sensitive ) ;
2020-03-25 21:00:32 +03:00
DBG_DEBUG ( " Conversion of base_name finished "
" [%s] -> [%s] \n " ,
2020-04-23 11:06:56 +03:00
state - > orig_path , state - > smb_fname - > base_name ) ;
2009-11-26 00:17:56 +03:00
goto done ;
2007-01-13 02:47:16 +03:00
}
2002-07-15 14:35:28 +04:00
2011-04-04 21:22:03 +04:00
/* Stat failed - ensure we don't use it. */
2020-04-23 11:06:56 +03:00
SET_STAT_INVALID ( state - > smb_fname - > st ) ;
2011-04-04 21:22:03 +04:00
2020-04-23 11:48:51 +03:00
/*
* Note : we must continue processing a path if we get EACCES
* from stat . With NFS4 permissions the file might be lacking
* READ_ATTR , but if the parent has LIST permissions we can
* resolve the path in the path traversal loop down below .
*/
2020-04-22 16:13:04 +03:00
2010-09-11 10:28:15 +04:00
if ( errno = = ENOENT ) {
/* Optimization when creating a new file - only
2013-04-30 02:21:00 +04:00
the last component doesn ' t exist .
NOTE : check_parent_exists ( ) doesn ' t preserve errno .
*/
int saved_errno = errno ;
2020-04-23 11:06:56 +03:00
status = check_parent_exists ( state - > mem_ctx ,
state - > conn ,
state - > posix_pathnames ,
state - > smb_fname ,
& state - > dirpath ,
2021-05-11 21:31:55 +03:00
& state - > name ,
NULL ) ;
2013-04-30 02:21:00 +04:00
errno = saved_errno ;
2010-09-11 10:28:15 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
}
2009-11-26 00:17:56 +03:00
/*
* A special case - if we don ' t have any wildcards or mangling chars and are case
2010-12-06 16:05:49 +03:00
* sensitive or the underlying filesystem is case insensitive then searching
2009-11-26 00:17:56 +03:00
* won ' t help .
*/
2002-07-15 14:35:28 +04:00
2020-04-23 11:06:56 +03:00
if ( ( state - > conn - > case_sensitive | | ! ( state - > conn - > fs_capabilities &
2009-11-26 00:17:56 +03:00
FILE_CASE_SENSITIVE_SEARCH ) ) & &
2020-04-23 11:06:56 +03:00
! mangle_is_mangled ( state - > smb_fname - > base_name , state - > conn - > params ) ) {
2002-07-15 14:35:28 +04:00
2020-04-23 11:06:56 +03:00
status = check_for_dot_component ( state - > smb_fname ) ;
2009-11-26 00:17:56 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
/*
* The stat failed . Could be ok as it could be
* a new file .
*/
if ( errno = = ENOTDIR | | errno = = ELOOP ) {
status = NT_STATUS_OBJECT_PATH_NOT_FOUND ;
goto fail ;
} else if ( errno = = ENOENT ) {
/*
* Was it a missing last component ?
* or a missing intermediate component ?
*/
2020-04-28 17:00:42 +03:00
struct smb_filename * parent_fname = NULL ;
struct smb_filename * base_fname = NULL ;
bool ok ;
ok = parent_smb_fname ( state - > mem_ctx ,
state - > smb_fname ,
& parent_fname ,
& base_fname ) ;
if ( ! ok ) {
2009-11-26 00:17:56 +03:00
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
2020-11-25 14:29:40 +03:00
ret = vfs_stat ( state - > conn , parent_fname ) ;
2020-04-28 17:00:42 +03:00
TALLOC_FREE ( parent_fname ) ;
2009-11-26 00:17:56 +03:00
if ( ret = = - 1 ) {
if ( errno = = ENOTDIR | |
errno = = ENOENT | |
errno = = ELOOP ) {
status = NT_STATUS_OBJECT_PATH_NOT_FOUND ;
goto fail ;
}
}
2010-09-09 03:55:24 +04:00
2009-11-26 00:17:56 +03:00
/*
* Missing last component is ok - new file .
* Also deal with permission denied elsewhere .
* Just drop out to done .
*/
goto done ;
}
}
2010-09-09 03:55:24 +04:00
} else {
/*
* We have a wildcard in the pathname .
*
* Optimization for common case where the wildcard
* is in the last component and the client already
* sent the correct case .
2013-04-30 02:21:00 +04:00
* NOTE : check_parent_exists ( ) doesn ' t preserve errno .
2010-09-09 03:55:24 +04:00
*/
2013-04-30 02:21:00 +04:00
int saved_errno = errno ;
2020-04-23 11:06:56 +03:00
status = check_parent_exists ( state - > mem_ctx ,
state - > conn ,
state - > posix_pathnames ,
state - > smb_fname ,
& state - > dirpath ,
2021-05-11 21:31:55 +03:00
& state - > name ,
NULL ) ;
2013-04-30 02:21:00 +04:00
errno = saved_errno ;
2010-09-11 10:28:15 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-09-09 03:55:24 +04:00
goto fail ;
}
2007-01-13 02:47:16 +03:00
}
2002-07-15 14:35:28 +04:00
2007-07-12 02:39:11 +04:00
/*
* is_mangled ( ) was changed to look at an entire pathname , not
2002-07-15 14:35:28 +04:00
* just a component . JRA .
*/
2020-04-23 11:06:56 +03:00
if ( mangle_is_mangled ( state - > name , state - > conn - > params ) ) {
state - > component_was_mangled = true ;
2007-01-13 02:47:16 +03:00
}
2002-07-15 14:35:28 +04:00
2007-07-12 02:39:11 +04:00
/*
* Now we need to recursively match the name against the real
2002-07-15 14:35:28 +04:00
* directory structure .
*/
2007-07-12 02:39:11 +04:00
/*
2002-07-15 14:35:28 +04:00
* Match each part of the path name separately , trying the names
* as is first , then trying to scan the directory for matching names .
*/
2020-04-23 11:06:56 +03:00
for ( ; state - > name ; state - > name = ( state - > end ? state - > end + 1 : ( char * ) NULL ) ) {
2020-04-23 12:16:36 +03:00
status = unix_convert_step ( state ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NO_MEMORY ) ) {
goto err ;
2007-01-13 02:47:16 +03:00
}
2007-07-12 02:39:11 +04:00
goto fail ;
2007-01-13 02:47:16 +03:00
}
2020-04-23 12:16:36 +03:00
if ( state - > done ) {
2010-09-09 03:55:24 +04:00
goto done ;
}
2002-07-15 14:35:28 +04:00
}
2007-07-12 02:39:11 +04:00
2002-07-15 14:35:28 +04:00
/*
2009-07-22 20:52:09 +04:00
* Cache the full path . Don ' t cache a name with mangled or wildcard
* components as this can change the size .
2002-07-15 14:35:28 +04:00
*/
2000-12-12 03:11:34 +03:00
2020-04-23 11:06:56 +03:00
if ( ! state - > component_was_mangled & & ! state - > name_has_wildcard ) {
2020-05-05 14:00:00 +03:00
stat_cache_add ( state - > orig_path ,
state - > smb_fname - > base_name ,
2020-04-30 16:24:44 +03:00
state - > smb_fname - > twrp ,
2020-04-23 11:06:56 +03:00
state - > conn - > case_sensitive ) ;
2007-01-13 02:47:16 +03:00
}
2000-12-12 03:11:34 +03:00
2007-07-12 02:39:11 +04:00
/*
2002-07-15 14:35:28 +04:00
* The name has been resolved .
*/
1998-08-28 00:38:53 +04:00
2007-07-12 02:39:11 +04:00
done :
2009-07-22 20:52:09 +04:00
/* Add back the stream if one was stripped off originally. */
2020-04-23 11:06:56 +03:00
if ( state - > stream ! = NULL ) {
state - > smb_fname - > stream_name = state - > stream ;
2008-01-20 01:25:36 +03:00
s3: Change unix_convert (and its callers) to use struct smb_filename
This is the first of a series of patches that change path based
operations to operate on a struct smb_filename instead of a char *.
This same concept already exists in source4.
My goals for this series of patches are to eventually:
1) Solve the stream vs. posix filename that contains a colon ambiguity
that currently exists.
2) Make unix_convert the only function that parses the stream name.
3) Clean up the unix_convert API.
4) Change all path based vfs operation to take a struct smb_filename.
5) Make is_ntfs_stream_name() a constant operation that can simply
check the state of struct smb_filename rather than re-parse the
filename.
6) Eliminate the need for split_ntfs_stream_name() to exist.
My strategy is to start from the inside at unix_convert() and work my
way out through the vfs layer, call by call. This first patch does
just that, by changing unix_convert and all of its callers to operate
on struct smb_filename. Since this is such a large change, I plan on
pushing the patches in phases, where each phase keeps full
compatibility and passes make test.
The API of unix_convert has been simplified from:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
bool allow_wcard_last_component,
char **pp_conv_path,
char **pp_saved_last_component,
SMB_STRUCT_STAT *pst)
to:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
struct smb_filename *smb_fname,
uint32_t ucf_flags)
Currently the smb_filename struct looks like:
struct smb_filename {
char *base_name;
char *stream_name;
char *original_lcomp;
SMB_STRUCT_STAT st;
};
One key point here is the decision to break up the base_name and
stream_name. I have introduced a helper function called
get_full_smb_filename() that takes an smb_filename struct and
allocates the full_name. I changed the callers of unix_convert() to
subsequently call get_full_smb_filename() for the time being, but I
plan to eventually eliminate get_full_smb_filename().
2009-04-08 00:39:57 +04:00
/* Check path now that the base_name has been converted. */
2020-04-23 11:06:56 +03:00
status = build_stream_path ( state - > mem_ctx , state - > conn , state - > smb_fname ) ;
2009-07-22 20:52:09 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-01-20 01:25:36 +03:00
goto fail ;
}
}
2020-05-02 09:09:24 +03:00
DBG_DEBUG ( " Conversion finished [%s] -> [%s] \n " ,
state - > orig_path , smb_fname_str_dbg ( state - > smb_fname ) ) ;
2020-04-23 11:06:56 +03:00
TALLOC_FREE ( state - > dirpath ) ;
* smb_fname_out = state - > smb_fname ;
2007-08-20 00:00:43 +04:00
return NT_STATUS_OK ;
2007-08-16 19:44:13 +04:00
fail :
2020-04-23 10:32:53 +03:00
DBG_DEBUG ( " Conversion failed: dirpath [%s] name [%s] \n " ,
2020-04-23 11:06:56 +03:00
state - > dirpath , state - > name ) ;
2020-06-15 13:16:36 +03:00
if ( ( state - > dirpath ! = NULL ) & & ! ISDOT ( state - > dirpath ) ) {
state - > smb_fname - > base_name = talloc_asprintf (
state - > smb_fname ,
" %s/%s " ,
state - > dirpath ,
state - > name ) ;
2007-09-08 00:57:01 +04:00
} else {
2020-06-15 13:16:36 +03:00
state - > smb_fname - > base_name = talloc_strdup (
state - > smb_fname , state - > name ) ;
2007-09-08 00:57:01 +04:00
}
2020-06-15 13:16:36 +03:00
if ( state - > smb_fname - > base_name = = NULL ) {
2020-03-25 21:00:32 +03:00
DBG_ERR ( " talloc_asprintf failed \n " ) ;
2009-07-22 20:52:09 +04:00
status = NT_STATUS_NO_MEMORY ;
goto err ;
2007-09-08 00:57:01 +04:00
}
s3: Change unix_convert (and its callers) to use struct smb_filename
This is the first of a series of patches that change path based
operations to operate on a struct smb_filename instead of a char *.
This same concept already exists in source4.
My goals for this series of patches are to eventually:
1) Solve the stream vs. posix filename that contains a colon ambiguity
that currently exists.
2) Make unix_convert the only function that parses the stream name.
3) Clean up the unix_convert API.
4) Change all path based vfs operation to take a struct smb_filename.
5) Make is_ntfs_stream_name() a constant operation that can simply
check the state of struct smb_filename rather than re-parse the
filename.
6) Eliminate the need for split_ntfs_stream_name() to exist.
My strategy is to start from the inside at unix_convert() and work my
way out through the vfs layer, call by call. This first patch does
just that, by changing unix_convert and all of its callers to operate
on struct smb_filename. Since this is such a large change, I plan on
pushing the patches in phases, where each phase keeps full
compatibility and passes make test.
The API of unix_convert has been simplified from:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
bool allow_wcard_last_component,
char **pp_conv_path,
char **pp_saved_last_component,
SMB_STRUCT_STAT *pst)
to:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
struct smb_filename *smb_fname,
uint32_t ucf_flags)
Currently the smb_filename struct looks like:
struct smb_filename {
char *base_name;
char *stream_name;
char *original_lcomp;
SMB_STRUCT_STAT st;
};
One key point here is the decision to break up the base_name and
stream_name. I have introduced a helper function called
get_full_smb_filename() that takes an smb_filename struct and
allocates the full_name. I changed the callers of unix_convert() to
subsequently call get_full_smb_filename() for the time being, but I
plan to eventually eliminate get_full_smb_filename().
2009-04-08 00:39:57 +04:00
2020-04-23 11:06:56 +03:00
* smb_fname_out = state - > smb_fname ;
TALLOC_FREE ( state - > dirpath ) ;
2009-07-22 20:52:09 +04:00
return status ;
err :
2020-04-23 11:06:56 +03:00
TALLOC_FREE ( state - > smb_fname ) ;
2009-07-22 20:52:09 +04:00
return status ;
1998-08-17 11:40:06 +04:00
}
/****************************************************************************
2015-02-09 17:42:23 +03:00
Ensure a path is not vetoed .
1998-08-17 11:40:06 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-07-15 14:35:28 +04:00
2017-06-30 21:59:20 +03:00
static NTSTATUS check_veto_path ( connection_struct * conn ,
const struct smb_filename * smb_fname )
1998-08-17 11:40:06 +04:00
{
2017-06-30 21:59:20 +03:00
const char * name = smb_fname - > base_name ;
2009-11-23 18:33:53 +03:00
if ( IS_VETO_PATH ( conn , name ) ) {
2004-03-06 01:32:45 +03:00
/* Is it not dot or dot dot. */
2011-07-26 03:12:45 +04:00
if ( ! ( ISDOT ( name ) | | ISDOTDOT ( name ) ) ) {
2011-10-22 01:12:41 +04:00
DEBUG ( 5 , ( " check_veto_path: file path name %s vetoed \n " ,
2007-08-31 01:46:42 +04:00
name ) ) ;
2007-01-17 05:09:37 +03:00
return map_nt_error_from_unix ( ENOENT ) ;
2002-07-15 14:35:28 +04:00
}
}
2011-10-22 01:12:41 +04:00
return NT_STATUS_OK ;
}
/****************************************************************************
Check a filename - possibly calling check_reduced_name .
This is called by every routine before it allows an operation on a filename .
It does any final confirmation necessary to ensure that the filename is
a valid one for the user to access .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2017-06-30 21:59:20 +03:00
NTSTATUS check_name ( connection_struct * conn ,
const struct smb_filename * smb_fname )
2011-10-22 01:12:41 +04:00
{
2017-06-30 21:59:20 +03:00
NTSTATUS status = check_veto_path ( conn , smb_fname ) ;
2011-10-22 01:12:41 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
1998-08-17 11:40:06 +04:00
2014-02-04 06:09:03 +04:00
if ( ! lp_widelinks ( SNUM ( conn ) ) | | ! lp_follow_symlinks ( SNUM ( conn ) ) ) {
2017-06-30 21:59:20 +03:00
status = check_reduced_name ( conn , NULL , smb_fname ) ;
2007-01-17 05:09:37 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2017-06-30 21:59:20 +03:00
DEBUG ( 5 , ( " check_name: name %s failed with %s \n " ,
smb_fname - > base_name ,
nt_errstr ( status ) ) ) ;
2007-01-17 05:09:37 +03:00
return status ;
}
2004-06-11 21:54:23 +04:00
}
1998-08-17 11:40:06 +04:00
2007-01-17 05:09:37 +03:00
return NT_STATUS_OK ;
1998-08-17 11:40:06 +04:00
}
2012-02-25 02:12:05 +04:00
/****************************************************************************
2012-03-01 05:04:08 +04:00
Must be called as root . Creates the struct privilege_paths
2012-02-25 02:12:05 +04:00
attached to the struct smb_request if this call is successful .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS check_name_with_privilege ( connection_struct * conn ,
struct smb_request * smbreq ,
2017-06-30 21:59:20 +03:00
const struct smb_filename * smb_fname )
2012-02-25 02:12:05 +04:00
{
2017-06-30 21:59:20 +03:00
NTSTATUS status = check_veto_path ( conn , smb_fname ) ;
2012-02-25 02:12:05 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
return check_reduced_name_with_privilege ( conn ,
2017-06-30 21:59:20 +03:00
smb_fname ,
2012-03-01 05:04:08 +04:00
smbreq ) ;
2012-02-25 02:12:05 +04:00
}
2007-07-12 02:39:11 +04:00
/****************************************************************************
Check if two filenames are equal .
This needs to be careful about whether we are case sensitive .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
static bool fname_equal ( const char * name1 , const char * name2 ,
bool case_sensitive )
2007-07-12 02:39:11 +04:00
{
/* Normal filename handling */
2007-09-08 00:57:01 +04:00
if ( case_sensitive ) {
2007-07-12 02:39:11 +04:00
return ( strcmp ( name1 , name2 ) = = 0 ) ;
2007-09-08 00:57:01 +04:00
}
2007-07-12 02:39:11 +04:00
return ( strequal ( name1 , name2 ) ) ;
}
2019-04-25 18:30:43 +03:00
static bool sname_equal ( const char * name1 , const char * name2 ,
bool case_sensitive )
{
bool match ;
const char * s1 = NULL ;
const char * s2 = NULL ;
size_t n1 ;
size_t n2 ;
const char * e1 = NULL ;
const char * e2 = NULL ;
char * c1 = NULL ;
char * c2 = NULL ;
match = fname_equal ( name1 , name2 , case_sensitive ) ;
if ( match ) {
return true ;
}
if ( name1 [ 0 ] ! = ' : ' ) {
return false ;
}
if ( name2 [ 0 ] ! = ' : ' ) {
return false ;
}
s1 = & name1 [ 1 ] ;
e1 = strchr ( s1 , ' : ' ) ;
if ( e1 = = NULL ) {
n1 = strlen ( s1 ) ;
} else {
n1 = PTR_DIFF ( e1 , s1 ) ;
}
s2 = & name2 [ 1 ] ;
e2 = strchr ( s2 , ' : ' ) ;
if ( e2 = = NULL ) {
n2 = strlen ( s2 ) ;
} else {
n2 = PTR_DIFF ( e2 , s2 ) ;
}
/* Normal filename handling */
if ( case_sensitive ) {
return ( strncmp ( s1 , s2 , n1 ) = = 0 ) ;
}
/*
* We can ' t use strnequal ( ) here
* as it takes the number of codepoints
* and not the number of bytes .
*
* So we make a copy before calling
* strequal ( ) .
*
* Note that we TALLOC_FREE ( ) in reverse order
* in order to avoid memory fragmentation .
*/
c1 = talloc_strndup ( talloc_tos ( ) , s1 , n1 ) ;
c2 = talloc_strndup ( talloc_tos ( ) , s2 , n2 ) ;
if ( c1 = = NULL | | c2 = = NULL ) {
TALLOC_FREE ( c2 ) ;
TALLOC_FREE ( c1 ) ;
return ( strncmp ( s1 , s2 , n1 ) = = 0 ) ;
}
match = strequal ( c1 , c2 ) ;
TALLOC_FREE ( c2 ) ;
TALLOC_FREE ( c1 ) ;
return match ;
}
1998-08-17 11:40:06 +04:00
/****************************************************************************
2002-07-15 14:35:28 +04:00
Scan a directory to find a filename , matching without case sensitivity .
If the name looks like a mangled name then try via the mangling functions
1998-08-17 11:40:06 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-07-15 14:35:28 +04:00
2020-04-23 17:09:16 +03:00
int get_real_filename_full_scan ( connection_struct * conn ,
const char * path ,
const char * name ,
bool mangled ,
TALLOC_CTX * mem_ctx ,
char * * found_name )
1998-08-17 11:40:06 +04:00
{
2009-04-23 16:54:52 +04:00
struct smb_Dir * cur_dir ;
2009-11-16 11:49:23 +03:00
const char * dname = NULL ;
char * talloced = NULL ;
2007-07-12 02:39:11 +04:00
char * unmangled_name = NULL ;
2009-04-23 16:54:52 +04:00
long curpos ;
2016-02-27 02:55:14 +03:00
struct smb_filename * smb_fname = NULL ;
2002-07-15 14:35:28 +04:00
/* handle null paths */
2007-09-08 00:57:01 +04:00
if ( ( path = = NULL ) | | ( * path = = 0 ) ) {
2002-07-15 14:35:28 +04:00
path = " . " ;
2007-09-08 00:57:01 +04:00
}
2002-07-15 14:35:28 +04:00
2007-12-23 01:55:37 +03:00
/* If we have a case-sensitive filesystem, it doesn't do us any
* good to search for a name . If a case variation of the name was
* there , then the original stat ( 2 ) would have found it .
*/
if ( ! mangled & & ! ( conn - > fs_capabilities & FILE_CASE_SENSITIVE_SEARCH ) ) {
errno = ENOENT ;
2008-12-10 05:03:51 +03:00
return - 1 ;
2007-12-23 01:55:37 +03:00
}
2002-07-15 14:35:28 +04:00
/*
* The incoming name can be mangled , and if we de - mangle it
* here it will not compare correctly against the filename ( name2 )
2007-09-08 00:57:01 +04:00
* read from the directory and then mangled by the name_to_8_3 ( )
2002-07-15 14:35:28 +04:00
* call . We need to mangle both names or neither .
* ( JRA ) .
2005-10-28 05:42:03 +04:00
*
* Fix for bug found by Dina Fine . If in case sensitive mode then
* the mangle cache is no good ( 3 letter extension could be wrong
* case - so don ' t demangle in this case - leave as mangled and
* allow the mangling of the directory entry read ( which is done
* case insensitively ) to match instead . This will lead to more
* false positive matches but we fail completely without it . JRA .
2002-07-15 14:35:28 +04:00
*/
2005-10-28 05:42:03 +04:00
if ( mangled & & ! conn - > case_sensitive ) {
2008-12-09 15:40:41 +03:00
mangled = ! mangle_lookup_name_from_8_3 ( talloc_tos ( ) , name ,
& unmangled_name ,
conn - > params ) ;
2007-09-14 22:24:31 +04:00
if ( ! mangled ) {
/* Name is now unmangled. */
2007-09-08 00:57:01 +04:00
name = unmangled_name ;
}
2005-10-28 05:42:03 +04:00
}
2002-07-15 14:35:28 +04:00
2016-02-27 02:55:14 +03:00
smb_fname = synthetic_smb_fname ( talloc_tos ( ) ,
path ,
NULL ,
2016-03-19 07:19:38 +03:00
NULL ,
2020-04-30 12:48:32 +03:00
0 ,
2016-03-19 07:19:38 +03:00
0 ) ;
2016-02-27 02:55:14 +03:00
if ( smb_fname = = NULL ) {
TALLOC_FREE ( unmangled_name ) ;
return - 1 ;
}
2002-07-15 14:35:28 +04:00
/* open the directory */
2016-02-27 02:55:14 +03:00
if ( ! ( cur_dir = OpenDir ( talloc_tos ( ) , conn , smb_fname , NULL , 0 ) ) ) {
2002-07-15 14:35:28 +04:00
DEBUG ( 3 , ( " scan dir didn't open dir [%s] \n " , path ) ) ;
2007-09-08 00:57:01 +04:00
TALLOC_FREE ( unmangled_name ) ;
2016-02-27 02:55:14 +03:00
TALLOC_FREE ( smb_fname ) ;
2008-12-10 05:03:51 +03:00
return - 1 ;
2002-07-15 14:35:28 +04:00
}
2016-02-27 02:55:14 +03:00
TALLOC_FREE ( smb_fname ) ;
2002-07-15 14:35:28 +04:00
/* now scan for matching names */
2005-01-29 00:01:58 +03:00
curpos = 0 ;
2009-11-16 11:49:23 +03:00
while ( ( dname = ReadDirName ( cur_dir , & curpos , NULL , & talloced ) ) ) {
2004-03-06 01:32:45 +03:00
/* Is it dot or dot dot. */
2007-09-08 00:57:01 +04:00
if ( ISDOT ( dname ) | | ISDOTDOT ( dname ) ) {
2009-11-16 11:49:23 +03:00
TALLOC_FREE ( talloced ) ;
2002-07-15 14:35:28 +04:00
continue ;
2004-03-06 01:32:45 +03:00
}
2002-07-15 14:35:28 +04:00
/*
* At this point dname is the unmangled name .
2007-08-31 01:46:42 +04:00
* name is either mangled or not , depending on the state
* of the " mangled " variable . JRA .
2002-07-15 14:35:28 +04:00
*/
/*
* Check mangled name against mangled name , or unmangled name
* against unmangled name .
*/
2007-08-31 01:46:42 +04:00
if ( ( mangled & & mangled_equal ( name , dname , conn - > params ) ) | |
fname_equal ( name , dname , conn - > case_sensitive ) ) {
2002-07-15 14:35:28 +04:00
/* we've found the file, change it's name and return */
2008-12-09 15:40:41 +03:00
* found_name = talloc_strdup ( mem_ctx , dname ) ;
2007-09-08 00:57:01 +04:00
TALLOC_FREE ( unmangled_name ) ;
2008-01-12 19:08:04 +03:00
TALLOC_FREE ( cur_dir ) ;
2007-09-08 00:57:01 +04:00
if ( ! * found_name ) {
errno = ENOMEM ;
2009-11-16 11:49:23 +03:00
TALLOC_FREE ( talloced ) ;
2008-12-10 05:03:51 +03:00
return - 1 ;
2007-09-08 00:57:01 +04:00
}
2009-11-16 11:49:23 +03:00
TALLOC_FREE ( talloced ) ;
2008-12-10 05:03:51 +03:00
return 0 ;
2002-07-15 14:35:28 +04:00
}
2009-11-16 11:49:23 +03:00
TALLOC_FREE ( talloced ) ;
2002-07-15 14:35:28 +04:00
}
2007-09-08 00:57:01 +04:00
TALLOC_FREE ( unmangled_name ) ;
2008-01-12 19:08:04 +03:00
TALLOC_FREE ( cur_dir ) ;
2004-06-11 21:54:23 +04:00
errno = ENOENT ;
2008-12-10 05:03:51 +03:00
return - 1 ;
1998-08-17 11:40:06 +04:00
}
2008-01-20 01:25:36 +03:00
2009-05-02 04:28:38 +04:00
/****************************************************************************
Wrapper around the vfs get_real_filename and the full directory scan
fallback .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-04-30 18:20:49 +03:00
int get_real_filename ( connection_struct * conn ,
2020-04-30 17:22:19 +03:00
struct smb_filename * path ,
2020-04-30 18:20:49 +03:00
const char * name ,
TALLOC_CTX * mem_ctx ,
2009-05-02 04:28:38 +04:00
char * * found_name )
{
int ret ;
2009-05-09 13:12:52 +04:00
bool mangled ;
mangled = mangle_is_mangled ( name , conn - > params ) ;
if ( mangled ) {
2020-04-30 18:20:49 +03:00
return get_real_filename_full_scan ( conn ,
2020-04-30 17:22:19 +03:00
path - > base_name ,
2020-04-30 18:20:49 +03:00
name ,
mangled ,
mem_ctx ,
found_name ) ;
2009-05-09 13:12:52 +04:00
}
2009-05-02 04:28:38 +04:00
/* Try the vfs first to take advantage of case-insensitive stat. */
2020-04-30 18:20:49 +03:00
ret = SMB_VFS_GET_REAL_FILENAME ( conn ,
2020-04-30 17:40:28 +03:00
path ,
2020-04-30 18:20:49 +03:00
name ,
mem_ctx ,
found_name ) ;
2009-05-02 04:28:38 +04:00
/*
* If the case - insensitive stat was successful , or returned an error
* other than EOPNOTSUPP then there is no need to fall back on the
* full directory scan .
*/
if ( ret = = 0 | | ( ret = = - 1 & & errno ! = EOPNOTSUPP ) ) {
return ret ;
}
2020-04-30 18:20:49 +03:00
return get_real_filename_full_scan ( conn ,
2020-04-30 17:22:19 +03:00
path - > base_name ,
2020-04-30 18:20:49 +03:00
name ,
mangled ,
mem_ctx ,
2009-05-09 13:12:52 +04:00
found_name ) ;
2009-05-02 04:28:38 +04:00
}
2008-01-20 01:25:36 +03:00
static NTSTATUS build_stream_path ( TALLOC_CTX * mem_ctx ,
connection_struct * conn ,
s3: Change unix_convert (and its callers) to use struct smb_filename
This is the first of a series of patches that change path based
operations to operate on a struct smb_filename instead of a char *.
This same concept already exists in source4.
My goals for this series of patches are to eventually:
1) Solve the stream vs. posix filename that contains a colon ambiguity
that currently exists.
2) Make unix_convert the only function that parses the stream name.
3) Clean up the unix_convert API.
4) Change all path based vfs operation to take a struct smb_filename.
5) Make is_ntfs_stream_name() a constant operation that can simply
check the state of struct smb_filename rather than re-parse the
filename.
6) Eliminate the need for split_ntfs_stream_name() to exist.
My strategy is to start from the inside at unix_convert() and work my
way out through the vfs layer, call by call. This first patch does
just that, by changing unix_convert and all of its callers to operate
on struct smb_filename. Since this is such a large change, I plan on
pushing the patches in phases, where each phase keeps full
compatibility and passes make test.
The API of unix_convert has been simplified from:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
bool allow_wcard_last_component,
char **pp_conv_path,
char **pp_saved_last_component,
SMB_STRUCT_STAT *pst)
to:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
struct smb_filename *smb_fname,
uint32_t ucf_flags)
Currently the smb_filename struct looks like:
struct smb_filename {
char *base_name;
char *stream_name;
char *original_lcomp;
SMB_STRUCT_STAT st;
};
One key point here is the decision to break up the base_name and
stream_name. I have introduced a helper function called
get_full_smb_filename() that takes an smb_filename struct and
allocates the full_name. I changed the callers of unix_convert() to
subsequently call get_full_smb_filename() for the time being, but I
plan to eventually eliminate get_full_smb_filename().
2009-04-08 00:39:57 +04:00
struct smb_filename * smb_fname )
2008-01-20 01:25:36 +03:00
{
NTSTATUS status ;
2011-10-14 02:41:53 +04:00
unsigned int i , num_streams = 0 ;
2008-01-20 01:25:36 +03:00
struct stream_struct * streams = NULL ;
2021-02-08 13:42:22 +03:00
struct smb_filename * pathref = NULL ;
2008-01-20 01:25:36 +03:00
2009-06-23 02:26:56 +04:00
if ( SMB_VFS_STAT ( conn , smb_fname ) = = 0 ) {
2009-07-22 20:52:09 +04:00
DEBUG ( 10 , ( " '%s' exists \n " , smb_fname_str_dbg ( smb_fname ) ) ) ;
2008-01-20 01:25:36 +03:00
return NT_STATUS_OK ;
}
if ( errno ! = ENOENT ) {
2009-08-29 02:53:05 +04:00
DEBUG ( 10 , ( " vfs_stat failed: %s \n " , strerror ( errno ) ) ) ;
2008-01-20 01:25:36 +03:00
status = map_nt_error_from_unix ( errno ) ;
goto fail ;
}
2021-02-08 13:42:22 +03:00
if ( smb_fname - > fsp = = NULL ) {
status = synthetic_pathref ( mem_ctx ,
conn - > cwd_fsp ,
smb_fname - > base_name ,
NULL ,
NULL ,
smb_fname - > twrp ,
smb_fname - > flags ,
& pathref ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
if ( NT_STATUS_EQUAL ( status ,
NT_STATUS_OBJECT_NAME_NOT_FOUND ) ) {
TALLOC_FREE ( pathref ) ;
SET_STAT_INVALID ( smb_fname - > st ) ;
return NT_STATUS_OK ;
}
DBG_DEBUG ( " synthetic_pathref failed: %s \n " ,
nt_errstr ( status ) ) ;
goto fail ;
}
} else {
pathref = smb_fname ;
}
s3: Change unix_convert (and its callers) to use struct smb_filename
This is the first of a series of patches that change path based
operations to operate on a struct smb_filename instead of a char *.
This same concept already exists in source4.
My goals for this series of patches are to eventually:
1) Solve the stream vs. posix filename that contains a colon ambiguity
that currently exists.
2) Make unix_convert the only function that parses the stream name.
3) Clean up the unix_convert API.
4) Change all path based vfs operation to take a struct smb_filename.
5) Make is_ntfs_stream_name() a constant operation that can simply
check the state of struct smb_filename rather than re-parse the
filename.
6) Eliminate the need for split_ntfs_stream_name() to exist.
My strategy is to start from the inside at unix_convert() and work my
way out through the vfs layer, call by call. This first patch does
just that, by changing unix_convert and all of its callers to operate
on struct smb_filename. Since this is such a large change, I plan on
pushing the patches in phases, where each phase keeps full
compatibility and passes make test.
The API of unix_convert has been simplified from:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
bool allow_wcard_last_component,
char **pp_conv_path,
char **pp_saved_last_component,
SMB_STRUCT_STAT *pst)
to:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
struct smb_filename *smb_fname,
uint32_t ucf_flags)
Currently the smb_filename struct looks like:
struct smb_filename {
char *base_name;
char *stream_name;
char *original_lcomp;
SMB_STRUCT_STAT st;
};
One key point here is the decision to break up the base_name and
stream_name. I have introduced a helper function called
get_full_smb_filename() that takes an smb_filename struct and
allocates the full_name. I changed the callers of unix_convert() to
subsequently call get_full_smb_filename() for the time being, but I
plan to eventually eliminate get_full_smb_filename().
2009-04-08 00:39:57 +04:00
/* Fall back to a case-insensitive scan of all streams on the file. */
2021-04-28 17:10:07 +03:00
status = vfs_fstreaminfo ( pathref - > fsp , mem_ctx ,
2011-10-17 22:10:29 +04:00
& num_streams , & streams ) ;
2008-01-20 01:25:36 +03:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ) {
s3: Change unix_convert (and its callers) to use struct smb_filename
This is the first of a series of patches that change path based
operations to operate on a struct smb_filename instead of a char *.
This same concept already exists in source4.
My goals for this series of patches are to eventually:
1) Solve the stream vs. posix filename that contains a colon ambiguity
that currently exists.
2) Make unix_convert the only function that parses the stream name.
3) Clean up the unix_convert API.
4) Change all path based vfs operation to take a struct smb_filename.
5) Make is_ntfs_stream_name() a constant operation that can simply
check the state of struct smb_filename rather than re-parse the
filename.
6) Eliminate the need for split_ntfs_stream_name() to exist.
My strategy is to start from the inside at unix_convert() and work my
way out through the vfs layer, call by call. This first patch does
just that, by changing unix_convert and all of its callers to operate
on struct smb_filename. Since this is such a large change, I plan on
pushing the patches in phases, where each phase keeps full
compatibility and passes make test.
The API of unix_convert has been simplified from:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
bool allow_wcard_last_component,
char **pp_conv_path,
char **pp_saved_last_component,
SMB_STRUCT_STAT *pst)
to:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
struct smb_filename *smb_fname,
uint32_t ucf_flags)
Currently the smb_filename struct looks like:
struct smb_filename {
char *base_name;
char *stream_name;
char *original_lcomp;
SMB_STRUCT_STAT st;
};
One key point here is the decision to break up the base_name and
stream_name. I have introduced a helper function called
get_full_smb_filename() that takes an smb_filename struct and
allocates the full_name. I changed the callers of unix_convert() to
subsequently call get_full_smb_filename() for the time being, but I
plan to eventually eliminate get_full_smb_filename().
2009-04-08 00:39:57 +04:00
SET_STAT_INVALID ( smb_fname - > st ) ;
2021-02-08 13:42:22 +03:00
TALLOC_FREE ( pathref ) ;
2008-01-20 01:25:36 +03:00
return NT_STATUS_OK ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
2021-04-28 17:10:07 +03:00
DEBUG ( 10 , ( " vfs_fstreaminfo failed: %s \n " , nt_errstr ( status ) ) ) ;
2008-01-20 01:25:36 +03:00
goto fail ;
}
for ( i = 0 ; i < num_streams ; i + + ) {
DEBUG ( 10 , ( " comparing [%s] and [%s]: " ,
s3: Change unix_convert (and its callers) to use struct smb_filename
This is the first of a series of patches that change path based
operations to operate on a struct smb_filename instead of a char *.
This same concept already exists in source4.
My goals for this series of patches are to eventually:
1) Solve the stream vs. posix filename that contains a colon ambiguity
that currently exists.
2) Make unix_convert the only function that parses the stream name.
3) Clean up the unix_convert API.
4) Change all path based vfs operation to take a struct smb_filename.
5) Make is_ntfs_stream_name() a constant operation that can simply
check the state of struct smb_filename rather than re-parse the
filename.
6) Eliminate the need for split_ntfs_stream_name() to exist.
My strategy is to start from the inside at unix_convert() and work my
way out through the vfs layer, call by call. This first patch does
just that, by changing unix_convert and all of its callers to operate
on struct smb_filename. Since this is such a large change, I plan on
pushing the patches in phases, where each phase keeps full
compatibility and passes make test.
The API of unix_convert has been simplified from:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
bool allow_wcard_last_component,
char **pp_conv_path,
char **pp_saved_last_component,
SMB_STRUCT_STAT *pst)
to:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
struct smb_filename *smb_fname,
uint32_t ucf_flags)
Currently the smb_filename struct looks like:
struct smb_filename {
char *base_name;
char *stream_name;
char *original_lcomp;
SMB_STRUCT_STAT st;
};
One key point here is the decision to break up the base_name and
stream_name. I have introduced a helper function called
get_full_smb_filename() that takes an smb_filename struct and
allocates the full_name. I changed the callers of unix_convert() to
subsequently call get_full_smb_filename() for the time being, but I
plan to eventually eliminate get_full_smb_filename().
2009-04-08 00:39:57 +04:00
smb_fname - > stream_name , streams [ i ] . name ) ) ;
2019-04-25 18:30:43 +03:00
if ( sname_equal ( smb_fname - > stream_name , streams [ i ] . name ,
2008-01-20 01:25:36 +03:00
conn - > case_sensitive ) ) {
DEBUGADD ( 10 , ( " equal \n " ) ) ;
break ;
}
DEBUGADD ( 10 , ( " not equal \n " ) ) ;
}
s3: Change unix_convert (and its callers) to use struct smb_filename
This is the first of a series of patches that change path based
operations to operate on a struct smb_filename instead of a char *.
This same concept already exists in source4.
My goals for this series of patches are to eventually:
1) Solve the stream vs. posix filename that contains a colon ambiguity
that currently exists.
2) Make unix_convert the only function that parses the stream name.
3) Clean up the unix_convert API.
4) Change all path based vfs operation to take a struct smb_filename.
5) Make is_ntfs_stream_name() a constant operation that can simply
check the state of struct smb_filename rather than re-parse the
filename.
6) Eliminate the need for split_ntfs_stream_name() to exist.
My strategy is to start from the inside at unix_convert() and work my
way out through the vfs layer, call by call. This first patch does
just that, by changing unix_convert and all of its callers to operate
on struct smb_filename. Since this is such a large change, I plan on
pushing the patches in phases, where each phase keeps full
compatibility and passes make test.
The API of unix_convert has been simplified from:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
bool allow_wcard_last_component,
char **pp_conv_path,
char **pp_saved_last_component,
SMB_STRUCT_STAT *pst)
to:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
struct smb_filename *smb_fname,
uint32_t ucf_flags)
Currently the smb_filename struct looks like:
struct smb_filename {
char *base_name;
char *stream_name;
char *original_lcomp;
SMB_STRUCT_STAT st;
};
One key point here is the decision to break up the base_name and
stream_name. I have introduced a helper function called
get_full_smb_filename() that takes an smb_filename struct and
allocates the full_name. I changed the callers of unix_convert() to
subsequently call get_full_smb_filename() for the time being, but I
plan to eventually eliminate get_full_smb_filename().
2009-04-08 00:39:57 +04:00
/* Couldn't find the stream. */
2008-01-20 01:25:36 +03:00
if ( i = = num_streams ) {
s3: Change unix_convert (and its callers) to use struct smb_filename
This is the first of a series of patches that change path based
operations to operate on a struct smb_filename instead of a char *.
This same concept already exists in source4.
My goals for this series of patches are to eventually:
1) Solve the stream vs. posix filename that contains a colon ambiguity
that currently exists.
2) Make unix_convert the only function that parses the stream name.
3) Clean up the unix_convert API.
4) Change all path based vfs operation to take a struct smb_filename.
5) Make is_ntfs_stream_name() a constant operation that can simply
check the state of struct smb_filename rather than re-parse the
filename.
6) Eliminate the need for split_ntfs_stream_name() to exist.
My strategy is to start from the inside at unix_convert() and work my
way out through the vfs layer, call by call. This first patch does
just that, by changing unix_convert and all of its callers to operate
on struct smb_filename. Since this is such a large change, I plan on
pushing the patches in phases, where each phase keeps full
compatibility and passes make test.
The API of unix_convert has been simplified from:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
bool allow_wcard_last_component,
char **pp_conv_path,
char **pp_saved_last_component,
SMB_STRUCT_STAT *pst)
to:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
struct smb_filename *smb_fname,
uint32_t ucf_flags)
Currently the smb_filename struct looks like:
struct smb_filename {
char *base_name;
char *stream_name;
char *original_lcomp;
SMB_STRUCT_STAT st;
};
One key point here is the decision to break up the base_name and
stream_name. I have introduced a helper function called
get_full_smb_filename() that takes an smb_filename struct and
allocates the full_name. I changed the callers of unix_convert() to
subsequently call get_full_smb_filename() for the time being, but I
plan to eventually eliminate get_full_smb_filename().
2009-04-08 00:39:57 +04:00
SET_STAT_INVALID ( smb_fname - > st ) ;
2021-02-08 13:42:22 +03:00
TALLOC_FREE ( pathref ) ;
2008-01-20 01:25:36 +03:00
TALLOC_FREE ( streams ) ;
return NT_STATUS_OK ;
}
s3: Change unix_convert (and its callers) to use struct smb_filename
This is the first of a series of patches that change path based
operations to operate on a struct smb_filename instead of a char *.
This same concept already exists in source4.
My goals for this series of patches are to eventually:
1) Solve the stream vs. posix filename that contains a colon ambiguity
that currently exists.
2) Make unix_convert the only function that parses the stream name.
3) Clean up the unix_convert API.
4) Change all path based vfs operation to take a struct smb_filename.
5) Make is_ntfs_stream_name() a constant operation that can simply
check the state of struct smb_filename rather than re-parse the
filename.
6) Eliminate the need for split_ntfs_stream_name() to exist.
My strategy is to start from the inside at unix_convert() and work my
way out through the vfs layer, call by call. This first patch does
just that, by changing unix_convert and all of its callers to operate
on struct smb_filename. Since this is such a large change, I plan on
pushing the patches in phases, where each phase keeps full
compatibility and passes make test.
The API of unix_convert has been simplified from:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
bool allow_wcard_last_component,
char **pp_conv_path,
char **pp_saved_last_component,
SMB_STRUCT_STAT *pst)
to:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
struct smb_filename *smb_fname,
uint32_t ucf_flags)
Currently the smb_filename struct looks like:
struct smb_filename {
char *base_name;
char *stream_name;
char *original_lcomp;
SMB_STRUCT_STAT st;
};
One key point here is the decision to break up the base_name and
stream_name. I have introduced a helper function called
get_full_smb_filename() that takes an smb_filename struct and
allocates the full_name. I changed the callers of unix_convert() to
subsequently call get_full_smb_filename() for the time being, but I
plan to eventually eliminate get_full_smb_filename().
2009-04-08 00:39:57 +04:00
DEBUG ( 10 , ( " case insensitive stream. requested: %s, actual: %s \n " ,
smb_fname - > stream_name , streams [ i ] . name ) ) ;
2008-01-20 01:25:36 +03:00
s3: Change unix_convert (and its callers) to use struct smb_filename
This is the first of a series of patches that change path based
operations to operate on a struct smb_filename instead of a char *.
This same concept already exists in source4.
My goals for this series of patches are to eventually:
1) Solve the stream vs. posix filename that contains a colon ambiguity
that currently exists.
2) Make unix_convert the only function that parses the stream name.
3) Clean up the unix_convert API.
4) Change all path based vfs operation to take a struct smb_filename.
5) Make is_ntfs_stream_name() a constant operation that can simply
check the state of struct smb_filename rather than re-parse the
filename.
6) Eliminate the need for split_ntfs_stream_name() to exist.
My strategy is to start from the inside at unix_convert() and work my
way out through the vfs layer, call by call. This first patch does
just that, by changing unix_convert and all of its callers to operate
on struct smb_filename. Since this is such a large change, I plan on
pushing the patches in phases, where each phase keeps full
compatibility and passes make test.
The API of unix_convert has been simplified from:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
bool allow_wcard_last_component,
char **pp_conv_path,
char **pp_saved_last_component,
SMB_STRUCT_STAT *pst)
to:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
struct smb_filename *smb_fname,
uint32_t ucf_flags)
Currently the smb_filename struct looks like:
struct smb_filename {
char *base_name;
char *stream_name;
char *original_lcomp;
SMB_STRUCT_STAT st;
};
One key point here is the decision to break up the base_name and
stream_name. I have introduced a helper function called
get_full_smb_filename() that takes an smb_filename struct and
allocates the full_name. I changed the callers of unix_convert() to
subsequently call get_full_smb_filename() for the time being, but I
plan to eventually eliminate get_full_smb_filename().
2009-04-08 00:39:57 +04:00
TALLOC_FREE ( smb_fname - > stream_name ) ;
2009-07-22 20:52:09 +04:00
smb_fname - > stream_name = talloc_strdup ( smb_fname , streams [ i ] . name ) ;
if ( smb_fname - > stream_name = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
s3: Change unix_convert (and its callers) to use struct smb_filename
This is the first of a series of patches that change path based
operations to operate on a struct smb_filename instead of a char *.
This same concept already exists in source4.
My goals for this series of patches are to eventually:
1) Solve the stream vs. posix filename that contains a colon ambiguity
that currently exists.
2) Make unix_convert the only function that parses the stream name.
3) Clean up the unix_convert API.
4) Change all path based vfs operation to take a struct smb_filename.
5) Make is_ntfs_stream_name() a constant operation that can simply
check the state of struct smb_filename rather than re-parse the
filename.
6) Eliminate the need for split_ntfs_stream_name() to exist.
My strategy is to start from the inside at unix_convert() and work my
way out through the vfs layer, call by call. This first patch does
just that, by changing unix_convert and all of its callers to operate
on struct smb_filename. Since this is such a large change, I plan on
pushing the patches in phases, where each phase keeps full
compatibility and passes make test.
The API of unix_convert has been simplified from:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
bool allow_wcard_last_component,
char **pp_conv_path,
char **pp_saved_last_component,
SMB_STRUCT_STAT *pst)
to:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
struct smb_filename *smb_fname,
uint32_t ucf_flags)
Currently the smb_filename struct looks like:
struct smb_filename {
char *base_name;
char *stream_name;
char *original_lcomp;
SMB_STRUCT_STAT st;
};
One key point here is the decision to break up the base_name and
stream_name. I have introduced a helper function called
get_full_smb_filename() that takes an smb_filename struct and
allocates the full_name. I changed the callers of unix_convert() to
subsequently call get_full_smb_filename() for the time being, but I
plan to eventually eliminate get_full_smb_filename().
2009-04-08 00:39:57 +04:00
SET_STAT_INVALID ( smb_fname - > st ) ;
2008-01-20 01:25:36 +03:00
2009-06-23 02:26:56 +04:00
if ( SMB_VFS_STAT ( conn , smb_fname ) = = 0 ) {
2009-07-22 20:52:09 +04:00
DEBUG ( 10 , ( " '%s' exists \n " , smb_fname_str_dbg ( smb_fname ) ) ) ;
2009-06-23 02:26:56 +04:00
}
status = NT_STATUS_OK ;
2008-01-20 01:25:36 +03:00
fail :
2021-02-08 13:42:22 +03:00
TALLOC_FREE ( pathref ) ;
2008-01-20 01:25:36 +03:00
TALLOC_FREE ( streams ) ;
return status ;
}
2009-06-19 00:13:38 +04:00
2020-03-25 20:00:57 +03:00
/*
* Lightweight function to just get last component
* for rename / enumerate directory calls .
*/
char * get_original_lcomp ( TALLOC_CTX * ctx ,
connection_struct * conn ,
const char * filename_in ,
uint32_t ucf_flags )
{
struct smb_filename * smb_fname = NULL ;
char * last_slash = NULL ;
char * orig_lcomp ;
char * fname = NULL ;
NTSTATUS status ;
if ( ucf_flags & UCF_DFS_PATHNAME ) {
2020-09-30 00:24:10 +03:00
status = dfs_redirect ( ctx ,
2020-03-25 20:00:57 +03:00
conn ,
filename_in ,
ucf_flags ,
! conn - > sconn - > using_smb2 ,
2020-09-30 00:17:35 +03:00
& fname ) ;
2020-03-25 20:00:57 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2020-09-30 00:24:10 +03:00
DBG_DEBUG ( " dfs_redirect "
2020-03-25 20:00:57 +03:00
" failed for name %s with %s \n " ,
filename_in ,
nt_errstr ( status ) ) ;
return NULL ;
}
filename_in = fname ;
ucf_flags & = ~ UCF_DFS_PATHNAME ;
}
/*
* NB . We don ' t need to care about
* is_fake_file_path ( filename_in ) here as these
* code paths don ' t ever return original_lcomp
* or use it anyway .
*/
if ( ucf_flags & UCF_GMT_PATHNAME ) {
/*
* Ensure we don ' t return a @ GMT
* value as the last component .
*/
smb_fname = synthetic_smb_fname ( ctx ,
filename_in ,
NULL ,
NULL ,
2020-04-30 12:48:32 +03:00
0 ,
2020-03-25 20:00:57 +03:00
0 ) ;
if ( smb_fname = = NULL ) {
TALLOC_FREE ( fname ) ;
return NULL ;
}
2020-05-04 14:51:37 +03:00
status = canonicalize_snapshot_path ( smb_fname ,
ucf_flags ,
0 ) ;
2020-03-25 20:00:57 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( fname ) ;
TALLOC_FREE ( smb_fname ) ;
return NULL ;
}
filename_in = smb_fname - > base_name ;
}
last_slash = strrchr ( filename_in , ' / ' ) ;
if ( last_slash ! = NULL ) {
orig_lcomp = talloc_strdup ( ctx , last_slash + 1 ) ;
} else {
orig_lcomp = talloc_strdup ( ctx , filename_in ) ;
}
/* We're done with any temp names here. */
TALLOC_FREE ( smb_fname ) ;
TALLOC_FREE ( fname ) ;
if ( orig_lcomp = = NULL ) {
return NULL ;
}
status = normalize_filename_case ( conn , orig_lcomp ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( orig_lcomp ) ;
return NULL ;
}
return orig_lcomp ;
}
2009-07-24 23:13:07 +04:00
/**
* Go through all the steps to validate a filename .
*
* @ param ctx talloc_ctx to allocate memory with .
* @ param conn connection struct for vfs calls .
2012-04-24 16:07:00 +04:00
* @ param smbreq SMB request if we ' re using privileges .
2009-07-24 23:13:07 +04:00
* @ param name_in The unconverted name .
* @ param ucf_flags flags to pass through to unix_convert ( ) .
2018-11-24 11:05:37 +03:00
* @ param twrp Optional VSS time
2009-07-24 23:13:07 +04:00
* @ param p_cont_wcard If not NULL , will be set to true if the dfs path
* resolution detects a wildcard .
2020-03-31 19:57:55 +03:00
* @ param _smb_fname The final converted name will be allocated if the
2009-07-24 23:13:07 +04:00
* return is NT_STATUS_OK .
*
2018-05-04 23:24:00 +03:00
* @ return NT_STATUS_OK if all operations completed successfully , appropriate
2009-07-24 23:13:07 +04:00
* error otherwise .
*/
2012-02-25 02:12:05 +04:00
static NTSTATUS filename_convert_internal ( TALLOC_CTX * ctx ,
2009-06-19 00:13:38 +04:00
connection_struct * conn ,
2012-02-25 02:12:05 +04:00
struct smb_request * smbreq ,
2009-06-19 00:13:38 +04:00
const char * name_in ,
2009-07-24 23:13:07 +04:00
uint32_t ucf_flags ,
2020-04-30 17:04:54 +03:00
NTTIME twrp ,
2020-03-26 17:08:53 +03:00
struct smb_filename * * _smb_fname )
2009-06-19 00:13:38 +04:00
{
2020-03-26 17:08:53 +03:00
struct smb_filename * smb_fname = NULL ;
2020-06-13 20:16:39 +03:00
bool has_wild ;
2009-06-19 00:13:38 +04:00
NTSTATUS status ;
2020-03-26 17:08:53 +03:00
* _smb_fname = NULL ;
2009-06-19 00:13:38 +04:00
2017-05-18 22:29:50 +03:00
if ( ucf_flags & UCF_DFS_PATHNAME ) {
2017-05-18 21:36:56 +03:00
char * fname = NULL ;
2020-09-30 00:24:10 +03:00
status = dfs_redirect ( ctx , conn ,
2009-06-19 00:13:38 +04:00
name_in ,
2016-03-25 21:23:29 +03:00
ucf_flags ,
2012-05-23 15:22:47 +04:00
! conn - > sconn - > using_smb2 ,
2020-09-30 00:17:35 +03:00
& fname ) ;
2017-05-18 21:34:33 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2020-09-30 00:24:10 +03:00
DEBUG ( 10 , ( " filename_convert_internal: dfs_redirect "
2017-05-18 21:34:33 +03:00
" failed for name %s with %s \n " ,
name_in ,
nt_errstr ( status ) ) ) ;
return status ;
}
2017-05-18 21:36:56 +03:00
name_in = fname ;
2017-05-18 22:29:50 +03:00
ucf_flags & = ~ UCF_DFS_PATHNAME ;
2009-06-19 00:13:38 +04:00
}
2009-07-24 23:13:07 +04:00
2009-08-19 11:58:38 +04:00
if ( is_fake_file_path ( name_in ) ) {
2020-03-26 17:08:53 +03:00
smb_fname = synthetic_smb_fname_split ( ctx ,
2016-03-10 03:00:47 +03:00
name_in ,
( ucf_flags & UCF_POSIX_PATHNAMES ) ) ;
2020-03-26 17:08:53 +03:00
if ( smb_fname = = NULL ) {
2013-04-12 13:49:19 +04:00
return NT_STATUS_NO_MEMORY ;
}
2020-03-26 17:08:53 +03:00
smb_fname - > st = ( SMB_STRUCT_STAT ) { . st_ex_nlink = 1 } ;
* _smb_fname = smb_fname ;
2013-04-12 13:49:19 +04:00
return NT_STATUS_OK ;
2009-08-19 11:58:38 +04:00
}
2020-04-30 16:14:36 +03:00
status = unix_convert ( ctx , conn , name_in , twrp , & smb_fname , ucf_flags ) ;
2009-06-19 00:13:38 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2012-02-25 02:12:05 +04:00
DEBUG ( 10 , ( " filename_convert_internal: unix_convert failed "
2009-06-19 00:13:38 +04:00
" for name %s with %s \n " ,
2017-05-18 21:36:56 +03:00
name_in ,
2009-06-19 00:13:38 +04:00
nt_errstr ( status ) ) ) ;
return status ;
}
2020-10-22 12:04:59 +03:00
if ( ( ucf_flags & UCF_POSIX_PATHNAMES ) & &
VALID_STAT ( smb_fname - > st ) & &
S_ISLNK ( smb_fname - > st . st_ex_mode ) )
{
2020-03-26 17:08:53 +03:00
status = check_veto_path ( conn , smb_fname ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( smb_fname ) ;
return status ;
}
2020-11-23 08:40:16 +03:00
} else if ( ! smbreq ) {
2020-03-26 17:08:53 +03:00
status = check_name ( conn , smb_fname ) ;
2012-02-25 02:12:05 +04:00
} else {
2017-06-30 21:59:20 +03:00
status = check_name_with_privilege ( conn , smbreq ,
2020-03-26 17:08:53 +03:00
smb_fname ) ;
2012-02-25 02:12:05 +04:00
}
2009-06-19 00:13:38 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2012-02-25 02:12:05 +04:00
DEBUG ( 3 , ( " filename_convert_internal: check_name failed "
2009-06-19 00:13:38 +04:00
" for name %s with %s \n " ,
2020-03-26 17:08:53 +03:00
smb_fname_str_dbg ( smb_fname ) ,
2009-06-19 00:13:38 +04:00
nt_errstr ( status ) ) ) ;
2020-03-26 17:08:53 +03:00
TALLOC_FREE ( smb_fname ) ;
2009-06-19 00:13:38 +04:00
return status ;
}
2009-07-02 03:14:40 +04:00
2020-06-13 20:16:39 +03:00
has_wild = ms_has_wild ( name_in ) ;
if ( has_wild ) {
DBG_DEBUG ( " [%s] contains wildcard, skipping pathref fsp \n " ,
name_in ) ;
* _smb_fname = smb_fname ;
return NT_STATUS_OK ;
}
if ( ! VALID_STAT ( smb_fname - > st ) ) {
DBG_DEBUG ( " [%s] does not exist, skipping pathref fsp \n " ,
smb_fname_str_dbg ( smb_fname ) ) ;
* _smb_fname = smb_fname ;
return NT_STATUS_OK ;
}
status = openat_pathref_fsp ( conn - > cwd_fsp , smb_fname ) ;
2021-02-02 13:18:54 +03:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ) {
2020-06-13 20:16:39 +03:00
/*
2021-02-02 13:18:54 +03:00
* We deal with symlinks here as we do in
2020-06-13 20:16:39 +03:00
* SMB_VFS_CREATE_FILE ( ) : return success for POSIX clients with
* the notable difference that there will be no fsp in
* smb_fname - > fsp .
*
* For Windows ( non POSIX ) clients fail with
* NT_STATUS_OBJECT_NAME_NOT_FOUND .
*/
2021-02-02 13:18:54 +03:00
if ( smb_fname - > flags & SMB_FILENAME_POSIX_PATH & &
S_ISLNK ( smb_fname - > st . st_ex_mode ) )
{
2020-06-13 20:16:39 +03:00
status = NT_STATUS_OK ;
}
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
2021-04-06 15:47:39 +03:00
DBG_DEBUG ( " open_pathref_fsp [%s] failed: %s \n " ,
smb_fname_str_dbg ( smb_fname ) ,
nt_errstr ( status ) ) ;
2020-06-13 20:16:39 +03:00
return status ;
}
2020-03-26 17:08:53 +03:00
* _smb_fname = smb_fname ;
2009-06-19 00:13:38 +04:00
return status ;
}
2012-02-25 02:12:05 +04:00
/*
* Go through all the steps to validate a filename .
* Non - root version .
*/
NTSTATUS filename_convert ( TALLOC_CTX * ctx ,
connection_struct * conn ,
const char * name_in ,
uint32_t ucf_flags ,
2020-04-30 17:04:54 +03:00
NTTIME twrp ,
2012-02-25 02:12:05 +04:00
struct smb_filename * * pp_smb_fname )
{
return filename_convert_internal ( ctx ,
conn ,
NULL ,
name_in ,
ucf_flags ,
2018-11-24 12:45:49 +03:00
twrp ,
2012-02-25 02:12:05 +04:00
pp_smb_fname ) ;
}
/*
* Go through all the steps to validate a filename .
* root ( privileged ) version .
*/
NTSTATUS filename_convert_with_privilege ( TALLOC_CTX * ctx ,
connection_struct * conn ,
struct smb_request * smbreq ,
const char * name_in ,
uint32_t ucf_flags ,
struct smb_filename * * pp_smb_fname )
{
return filename_convert_internal ( ctx ,
conn ,
smbreq ,
name_in ,
ucf_flags ,
2020-04-30 17:04:54 +03:00
0 ,
2012-02-25 02:12:05 +04:00
pp_smb_fname ) ;
}
2020-04-14 18:44:37 +03:00
/*
* Build the full path from a dirfsp and dirfsp relative name
*/
struct smb_filename * full_path_from_dirfsp_atname (
TALLOC_CTX * mem_ctx ,
const struct files_struct * dirfsp ,
const struct smb_filename * atname )
{
struct smb_filename * fname = NULL ;
char * path = NULL ;
if ( dirfsp = = dirfsp - > conn - > cwd_fsp | |
2020-12-14 17:53:11 +03:00
ISDOT ( dirfsp - > fsp_name - > base_name ) | |
atname - > base_name [ 0 ] = = ' / ' )
2020-04-14 18:44:37 +03:00
{
path = talloc_strdup ( mem_ctx , atname - > base_name ) ;
} else {
path = talloc_asprintf ( mem_ctx , " %s/%s " ,
dirfsp - > fsp_name - > base_name ,
atname - > base_name ) ;
}
if ( path = = NULL ) {
return NULL ;
}
fname = synthetic_smb_fname ( mem_ctx ,
path ,
atname - > stream_name ,
& atname - > st ,
atname - > twrp ,
atname - > flags ) ;
TALLOC_FREE ( path ) ;
if ( fname = = NULL ) {
return NULL ;
}
return fname ;
}