2004-03-27 01:26:33 +03:00
/*
* Expand msdfs targets based on client IP
*
* Copyright ( C ) Volker Lendecke , 2004
*
* 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
2004-03-27 01:26:33 +03:00
* ( 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
2007-07-10 09:23:25 +04:00
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
2004-03-27 01:26:33 +03:00
*/
# include "includes.h"
2011-02-26 01:20:06 +03:00
# include "system/filesys.h"
2011-03-23 00:34:22 +03:00
# include "smbd/smbd.h"
2010-08-05 17:14:04 +04:00
# include "../librpc/gen_ndr/ndr_netlogon.h"
2010-08-18 21:57:21 +04:00
# include "smbd/globals.h"
2011-03-24 16:15:54 +03:00
# include "auth.h"
2011-06-16 16:23:54 +04:00
# include "../lib/tsocket/tsocket.h"
2021-02-11 21:52:47 +03:00
# include "msdfs.h"
2021-11-10 22:18:07 +03:00
# include "source3/lib/substitute.h"
2004-03-27 01:26:33 +03:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_VFS
/**********************************************************
Under mapfile we expect a table of the following format :
IP - Prefix whitespace expansion
For example :
192.168 .234 local . samba . org
192.168 remote . samba . org
default . samba . org
This is to redirect a DFS client to a host close to it .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-08-14 14:11:07 +04:00
static char * read_target_host ( TALLOC_CTX * ctx , const char * mapfile ,
const char * clientaddr )
2004-03-27 01:26:33 +03:00
{
2016-11-22 03:42:36 +03:00
FILE * f ;
2007-11-17 04:07:11 +03:00
char buf [ 1024 ] ;
2005-01-20 04:19:57 +03:00
char * space = buf ;
2007-11-17 04:07:11 +03:00
bool found = false ;
2016-11-22 03:42:36 +03:00
f = fopen ( mapfile , " r " ) ;
2004-03-27 01:26:33 +03:00
if ( f = = NULL ) {
DEBUG ( 0 , ( " can't open IP map %s. Error %s \n " ,
mapfile , strerror ( errno ) ) ) ;
2007-11-17 04:07:11 +03:00
return NULL ;
2004-03-27 01:26:33 +03:00
}
DEBUG ( 10 , ( " Scanning mapfile [%s] \n " , mapfile ) ) ;
2016-11-22 03:42:36 +03:00
while ( fgets ( buf , sizeof ( buf ) , f ) ! = NULL ) {
2004-03-29 15:40:43 +04:00
2004-03-29 15:54:34 +04:00
if ( ( strlen ( buf ) > 0 ) & & ( buf [ strlen ( buf ) - 1 ] = = ' \n ' ) )
2004-03-29 15:40:43 +04:00
buf [ strlen ( buf ) - 1 ] = ' \0 ' ;
DEBUG ( 10 , ( " Scanning line [%s] \n " , buf ) ) ;
2004-03-27 01:26:33 +03:00
space = strchr_m ( buf , ' ' ) ;
if ( space = = NULL ) {
DEBUG ( 0 , ( " Ignoring invalid line %s \n " , buf ) ) ;
continue ;
}
* space = ' \0 ' ;
2010-08-14 14:11:07 +04:00
if ( strncmp ( clientaddr , buf , strlen ( buf ) ) = = 0 ) {
2007-11-17 04:07:11 +03:00
found = true ;
2004-03-27 01:26:33 +03:00
break ;
}
}
2016-11-22 03:42:36 +03:00
fclose ( f ) ;
2004-03-27 01:26:33 +03:00
2007-11-17 04:07:11 +03:00
if ( ! found ) {
return NULL ;
}
2004-03-27 01:26:33 +03:00
space + = 1 ;
while ( isspace ( * space ) )
space + = 1 ;
2007-11-17 04:07:11 +03:00
return talloc_strdup ( ctx , space ) ;
2004-03-27 01:26:33 +03:00
}
/**********************************************************
Expand the msdfs target host using read_target_host
explained above . The syntax used in the msdfs link is
msdfs : @ table - filename @ / share
Everything between and including the two @ - signs is
replaced by the substitution string found in the table
described above .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-11-17 04:07:11 +03:00
static char * expand_msdfs_target ( TALLOC_CTX * ctx ,
connection_struct * conn ,
char * target )
2004-03-27 01:26:33 +03:00
{
2019-11-07 13:01:05 +03:00
const struct loadparm_substitution * lp_sub =
loadparm_s3_global_substitution ( ) ;
2007-11-17 04:07:11 +03:00
char * mapfilename = NULL ;
2004-03-27 01:26:33 +03:00
char * filename_start = strchr_m ( target , ' @ ' ) ;
2007-11-17 04:07:11 +03:00
char * filename_end = NULL ;
int filename_len = 0 ;
char * targethost = NULL ;
char * new_target = NULL ;
2011-06-16 16:23:54 +04:00
char * raddr ;
2004-03-27 01:26:33 +03:00
if ( filename_start = = NULL ) {
DEBUG ( 10 , ( " No filename start in %s \n " , target ) ) ;
2007-11-17 04:07:11 +03:00
return NULL ;
2004-03-27 01:26:33 +03:00
}
filename_end = strchr_m ( filename_start + 1 , ' @ ' ) ;
if ( filename_end = = NULL ) {
DEBUG ( 10 , ( " No filename end in %s \n " , target ) ) ;
2007-11-17 04:07:11 +03:00
return NULL ;
2004-03-27 01:26:33 +03:00
}
filename_len = PTR_DIFF ( filename_end , filename_start + 1 ) ;
2007-11-17 04:07:11 +03:00
mapfilename = talloc_strdup ( ctx , filename_start + 1 ) ;
if ( ! mapfilename ) {
return NULL ;
}
2004-03-27 01:26:33 +03:00
mapfilename [ filename_len ] = ' \0 ' ;
2021-02-11 21:52:47 +03:00
/*
* dfs links returned have had ' / ' characters replaced with ' \ ' .
* Return them to ' / ' so we can have absoute path mapfilenames .
*/
string_replace ( mapfilename , ' \\ ' , ' / ' ) ;
2004-03-27 01:26:33 +03:00
DEBUG ( 10 , ( " Expanding from table [%s] \n " , mapfilename ) ) ;
2011-06-16 16:23:54 +04:00
raddr = tsocket_address_inet_addr_string ( conn - > sconn - > remote_address ,
ctx ) ;
if ( raddr = = NULL ) {
return NULL ;
}
2017-03-14 18:12:20 +03:00
targethost = read_target_host ( ctx , mapfilename , raddr ) ;
2010-08-14 14:11:07 +04:00
if ( targethost = = NULL ) {
2004-03-27 01:26:33 +03:00
DEBUG ( 1 , ( " Could not expand target host from file %s \n " ,
mapfilename ) ) ;
2007-11-17 04:07:11 +03:00
return NULL ;
2004-03-27 01:26:33 +03:00
}
2019-10-31 14:45:44 +03:00
targethost = talloc_sub_full ( ctx ,
2019-11-07 13:01:05 +03:00
lp_servicename ( talloc_tos ( ) , lp_sub , SNUM ( conn ) ) ,
2011-07-15 09:55:31 +04:00
conn - > session_info - > unix_info - > unix_name ,
2007-11-17 04:07:11 +03:00
conn - > connectpath ,
2011-07-15 08:59:14 +04:00
conn - > session_info - > unix_token - > gid ,
2011-07-15 09:55:31 +04:00
conn - > session_info - > unix_info - > sanitized_username ,
2011-07-18 06:58:25 +04:00
conn - > session_info - > info - > domain_name ,
2007-11-17 04:07:11 +03:00
targethost ) ;
2004-03-27 01:26:33 +03:00
DEBUG ( 10 , ( " Expanded targethost to %s \n " , targethost ) ) ;
2007-11-17 04:07:11 +03:00
/* Replace the part between '@...@' */
2004-03-27 01:26:33 +03:00
* filename_start = ' \0 ' ;
2007-11-17 04:07:11 +03:00
new_target = talloc_asprintf ( ctx ,
" %s%s%s " ,
target ,
targethost ,
filename_end + 1 ) ;
if ( ! new_target ) {
return NULL ;
}
2004-03-27 01:26:33 +03:00
DEBUG ( 10 , ( " New DFS target: %s \n " , new_target ) ) ;
2007-11-17 04:07:11 +03:00
return new_target ;
2004-03-27 01:26:33 +03:00
}
2021-02-11 21:52:47 +03:00
static NTSTATUS expand_read_dfs_pathat ( struct vfs_handle_struct * handle ,
TALLOC_CTX * mem_ctx ,
struct files_struct * dirfsp ,
struct smb_filename * smb_fname ,
struct referral * * ppreflist ,
size_t * preferral_count )
2019-08-23 00:18:16 +03:00
{
2021-02-11 21:52:47 +03:00
NTSTATUS status ;
size_t i ;
struct referral * reflist = NULL ;
size_t count = 0 ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
/*
* Always call the NEXT function first , then
* modify the return if needed .
*/
status = SMB_VFS_NEXT_READ_DFS_PATHAT ( handle ,
mem_ctx ,
2019-08-23 00:18:16 +03:00
dirfsp ,
smb_fname ,
2021-02-11 21:52:47 +03:00
ppreflist ,
preferral_count ) ;
2019-08-23 00:18:16 +03:00
2021-02-11 21:52:47 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( frame ) ;
return status ;
}
2019-08-23 00:18:16 +03:00
2021-02-11 21:52:47 +03:00
/*
* This function can be called to check if a pathname
* is an MSDFS link , but not return the values of it .
* In this case ppreflist and preferral_count are NULL ,
* so don ' t bother trying to look at any returns .
*/
if ( ppreflist = = NULL | | preferral_count = = NULL ) {
TALLOC_FREE ( frame ) ;
return status ;
}
2019-08-23 00:18:16 +03:00
2021-02-11 21:52:47 +03:00
/*
* We are always returning the values returned
* returned by the NEXT call , but we might mess
* with the reflist [ i ] . alternate_path values ,
* so use local pointers to minimise indirections .
*/
count = * preferral_count ;
reflist = * ppreflist ;
for ( i = 0 ; i < count ; i + + ) {
if ( strchr_m ( reflist [ i ] . alternate_path , ' @ ' ) ! = NULL ) {
char * new_altpath = expand_msdfs_target ( frame ,
handle - > conn ,
reflist [ i ] . alternate_path ) ;
if ( new_altpath = = NULL ) {
TALLOC_FREE ( * ppreflist ) ;
* preferral_count = 0 ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
reflist [ i ] . alternate_path = talloc_move ( reflist ,
& new_altpath ) ;
2019-08-23 00:18:16 +03:00
}
}
2021-02-11 21:52:47 +03:00
TALLOC_FREE ( frame ) ;
return status ;
2019-08-23 00:18:16 +03:00
}
2009-07-24 04:28:58 +04:00
static struct vfs_fn_pointers vfs_expand_msdfs_fns = {
2021-02-11 21:52:47 +03:00
. read_dfs_pathat_fn = expand_read_dfs_pathat ,
2004-03-27 01:26:33 +03:00
} ;
2017-12-16 01:32:12 +03:00
static_decl_vfs ;
2017-04-20 22:24:43 +03:00
NTSTATUS vfs_expand_msdfs_init ( TALLOC_CTX * ctx )
2004-03-27 01:26:33 +03:00
{
return smb_register_vfs ( SMB_VFS_INTERFACE_VERSION , " expand_msdfs " ,
2009-07-24 04:28:58 +04:00
& vfs_expand_msdfs_fns ) ;
2004-03-27 01:26:33 +03:00
}