2009-07-11 02:35:08 +04:00
/*
Unix SMB / CIFS implementation .
Filename utility functions .
Copyright ( C ) Tim Prouty 2009
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
/**
* XXX : This is temporary and there should be no callers of this outside of
* this file once smb_filename is plumbed through all path based operations .
* The one legitimate caller currently is smb_fname_str_dbg ( ) , which this
* could be made static for .
*/
NTSTATUS get_full_smb_filename ( TALLOC_CTX * ctx ,
const struct smb_filename * smb_fname ,
char * * full_name )
{
if ( smb_fname - > stream_name ) {
2009-07-21 01:32:32 +04:00
/* stream_name must always be NULL if there is no stream. */
SMB_ASSERT ( smb_fname - > stream_name [ 0 ] ! = ' \0 ' ) ;
2009-07-11 02:35:08 +04:00
* full_name = talloc_asprintf ( ctx , " %s%s " , smb_fname - > base_name ,
smb_fname - > stream_name ) ;
} else {
* full_name = talloc_strdup ( ctx , smb_fname - > base_name ) ;
}
if ( ! * full_name ) {
return NT_STATUS_NO_MEMORY ;
}
return NT_STATUS_OK ;
}
/**
* There are actually legitimate callers of this such as functions that
2011-10-17 22:10:29 +04:00
* enumerate streams using the vfs_streaminfo interface and then want to
2009-07-11 02:35:08 +04:00
* operate on each stream .
*/
2013-04-11 19:01:22 +04:00
struct smb_filename * synthetic_smb_fname ( TALLOC_CTX * mem_ctx ,
const char * base_name ,
const char * stream_name ,
2016-03-19 07:19:38 +03:00
const SMB_STRUCT_STAT * psbuf ,
2020-04-30 12:48:32 +03:00
NTTIME twrp ,
2016-03-19 07:19:38 +03:00
uint32_t flags )
2013-04-11 19:01:22 +04:00
{
/* Setup the base_name/stream_name. */
2021-11-05 13:48:25 +03:00
struct smb_filename smb_fname_loc = {
. base_name = discard_const_p ( char , base_name ) ,
. stream_name = discard_const_p ( char , stream_name ) ,
. flags = flags ,
. twrp = twrp ,
} ;
2013-04-11 19:01:22 +04:00
/* Copy the psbuf if one was given. */
if ( psbuf )
smb_fname_loc . st = * psbuf ;
2013-04-12 13:00:31 +04:00
/* Let cp_smb_filename() do the heavy lifting. */
2013-04-11 19:01:22 +04:00
return cp_smb_filename ( mem_ctx , & smb_fname_loc ) ;
}
2017-05-30 21:46:49 +03:00
/**
* Utility function used by VFS calls that must * NOT * operate
* on a stream filename , only the base_name .
*/
struct smb_filename * cp_smb_filename_nostream ( TALLOC_CTX * mem_ctx ,
const struct smb_filename * smb_fname_in )
{
2021-11-05 13:51:33 +03:00
struct smb_filename smb_fname_loc = * smb_fname_in ;
struct smb_filename * smb_fname = NULL ;
smb_fname_loc . stream_name = NULL ;
smb_fname = cp_smb_filename ( mem_ctx , & smb_fname_loc ) ;
2017-05-30 21:46:49 +03:00
return smb_fname ;
}
2009-07-11 02:35:08 +04:00
/**
2016-03-10 02:45:55 +03:00
* There are a few legitimate users of this .
2009-07-11 02:35:08 +04:00
*/
2013-04-12 13:06:45 +04:00
struct smb_filename * synthetic_smb_fname_split ( TALLOC_CTX * ctx ,
2016-03-10 03:00:47 +03:00
const char * fname ,
bool posix_path )
2013-04-12 13:06:45 +04:00
{
2016-03-10 02:45:55 +03:00
char * stream_name = NULL ;
2013-04-12 13:06:45 +04:00
char * base_name = NULL ;
struct smb_filename * ret ;
2016-03-10 02:45:55 +03:00
bool ok ;
2013-04-12 13:06:45 +04:00
2016-03-10 03:00:47 +03:00
if ( posix_path ) {
2016-03-10 02:45:55 +03:00
/* No stream name looked for. */
2016-03-19 07:19:38 +03:00
return synthetic_smb_fname ( ctx ,
fname ,
NULL ,
NULL ,
2020-04-30 12:48:32 +03:00
0 ,
2016-03-19 07:19:38 +03:00
SMB_FILENAME_POSIX_PATH ) ;
2013-04-12 13:06:45 +04:00
}
2016-03-10 02:45:55 +03:00
ok = split_stream_filename ( ctx ,
fname ,
& base_name ,
& stream_name ) ;
if ( ! ok ) {
2013-04-12 13:06:45 +04:00
return NULL ;
}
2020-05-03 09:26:47 +03:00
ret = synthetic_smb_fname ( ctx ,
base_name ,
stream_name ,
NULL ,
2020-04-30 12:48:32 +03:00
0 ,
2020-05-03 09:26:47 +03:00
0 ) ;
2013-04-12 13:06:45 +04:00
TALLOC_FREE ( base_name ) ;
2016-03-10 02:45:55 +03:00
TALLOC_FREE ( stream_name ) ;
2013-04-12 13:06:45 +04:00
return ret ;
}
2009-07-11 02:35:08 +04:00
/**
2009-11-03 12:59:18 +03:00
* Return a string using the talloc_tos ( )
2009-07-11 02:35:08 +04:00
*/
const char * smb_fname_str_dbg ( const struct smb_filename * smb_fname )
{
char * fname = NULL ;
2020-05-01 17:30:28 +03:00
time_t t ;
struct tm tm ;
struct tm * ptm = NULL ;
fstring tstr ;
ssize_t slen ;
2009-07-11 02:35:08 +04:00
NTSTATUS status ;
if ( smb_fname = = NULL ) {
return " " ;
}
2009-11-03 12:59:18 +03:00
status = get_full_smb_filename ( talloc_tos ( ) , smb_fname , & fname ) ;
2009-07-11 02:35:08 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return " " ;
}
2020-05-01 17:30:28 +03:00
if ( smb_fname - > twrp = = 0 ) {
return fname ;
}
t = nt_time_to_unix ( smb_fname - > twrp ) ;
ptm = gmtime_r ( & t , & tm ) ;
if ( ptm = = NULL ) {
return " " ;
}
slen = strftime ( tstr , sizeof ( tstr ) , GMT_FORMAT , & tm ) ;
if ( slen = = 0 ) {
return " " ;
}
2020-11-03 14:33:12 +03:00
fname = talloc_asprintf_append_buffer (
fname , " {%s} " , tstr ) ;
2020-05-01 17:30:28 +03:00
if ( fname = = NULL ) {
return " " ;
}
2009-07-11 02:35:08 +04:00
return fname ;
}
/**
2012-06-13 19:43:18 +04:00
* Return a debug string of the path name of an fsp using the talloc_tos ( ) .
2009-07-11 02:35:08 +04:00
*/
const char * fsp_str_dbg ( const struct files_struct * fsp )
{
2020-05-17 08:53:42 +03:00
const char * name = NULL ;
name = smb_fname_str_dbg ( fsp - > fsp_name ) ;
if ( name = = NULL ) {
return " " ;
}
return name ;
2009-07-11 02:35:08 +04:00
}
2012-06-13 19:58:54 +04:00
/**
* Create a debug string for the fnum of an fsp .
*
* This is allocated to talloc_tos ( ) or a string constant
* in certain corner cases . The returned string should
* hence not be free ' d directly but only via the talloc stack .
*/
const char * fsp_fnum_dbg ( const struct files_struct * fsp )
{
char * str ;
if ( fsp = = NULL ) {
return " fnum [fsp is NULL] " ;
}
if ( fsp - > fnum = = FNUM_FIELD_INVALID ) {
return " fnum [invalid value] " ;
}
2021-12-27 13:25:34 +03:00
str = talloc_asprintf ( talloc_tos ( ) , " fnum % " PRIu64 , fsp - > fnum ) ;
2012-06-13 19:58:54 +04:00
if ( str = = NULL ) {
DEBUG ( 1 , ( " %s: talloc_asprintf failed \n " , __FUNCTION__ ) ) ;
return " fnum [talloc failed!] " ;
}
return str ;
}
2013-04-11 17:24:55 +04:00
struct smb_filename * cp_smb_filename ( TALLOC_CTX * mem_ctx ,
const struct smb_filename * in )
{
struct smb_filename * out ;
2013-09-07 02:34:44 +04:00
size_t base_len = 0 ;
size_t stream_len = 0 ;
int num = 0 ;
2013-04-11 17:24:55 +04:00
/* stream_name must always be NULL if there is no stream. */
if ( in - > stream_name ) {
SMB_ASSERT ( in - > stream_name [ 0 ] ! = ' \0 ' ) ;
}
2013-09-07 02:34:44 +04:00
if ( in - > base_name ! = NULL ) {
base_len = strlen ( in - > base_name ) + 1 ;
num + = 1 ;
}
if ( in - > stream_name ! = NULL ) {
stream_len = strlen ( in - > stream_name ) + 1 ;
num + = 1 ;
}
out = talloc_pooled_object ( mem_ctx , struct smb_filename ,
2020-03-27 02:24:08 +03:00
num , stream_len + base_len ) ;
2013-04-11 17:24:55 +04:00
if ( out = = NULL ) {
return NULL ;
}
2013-09-07 02:34:44 +04:00
ZERO_STRUCTP ( out ) ;
/*
2015-05-18 10:00:46 +03:00
* The following allocations cannot fail as we
2013-09-07 02:34:44 +04:00
* pre - allocated space for them in the out pooled
* object .
*/
2013-04-11 17:24:55 +04:00
if ( in - > base_name ! = NULL ) {
2013-09-07 02:34:44 +04:00
out - > base_name = talloc_memdup (
out , in - > base_name , base_len ) ;
2015-01-09 17:38:19 +03:00
talloc_set_name_const ( out - > base_name ,
out - > base_name ) ;
2013-04-11 17:24:55 +04:00
}
if ( in - > stream_name ! = NULL ) {
2013-09-07 02:34:44 +04:00
out - > stream_name = talloc_memdup (
out , in - > stream_name , stream_len ) ;
2015-01-09 17:38:19 +03:00
talloc_set_name_const ( out - > stream_name ,
out - > stream_name ) ;
2013-04-11 17:24:55 +04:00
}
2016-03-18 02:20:17 +03:00
out - > flags = in - > flags ;
2013-04-11 17:24:55 +04:00
out - > st = in - > st ;
2020-04-28 19:24:59 +03:00
out - > twrp = in - > twrp ;
2013-04-11 17:24:55 +04:00
return out ;
}
2019-09-25 20:18:03 +03:00
static void assert_valid_stream_smb_fname ( const struct smb_filename * smb_fname )
2009-07-11 02:35:08 +04:00
{
2009-07-21 01:32:32 +04:00
/* stream_name must always be NULL if there is no stream. */
if ( smb_fname - > stream_name ) {
SMB_ASSERT ( smb_fname - > stream_name [ 0 ] ! = ' \0 ' ) ;
}
2016-03-19 07:58:20 +03:00
if ( smb_fname - > flags & SMB_FILENAME_POSIX_PATH ) {
2019-09-25 20:15:27 +03:00
SMB_ASSERT ( smb_fname - > stream_name = = NULL ) ;
2009-07-11 02:35:08 +04:00
}
2019-09-25 20:18:03 +03:00
}
/****************************************************************************
2019-09-26 20:38:06 +03:00
Simple check to determine if a smb_fname is a real named stream or the
default stream .
2019-09-25 20:18:03 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool is_ntfs_stream_smb_fname ( const struct smb_filename * smb_fname )
{
assert_valid_stream_smb_fname ( smb_fname ) ;
2009-07-11 02:35:08 +04:00
2022-06-05 15:39:48 +03:00
return ( smb_fname - > stream_name ! = NULL ) ;
2009-07-11 02:35:08 +04:00
}
2019-09-26 20:05:40 +03:00
/****************************************************************************
Simple check to determine if a smb_fname is pointing to a normal file or
a named stream that is not the default stream " ::$DATA " .
foo - > false
foo : : $ DATA - > false
foo : bar - > true
foo : bar : $ DATA - > true
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool is_named_stream ( const struct smb_filename * smb_fname )
{
assert_valid_stream_smb_fname ( smb_fname ) ;
if ( smb_fname - > stream_name = = NULL ) {
return false ;
}
if ( strequal_m ( smb_fname - > stream_name , " ::$DATA " ) ) {
return false ;
}
return true ;
}
2009-07-11 02:35:08 +04:00
/****************************************************************************
Returns true if the filename ' s stream = = " ::$DATA "
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool is_ntfs_default_stream_smb_fname ( const struct smb_filename * smb_fname )
{
2019-09-25 21:19:26 +03:00
assert_valid_stream_smb_fname ( smb_fname ) ;
if ( smb_fname - > stream_name = = NULL ) {
2009-07-11 02:35:08 +04:00
return false ;
}
2019-09-25 21:29:04 +03:00
return strequal_m ( smb_fname - > stream_name , " ::$DATA " ) ;
2009-07-11 02:35:08 +04:00
}
2013-07-10 02:50:47 +04:00
/****************************************************************************
Filter out Windows invalid EA names ( list probed from Windows 2012 ) .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2023-01-03 21:32:41 +03:00
static const char bad_ea_name_chars [ ] = " \" *+,/:;<=>?[ \\ ]| " ;
2013-07-10 02:50:47 +04:00
bool is_invalid_windows_ea_name ( const char * name )
{
int i ;
/* EA name is pulled as ascii so we can examine
individual bytes here . */
for ( i = 0 ; name [ i ] ! = 0 ; i + + ) {
int val = ( name [ i ] & 0xff ) ;
if ( val < ' ' | | strchr ( bad_ea_name_chars , val ) ) {
return true ;
}
}
return false ;
}
bool ea_list_has_invalid_name ( struct ea_list * ea_list )
{
for ( ; ea_list ; ea_list = ea_list - > next ) {
if ( is_invalid_windows_ea_name ( ea_list - > ea . name ) ) {
return true ;
}
}
return false ;
}
2016-03-10 01:56:49 +03:00
/****************************************************************************
Split an incoming name into tallocd filename and stream components .
Returns true on success , false on out of memory .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool split_stream_filename ( TALLOC_CTX * ctx ,
const char * filename_in ,
char * * filename_out ,
char * * streamname_out )
{
const char * stream_name = NULL ;
char * stream_out = NULL ;
char * file_out = NULL ;
stream_name = strchr_m ( filename_in , ' : ' ) ;
if ( stream_name ) {
stream_out = talloc_strdup ( ctx , stream_name ) ;
if ( stream_out = = NULL ) {
return false ;
}
file_out = talloc_strndup ( ctx ,
filename_in ,
PTR_DIFF ( stream_name , filename_in ) ) ;
} else {
file_out = talloc_strdup ( ctx , filename_in ) ;
}
if ( file_out = = NULL ) {
TALLOC_FREE ( stream_out ) ;
return false ;
}
if ( filename_out ) {
* filename_out = file_out ;
}
if ( streamname_out ) {
* streamname_out = stream_out ;
}
return true ;
}