2015-12-13 18:32:52 +03:00
/*
* Unix SMB / CIFS implementation .
* Samba utility functions
* Copyright ( C ) Andrew Tridgell 1992 - 1998
* Copyright ( C ) Jeremy Allison 2001 - 2007
* Copyright ( C ) Simo Sorce 2001
* Copyright ( C ) Jim McDonough < jmcd @ us . ibm . com > 2003
* Copyright ( C ) James Peach 2006
*
* 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 "replace.h"
# include <talloc.h>
2022-09-17 20:13:27 +03:00
# include "lib/util/debug.h"
2022-10-15 14:26:48 +03:00
# include "lib/util/samba_util.h"
2015-12-13 18:32:52 +03:00
# include "lib/util_path.h"
2019-10-15 17:52:30 +03:00
struct loadparm_substitution ;
2015-12-13 18:32:52 +03:00
struct share_params ;
# include "source3/param/param_proto.h"
/**
* @ brief Returns an absolute path to a file concatenating the provided
* @ a rootpath and @ a basename
*
* @ param name Filename , relative to @ a rootpath
*
* @ retval Pointer to a string containing the full path .
* */
2018-08-16 11:45:23 +03:00
static char * xx_path ( TALLOC_CTX * mem_ctx ,
const char * name ,
const char * rootpath )
2015-12-13 18:32:52 +03:00
{
char * fname = NULL ;
2018-08-16 11:45:23 +03:00
fname = talloc_strdup ( mem_ctx , rootpath ) ;
2015-12-13 18:32:52 +03:00
if ( ! fname ) {
return NULL ;
}
trim_string ( fname , " " , " / " ) ;
if ( ! directory_create_or_exist ( fname , 0755 ) ) {
return NULL ;
}
return talloc_asprintf_append ( fname , " /%s " , name ) ;
}
/**
* @ brief Returns an absolute path to a file in the Samba lock directory .
*
* @ param name File to find , relative to LOCKDIR .
*
* @ retval Pointer to a talloc ' ed string containing the full path .
* */
2018-08-16 11:51:44 +03:00
char * lock_path ( TALLOC_CTX * mem_ctx , const char * name )
2015-12-13 18:32:52 +03:00
{
2018-08-16 11:51:44 +03:00
return xx_path ( mem_ctx , name , lp_lock_directory ( ) ) ;
2015-12-13 18:32:52 +03:00
}
/**
* @ brief Returns an absolute path to a file in the Samba state directory .
*
* @ param name File to find , relative to STATEDIR .
*
* @ retval Pointer to a talloc ' ed string containing the full path .
* */
2018-08-16 11:51:44 +03:00
char * state_path ( TALLOC_CTX * mem_ctx , const char * name )
2015-12-13 18:32:52 +03:00
{
2018-08-16 11:51:44 +03:00
return xx_path ( mem_ctx , name , lp_state_directory ( ) ) ;
2015-12-13 18:32:52 +03:00
}
/**
* @ brief Returns an absolute path to a file in the Samba cache directory .
*
* @ param name File to find , relative to CACHEDIR .
*
* @ retval Pointer to a talloc ' ed string containing the full path .
* */
2018-08-16 11:51:44 +03:00
char * cache_path ( TALLOC_CTX * mem_ctx , const char * name )
2015-12-13 18:32:52 +03:00
{
2018-08-16 11:51:44 +03:00
return xx_path ( mem_ctx , name , lp_cache_directory ( ) ) ;
2015-12-13 18:32:52 +03:00
}
2017-01-17 22:33:18 +03:00
/**
* @ brief Removes any invalid path components in an absolute POSIX path .
*
* @ param ctx Talloc context to return string .
*
* @ param abs_path Absolute path string to process .
*
* @ retval Pointer to a talloc ' ed string containing the absolute full path .
* */
2020-04-21 23:24:44 +03:00
char * canonicalize_absolute_path ( TALLOC_CTX * ctx , const char * pathname_in )
{
/*
* Note we use + 2 here so if pathname_in = = " " then we
* have space to return " / " .
*/
char * pathname = talloc_array ( ctx , char , strlen ( pathname_in ) + 2 ) ;
const char * s = pathname_in ;
char * p = pathname ;
if ( pathname = = NULL ) {
return NULL ;
}
/* Always start with a '/'. */
* p + + = ' / ' ;
while ( * s ) {
/* Deal with '/' or multiples of '/'. */
if ( s [ 0 ] = = ' / ' ) {
while ( s [ 0 ] = = ' / ' ) {
/* Eat trailing '/' */
s + + ;
}
/* Update target with one '/' */
2022-07-05 14:48:18 +03:00
if ( p [ - 1 ] ! = ' / ' ) {
2020-04-21 23:24:44 +03:00
* p + + = ' / ' ;
}
continue ;
}
2022-07-05 14:48:18 +03:00
if ( p [ - 1 ] = = ' / ' ) {
2020-04-21 23:24:44 +03:00
/* Deal with "./" or ".\0" */
if ( s [ 0 ] = = ' . ' & &
( s [ 1 ] = = ' / ' | | s [ 1 ] = = ' \0 ' ) ) {
/* Eat the dot. */
s + + ;
while ( s [ 0 ] = = ' / ' ) {
/* Eat any trailing '/' */
s + + ;
}
/* Don't write anything to target. */
continue ;
}
/* Deal with "../" or "..\0" */
if ( s [ 0 ] = = ' . ' & & s [ 1 ] = = ' . ' & &
( s [ 2 ] = = ' / ' | | s [ 2 ] = = ' \0 ' ) ) {
/* Eat the dot dot. */
s + = 2 ;
while ( s [ 0 ] = = ' / ' ) {
/* Eat any trailing '/' */
s + + ;
}
/*
2022-07-05 14:48:18 +03:00
* As we ' re on the slash , we go back
* one character to point p at the
* slash we just saw .
2020-04-21 23:24:44 +03:00
*/
if ( p > pathname ) {
p - - ;
}
/*
* Now go back to the slash
* before the one that p currently points to .
*/
while ( p > pathname ) {
p - - ;
if ( p [ 0 ] = = ' / ' ) {
break ;
}
}
/*
* Step forward one to leave the
* last written ' / ' alone .
*/
p + + ;
/* Don't write anything to target. */
continue ;
}
}
/* Non-separator character, just copy. */
* p + + = * s + + ;
}
2022-07-05 14:48:18 +03:00
if ( p [ - 1 ] = = ' / ' ) {
2020-04-21 23:24:44 +03:00
/*
* We finished on a ' / ' .
* Remove the trailing ' / ' , but not if it ' s
* the sole character in the path .
*/
if ( p > pathname + 1 ) {
p - - ;
}
}
/* Terminate and we're done ! */
* p + + = ' \0 ' ;
return pathname ;
}
2022-09-17 20:13:27 +03:00
static bool find_snapshot_token (
const char * filename ,
2022-09-17 23:48:31 +03:00
char sep ,
2022-09-17 20:13:27 +03:00
const char * * _start ,
const char * * _next_component ,
NTTIME * twrp )
{
const char * start = NULL ;
const char * end = NULL ;
struct tm tm ;
time_t t ;
start = strstr_m ( filename , " @GMT- " ) ;
if ( start = = NULL ) {
return false ;
}
2022-09-17 23:48:31 +03:00
if ( ( start > filename ) & & ( start [ - 1 ] ! = sep ) ) {
2022-09-17 20:13:27 +03:00
/* the GMT-token does not start a path-component */
return false ;
}
end = strptime ( start , GMT_FORMAT , & tm ) ;
if ( end = = NULL ) {
/* Not a valid timestring. */
return false ;
}
2022-09-17 23:48:31 +03:00
if ( ( end [ 0 ] ! = ' \0 ' ) & & ( end [ 0 ] ! = sep ) ) {
2022-09-17 20:13:27 +03:00
/*
* It is not a complete path component , i . e . the path
* component continues after the gmt - token .
*/
return false ;
}
tm . tm_isdst = - 1 ;
t = timegm ( & tm ) ;
unix_to_nt_time ( twrp , t ) ;
DBG_DEBUG ( " Extracted @GMT-Timestamp %s \n " ,
nt_time_string ( talloc_tos ( ) , * twrp ) ) ;
* _start = start ;
2022-09-17 23:48:31 +03:00
if ( end [ 0 ] = = sep ) {
2022-09-17 20:13:27 +03:00
end + = 1 ;
}
* _next_component = end ;
return true ;
}
2022-12-15 21:14:48 +03:00
bool clistr_is_previous_version_path ( const char * path )
2022-09-18 00:02:31 +03:00
{
const char * start = NULL ;
const char * next = NULL ;
NTTIME twrp ;
bool ok ;
ok = find_snapshot_token ( path , ' \\ ' , & start , & next , & twrp ) ;
2022-12-15 21:14:48 +03:00
return ok ;
2022-09-18 00:02:31 +03:00
}
2022-12-16 00:24:12 +03:00
static bool extract_snapshot_token_internal ( char * fname , NTTIME * twrp , char sep )
2022-09-17 20:13:27 +03:00
{
const char * start = NULL ;
const char * next = NULL ;
size_t remaining ;
bool found ;
2022-12-16 00:24:12 +03:00
found = find_snapshot_token ( fname , sep , & start , & next , twrp ) ;
2022-09-17 20:13:27 +03:00
if ( ! found ) {
return false ;
}
remaining = strlen ( next ) ;
memmove ( discard_const_p ( char , start ) , next , remaining + 1 ) ;
return true ;
}
2022-10-15 14:29:14 +03:00
2022-12-16 00:24:12 +03:00
bool extract_snapshot_token ( char * fname , NTTIME * twrp )
{
return extract_snapshot_token_internal ( fname , twrp , ' / ' ) ;
}
2022-12-16 00:26:49 +03:00
bool clistr_smb2_extract_snapshot_token ( char * fname , NTTIME * twrp )
{
return extract_snapshot_token_internal ( fname , twrp , ' \\ ' ) ;
}
2022-10-15 14:29:14 +03:00
/*
* Take two absolute paths , figure out if " subdir " is a proper
* subdirectory of " parent " . Return the component relative to the
* " parent " without the potential " / " . Take care of " parent "
* possibly ending in " / " .
*/
bool subdir_of ( const char * parent ,
size_t parent_len ,
const char * subdir ,
const char * * _relative )
{
const char * relative = NULL ;
bool matched ;
SMB_ASSERT ( parent [ 0 ] = = ' / ' ) ;
SMB_ASSERT ( subdir [ 0 ] = = ' / ' ) ;
if ( parent_len = = 1 ) {
/*
* Everything is below " / "
*/
* _relative = subdir + 1 ;
return true ;
}
if ( parent [ parent_len - 1 ] = = ' / ' ) {
parent_len - = 1 ;
}
matched = ( strncmp ( subdir , parent , parent_len ) = = 0 ) ;
if ( ! matched ) {
return false ;
}
relative = & subdir [ parent_len ] ;
if ( relative [ 0 ] = = ' \0 ' ) {
* _relative = relative ; /* nothing left */
return true ;
}
if ( relative [ 0 ] = = ' / ' ) {
/* End of parent must match a '/' in subdir. */
* _relative = relative + 1 ;
return true ;
}
return false ;
}