2000-03-09 01:14:30 +03:00
/*
2002-07-15 14:35:28 +04:00
Unix SMB / Netbios implementation .
Version 3.0
2000-03-09 01:14:30 +03:00
MSDfs services for Samba
Copyright ( C ) Shirish Kalele 2000
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 2 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 , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
2002-07-15 14:35:28 +04:00
2000-03-09 01:14:30 +03:00
*/
# include "includes.h"
2002-07-15 14:35:28 +04:00
extern fstring local_machine ;
extern uint32 global_client_caps ;
2000-03-09 01:14:30 +03:00
2000-05-18 22:43:53 +04:00
/**********************************************************************
2002-07-15 14:35:28 +04:00
Parse the pathname of the form \ hostname \ service \ reqpath
2000-05-18 22:43:53 +04:00
into the dfs_path structure
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-06-30 02:32:24 +04:00
2000-03-11 02:05:53 +03:00
static BOOL parse_dfs_path ( char * pathname , struct dfs_path * pdp )
2000-03-09 01:14:30 +03:00
{
2001-06-30 02:32:24 +04:00
pstring pathname_local ;
char * p , * temp ;
pstrcpy ( pathname_local , pathname ) ;
p = temp = pathname_local ;
ZERO_STRUCTP ( pdp ) ;
trim_string ( temp , " \\ " , " \\ " ) ;
DEBUG ( 10 , ( " temp in parse_dfs_path: .%s. after trimming \\ 's \n " , temp ) ) ;
/* now tokenize */
/* parse out hostname */
2002-07-15 14:35:28 +04:00
p = strchr ( temp , ' \\ ' ) ;
2001-06-30 02:32:24 +04:00
if ( p = = NULL )
return False ;
* p = ' \0 ' ;
pstrcpy ( pdp - > hostname , temp ) ;
DEBUG ( 10 , ( " hostname: %s \n " , pdp - > hostname ) ) ;
/* parse out servicename */
temp = p + 1 ;
2002-07-15 14:35:28 +04:00
p = strchr ( temp , ' \\ ' ) ;
2001-06-30 02:32:24 +04:00
if ( p = = NULL ) {
pstrcpy ( pdp - > servicename , temp ) ;
2002-07-15 14:35:28 +04:00
pdp - > reqpath [ 0 ] = ' \0 ' ;
2001-06-30 02:32:24 +04:00
return True ;
}
* p = ' \0 ' ;
pstrcpy ( pdp - > servicename , temp ) ;
DEBUG ( 10 , ( " servicename: %s \n " , pdp - > servicename ) ) ;
2002-07-15 14:35:28 +04:00
/* rest is reqpath */
pstrcpy ( pdp - > reqpath , p + 1 ) ;
p = pdp - > reqpath ;
while ( * p ) {
if ( * p = = ' \\ ' ) * p = ' / ' ;
p + + ;
2001-06-30 02:32:24 +04:00
}
2002-07-15 14:35:28 +04:00
DEBUG ( 10 , ( " rest of the path: %s \n " , pdp - > reqpath ) ) ;
2001-06-30 02:32:24 +04:00
return True ;
}
/********************************************************
Fake up a connection struct for the VFS layer .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL create_conn_struct ( connection_struct * conn , int snum , char * path )
{
ZERO_STRUCTP ( conn ) ;
conn - > service = snum ;
conn - > connectpath = path ;
2002-07-15 14:35:28 +04:00
pstring_sub ( conn - > connectpath , " %S " , lp_servicename ( snum ) ) ;
2001-06-30 02:32:24 +04:00
2001-10-18 04:27:20 +04:00
if ( ! smbd_vfs_init ( conn ) ) {
2002-07-15 14:35:28 +04:00
DEBUG ( 0 , ( " create_conn_struct: smbd_vfs_init failed. \n " ) ) ;
2001-06-30 02:32:24 +04:00
return False ;
}
return True ;
2000-03-09 01:14:30 +03:00
}
2000-05-18 22:43:53 +04:00
2000-05-16 05:13:16 +04:00
/**********************************************************************
Parse the contents of a symlink to verify if it is an msdfs referral
A valid referral is of the form : msdfs : server1 \ share1 , server2 \ share2
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-07-15 14:35:28 +04:00
static BOOL parse_symlink ( char * buf , struct referral * * preflist ,
int * refcount )
2000-05-16 05:13:16 +04:00
{
2001-06-30 02:32:24 +04:00
pstring temp ;
char * prot ;
char * alt_path [ MAX_REFERRAL_COUNT ] ;
int count = 0 , i ;
struct referral * reflist ;
2000-05-16 05:13:16 +04:00
2001-06-30 02:32:24 +04:00
pstrcpy ( temp , buf ) ;
2000-05-16 05:13:16 +04:00
2001-06-30 02:32:24 +04:00
prot = strtok ( temp , " : " ) ;
2002-07-15 14:35:28 +04:00
if ( ! strequal ( prot , " msdfs " ) )
2001-06-30 02:32:24 +04:00
return False ;
2002-07-15 14:35:28 +04:00
/* No referral list requested. Just yes/no. */
if ( ! preflist )
2001-06-30 02:32:24 +04:00
return True ;
/* parse out the alternate paths */
while ( ( ( alt_path [ count ] = strtok ( NULL , " , " ) ) ! = NULL ) & & count < MAX_REFERRAL_COUNT )
count + + ;
DEBUG ( 10 , ( " parse_symlink: count=%d \n " , count ) ) ;
reflist = * preflist = ( struct referral * ) malloc ( count * sizeof ( struct referral ) ) ;
if ( reflist = = NULL ) {
DEBUG ( 0 , ( " parse_symlink: Malloc failed! \n " ) ) ;
return False ;
}
2002-07-15 14:35:28 +04:00
2001-06-30 02:32:24 +04:00
for ( i = 0 ; i < count ; i + + ) {
/* replace / in the alternate path by a \ */
2002-07-15 14:35:28 +04:00
char * p = strchr ( alt_path [ i ] , ' / ' ) ;
2001-06-30 02:32:24 +04:00
if ( p )
* p = ' \\ ' ;
pstrcpy ( reflist [ i ] . alternate_path , " \\ " ) ;
pstrcat ( reflist [ i ] . alternate_path , alt_path [ i ] ) ;
reflist [ i ] . proximity = 0 ;
reflist [ i ] . ttl = REFERRAL_TTL ;
DEBUG ( 10 , ( " parse_symlink: Created alt path: %s \n " , reflist [ i ] . alternate_path ) ) ;
}
if ( refcount )
* refcount = count ;
return True ;
2000-05-16 05:13:16 +04:00
}
2000-05-26 21:10:40 +04:00
/**********************************************************************
Returns true if the unix path is a valid msdfs symlink
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-07-15 14:35:28 +04:00
BOOL is_msdfs_link ( connection_struct * conn , char * path ,
struct referral * * reflistp , int * refcnt ,
SMB_STRUCT_STAT * sbufp )
2000-05-16 05:13:16 +04:00
{
2001-06-30 02:32:24 +04:00
SMB_STRUCT_STAT st ;
pstring referral ;
int referral_len = 0 ;
2000-05-16 05:13:16 +04:00
2002-07-15 14:35:28 +04:00
if ( ! path | | ! conn )
2001-06-30 02:32:24 +04:00
return False ;
2000-05-16 05:13:16 +04:00
2001-06-30 02:32:24 +04:00
strlower ( path ) ;
2000-05-16 05:13:16 +04:00
2002-07-15 14:35:28 +04:00
if ( sbufp = = NULL )
sbufp = & st ;
if ( conn - > vfs_ops . lstat ( conn , path , sbufp ) ! = 0 ) {
2001-06-30 02:32:24 +04:00
DEBUG ( 5 , ( " is_msdfs_link: %s does not exist. \n " , path ) ) ;
return False ;
}
2000-05-16 05:13:16 +04:00
2002-07-15 14:35:28 +04:00
if ( S_ISLNK ( sbufp - > st_mode ) ) {
2001-06-30 02:32:24 +04:00
/* open the link and read it */
2002-07-15 14:35:28 +04:00
referral_len = conn - > vfs_ops . readlink ( conn , path , referral ,
sizeof ( pstring ) ) ;
if ( referral_len = = - 1 ) {
2001-06-30 02:32:24 +04:00
DEBUG ( 0 , ( " is_msdfs_link: Error reading msdfs link %s: %s \n " , path , strerror ( errno ) ) ) ;
2002-07-15 14:35:28 +04:00
return False ;
}
2001-06-30 02:32:24 +04:00
referral [ referral_len ] = ' \0 ' ;
DEBUG ( 5 , ( " is_msdfs_link: %s -> %s \n " , path , referral ) ) ;
2002-07-15 14:35:28 +04:00
if ( parse_symlink ( referral , reflistp , refcnt ) )
2001-06-30 02:32:24 +04:00
return True ;
}
return False ;
2000-05-16 05:13:16 +04:00
}
2002-07-15 14:35:28 +04:00
/*****************************************************************
Used by other functions to decide if a dfs path is remote ,
and to get the list of referred locations for that remote path .
2001-06-30 02:32:24 +04:00
2002-07-15 14:35:28 +04:00
findfirst_flag : For findfirsts , dfs links themselves are not
redirected , but paths beyond the links are . For normal smb calls ,
even dfs links need to be redirected .
self_referralp : clients expect a dfs referral for the same share when
they request referrals for dfs roots on a server .
consumedcntp : how much of the dfs path is being redirected . the client
should try the remaining path on the redirected server .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL resolve_dfs_path ( char * dfspath , struct dfs_path * dp ,
connection_struct * conn ,
BOOL findfirst_flag ,
struct referral * * reflistpp , int * refcntp ,
BOOL * self_referralp , int * consumedcntp )
{
fstring localpath ;
char * p ;
fstring reqpath ;
if ( ! dp | | ! conn ) {
DEBUG ( 1 , ( " resolve_dfs_path: NULL dfs_path* or NULL connection_struct*! \n " ) ) ;
2001-06-30 02:32:24 +04:00
return False ;
2002-07-15 14:35:28 +04:00
}
2000-05-16 05:13:16 +04:00
2002-07-15 14:35:28 +04:00
if ( dp - > reqpath [ 0 ] = = ' \0 ' ) {
if ( self_referralp ) {
DEBUG ( 6 , ( " resolve_dfs_path: self-referral. returning False \n " ) ) ;
* self_referralp = True ;
}
2001-06-30 02:32:24 +04:00
return False ;
}
2002-07-15 14:35:28 +04:00
/* check if need to redirect */
fstrcpy ( localpath , conn - > connectpath ) ;
fstrcat ( localpath , " / " ) ;
fstrcat ( localpath , dp - > reqpath ) ;
if ( is_msdfs_link ( conn , localpath , reflistpp , refcntp , NULL ) ) {
if ( findfirst_flag ) {
DEBUG ( 6 , ( " resolve_dfs_path (FindFirst) No redirection "
" for dfs link %s. \n " , dfspath ) ) ;
return False ;
} else {
DEBUG ( 6 , ( " resolve_dfs_path: %s resolves to a valid Dfs link. \n " ,
dfspath ) ) ;
if ( consumedcntp )
* consumedcntp = strlen ( dfspath ) ;
return True ;
}
}
/* also redirect if the parent directory is a dfs link */
fstrcpy ( reqpath , dp - > reqpath ) ;
p = strrchr ( reqpath , ' / ' ) ;
if ( p ) {
* p = ' \0 ' ;
fstrcpy ( localpath , conn - > connectpath ) ;
fstrcat ( localpath , " / " ) ;
fstrcat ( localpath , reqpath ) ;
if ( is_msdfs_link ( conn , localpath , reflistpp , refcntp , NULL ) ) {
DEBUG ( 4 , ( " resolve_dfs_path: Redirecting %s because parent %s is dfs link \n " , dfspath , localpath ) ) ;
/* To find the path consumed, we truncate the original
DFS pathname passed to use to remove the last
component . The length of the resulting string is
the path consumed
*/
if ( consumedcntp ) {
char * q ;
pstring buf ;
2003-02-24 22:37:20 +03:00
pstrcpy ( buf , dfspath ) ;
2002-07-15 14:35:28 +04:00
trim_string ( buf , NULL , " \\ " ) ;
q = strrchr ( buf , ' \\ ' ) ;
if ( q )
* q = ' \0 ' ;
* consumedcntp = strlen ( buf ) ;
DEBUG ( 10 , ( " resolve_dfs_path: Path consumed: %d \n " , * consumedcntp ) ) ;
}
2001-06-30 02:32:24 +04:00
return True ;
2002-07-15 14:35:28 +04:00
}
2001-06-30 02:32:24 +04:00
}
2002-07-15 14:35:28 +04:00
2001-06-30 02:32:24 +04:00
return False ;
2000-05-16 05:13:16 +04:00
}
2000-03-09 01:14:30 +03:00
2002-07-15 14:35:28 +04:00
/*****************************************************************
Decides if a dfs pathname should be redirected or not .
If not , the pathname is converted to a tcon - relative local unix path
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL dfs_redirect ( char * pathname , connection_struct * conn ,
BOOL findfirst_flag )
2000-03-09 01:14:30 +03:00
{
2001-06-30 02:32:24 +04:00
struct dfs_path dp ;
2002-07-15 14:35:28 +04:00
if ( ! conn | | ! pathname )
2001-06-30 02:32:24 +04:00
return False ;
2002-07-15 14:35:28 +04:00
parse_dfs_path ( pathname , & dp ) ;
2001-06-30 02:32:24 +04:00
2002-07-15 14:35:28 +04:00
/* if dfs pathname for a non-dfs share, convert to tcon-relative
path and return false */
if ( ! lp_msdfs_root ( SNUM ( conn ) ) ) {
fstrcpy ( pathname , dp . reqpath ) ;
return False ;
}
if ( strcasecmp ( dp . servicename , lp_servicename ( SNUM ( conn ) ) ) ! = 0 )
2001-06-30 02:32:24 +04:00
return False ;
2002-07-15 14:35:28 +04:00
if ( resolve_dfs_path ( pathname , & dp , conn , findfirst_flag ,
NULL , NULL , NULL , NULL ) ) {
DEBUG ( 3 , ( " dfs_redirect: Redirecting %s \n " , pathname ) ) ;
2001-06-30 02:32:24 +04:00
return True ;
} else {
2002-07-15 14:35:28 +04:00
DEBUG ( 3 , ( " dfs_redirect: Not redirecting %s. \n " , pathname ) ) ;
/* Form non-dfs tcon-relative path */
fstrcpy ( pathname , dp . reqpath ) ;
DEBUG ( 3 , ( " dfs_redirect: Path converted to non-dfs path %s \n " ,
pathname ) ) ;
2001-06-30 02:32:24 +04:00
return False ;
}
2002-07-15 14:35:28 +04:00
/* never reached */
return False ;
2000-03-09 01:14:30 +03:00
}
2002-07-15 14:35:28 +04:00
/**********************************************************************
Gets valid referrals for a dfs path and fills up the
junction_map structure
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL get_referred_path ( char * pathname , struct junction_map * jn ,
int * consumedcntp , BOOL * self_referralp )
2000-03-09 01:14:30 +03:00
{
2001-06-30 02:32:24 +04:00
struct dfs_path dp ;
2002-07-15 14:35:28 +04:00
struct connection_struct conns ;
struct connection_struct * conn = & conns ;
pstring conn_path ;
int snum ;
BOOL self_referral = False ;
if ( ! pathname | | ! jn )
return False ;
if ( self_referralp )
* self_referralp = False ;
else
self_referralp = & self_referral ;
parse_dfs_path ( pathname , & dp ) ;
2001-06-30 02:32:24 +04:00
2002-07-15 14:35:28 +04:00
/* Verify hostname in path */
if ( local_machine & & ( strcasecmp ( local_machine , dp . hostname ) ! = 0 ) ) {
/* Hostname mismatch, check if one of our IP addresses */
if ( ! ismyip ( * interpret_addr2 ( dp . hostname ) ) ) {
DEBUG ( 3 , ( " get_referred_path: Invalid hostname %s in path %s \n " ,
dp . hostname , pathname ) ) ;
2001-06-30 02:32:24 +04:00
return False ;
2002-07-15 14:35:28 +04:00
}
2001-06-30 02:32:24 +04:00
}
2002-07-15 14:35:28 +04:00
pstrcpy ( jn - > service_name , dp . servicename ) ;
pstrcpy ( jn - > volume_name , dp . reqpath ) ;
/* Verify the share is a dfs root */
snum = lp_servicenumber ( jn - > service_name ) ;
if ( snum < 0 ) {
if ( ( snum = find_service ( jn - > service_name ) ) < 0 )
return False ;
}
pstrcpy ( conn_path , lp_pathname ( snum ) ) ;
if ( ! create_conn_struct ( conn , snum , conn_path ) )
2001-06-30 02:32:24 +04:00
return False ;
2002-07-15 14:35:28 +04:00
if ( ! lp_msdfs_root ( SNUM ( conn ) ) ) {
DEBUG ( 3 , ( " get_referred_path: .%s. in dfs path %s is not a dfs root. \n " ,
dp . servicename , pathname ) ) ;
return False ;
}
2002-12-27 23:08:35 +03:00
if ( * lp_msdfs_proxy ( snum ) ! = ' \0 ' ) {
struct referral * ref ;
jn - > referral_count = 1 ;
if ( ( ref = ( struct referral * ) malloc ( sizeof ( struct referral ) ) )
= = NULL ) {
DEBUG ( 0 , ( " malloc failed for referral \n " ) ) ;
return False ;
}
pstrcpy ( ref - > alternate_path , lp_msdfs_proxy ( snum ) ) ;
if ( dp . reqpath [ 0 ] ! = ' \0 ' )
pstrcat ( ref - > alternate_path , dp . reqpath ) ;
ref - > proximity = 0 ;
ref - > ttl = REFERRAL_TTL ;
jn - > referral_list = ref ;
if ( consumedcntp )
* consumedcntp = strlen ( pathname ) ;
return True ;
}
2002-07-15 14:35:28 +04:00
/* If not remote & not a self referral, return False */
if ( ! resolve_dfs_path ( pathname , & dp , conn , False ,
& jn - > referral_list , & jn - > referral_count ,
self_referralp , consumedcntp ) ) {
if ( ! * self_referralp ) {
DEBUG ( 3 , ( " get_referred_path: No valid referrals for path %s \n " , pathname ) ) ;
return False ;
}
}
/* if self_referral, fill up the junction map */
if ( * self_referralp ) {
struct referral * ref ;
jn - > referral_count = 1 ;
if ( ( ref = ( struct referral * ) malloc ( sizeof ( struct referral ) ) )
= = NULL ) {
DEBUG ( 0 , ( " malloc failed for referral \n " ) ) ;
return False ;
}
pstrcpy ( ref - > alternate_path , pathname ) ;
ref - > proximity = 0 ;
ref - > ttl = REFERRAL_TTL ;
jn - > referral_list = ref ;
if ( consumedcntp )
* consumedcntp = strlen ( pathname ) ;
2001-06-30 02:32:24 +04:00
}
return True ;
2000-03-09 01:14:30 +03:00
}
2000-05-16 05:13:16 +04:00
static int setup_ver2_dfs_referral ( char * pathname , char * * ppdata ,
struct junction_map * junction ,
2002-07-15 14:35:28 +04:00
int consumedcnt ,
2000-05-16 05:13:16 +04:00
BOOL self_referral )
{
2001-06-30 02:32:24 +04:00
char * pdata = * ppdata ;
unsigned char uni_requestedpath [ 1024 ] ;
int uni_reqpathoffset1 , uni_reqpathoffset2 ;
int uni_curroffset ;
int requestedpathlen = 0 ;
int offset ;
int reply_size = 0 ;
int i = 0 ;
DEBUG ( 10 , ( " setting up version2 referral \n Requested path: \n " ) ) ;
2002-07-15 14:35:28 +04:00
requestedpathlen = rpcstr_push ( uni_requestedpath , pathname , - 1 ,
STR_TERMINATE ) ;
2001-09-12 16:20:14 +04:00
2002-07-15 14:35:28 +04:00
dump_data ( 10 , ( const char * ) uni_requestedpath , requestedpathlen ) ;
2001-06-30 02:32:24 +04:00
DEBUG ( 10 , ( " ref count = %u \n " , junction - > referral_count ) ) ;
uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
VERSION2_REFERRAL_SIZE * junction - > referral_count ;
uni_reqpathoffset2 = uni_reqpathoffset1 + requestedpathlen ;
uni_curroffset = uni_reqpathoffset2 + requestedpathlen ;
reply_size = REFERRAL_HEADER_SIZE + VERSION2_REFERRAL_SIZE * junction - > referral_count +
2 * requestedpathlen ;
DEBUG ( 10 , ( " reply_size: %u \n " , reply_size ) ) ;
/* add up the unicode lengths of all the referral paths */
for ( i = 0 ; i < junction - > referral_count ; i + + ) {
DEBUG ( 10 , ( " referral %u : %s \n " , i , junction - > referral_list [ i ] . alternate_path ) ) ;
reply_size + = ( strlen ( junction - > referral_list [ i ] . alternate_path ) + 1 ) * 2 ;
}
DEBUG ( 10 , ( " reply_size = %u \n " , reply_size ) ) ;
/* add the unexplained 0x16 bytes */
reply_size + = 0x16 ;
2001-08-12 21:30:01 +04:00
pdata = Realloc ( pdata , reply_size ) ;
2001-06-30 02:32:24 +04:00
if ( pdata = = NULL ) {
DEBUG ( 0 , ( " malloc failed for Realloc! \n " ) ) ;
return - 1 ;
2002-07-15 14:35:28 +04:00
} else
* ppdata = pdata ;
2001-06-30 02:32:24 +04:00
/* copy in the dfs requested paths.. required for offset calculations */
memcpy ( pdata + uni_reqpathoffset1 , uni_requestedpath , requestedpathlen ) ;
memcpy ( pdata + uni_reqpathoffset2 , uni_requestedpath , requestedpathlen ) ;
/* create the header */
2002-07-15 14:35:28 +04:00
SSVAL ( pdata , 0 , consumedcnt * 2 ) ; /* path consumed */
2001-06-30 02:32:24 +04:00
SSVAL ( pdata , 2 , junction - > referral_count ) ; /* number of referral in this pkt */
if ( self_referral )
SIVAL ( pdata , 4 , DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER ) ;
else
SIVAL ( pdata , 4 , DFSREF_STORAGE_SERVER ) ;
offset = 8 ;
/* add the referral elements */
for ( i = 0 ; i < junction - > referral_count ; i + + ) {
struct referral * ref = & ( junction - > referral_list [ i ] ) ;
int unilen ;
SSVAL ( pdata , offset , 2 ) ; /* version 2 */
SSVAL ( pdata , offset + 2 , VERSION2_REFERRAL_SIZE ) ;
if ( self_referral )
SSVAL ( pdata , offset + 4 , 1 ) ;
else
SSVAL ( pdata , offset + 4 , 0 ) ;
SSVAL ( pdata , offset + 6 , 0 ) ; /* ref_flags :use path_consumed bytes? */
SIVAL ( pdata , offset + 8 , ref - > proximity ) ;
SIVAL ( pdata , offset + 12 , ref - > ttl ) ;
SSVAL ( pdata , offset + 16 , uni_reqpathoffset1 - offset ) ;
SSVAL ( pdata , offset + 18 , uni_reqpathoffset2 - offset ) ;
/* copy referred path into current offset */
2002-07-15 14:35:28 +04:00
unilen = rpcstr_push ( pdata + uni_curroffset , ref - > alternate_path ,
- 1 , STR_UNICODE ) ;
2001-06-30 02:32:24 +04:00
SSVAL ( pdata , offset + 20 , uni_curroffset - offset ) ;
uni_curroffset + = unilen ;
offset + = VERSION2_REFERRAL_SIZE ;
}
/* add in the unexplained 22 (0x16) bytes at the end */
memset ( pdata + uni_curroffset , ' \0 ' , 0x16 ) ;
return reply_size ;
2000-05-16 05:13:16 +04:00
}
static int setup_ver3_dfs_referral ( char * pathname , char * * ppdata ,
struct junction_map * junction ,
2002-07-15 14:35:28 +04:00
int consumedcnt ,
2000-05-16 05:13:16 +04:00
BOOL self_referral )
{
2001-06-30 02:32:24 +04:00
char * pdata = * ppdata ;
2000-05-16 05:13:16 +04:00
2001-06-30 02:32:24 +04:00
unsigned char uni_reqpath [ 1024 ] ;
int uni_reqpathoffset1 , uni_reqpathoffset2 ;
int uni_curroffset ;
int reply_size = 0 ;
2000-05-16 05:13:16 +04:00
2001-06-30 02:32:24 +04:00
int reqpathlen = 0 ;
int offset , i = 0 ;
2000-05-16 05:13:16 +04:00
2001-06-30 02:32:24 +04:00
DEBUG ( 10 , ( " setting up version3 referral \n " ) ) ;
2000-05-16 05:13:16 +04:00
2002-07-15 14:35:28 +04:00
reqpathlen = rpcstr_push ( uni_reqpath , pathname , - 1 , STR_TERMINATE ) ;
dump_data ( 10 , ( char * ) uni_reqpath , reqpathlen ) ;
2001-06-30 02:32:24 +04:00
uni_reqpathoffset1 = REFERRAL_HEADER_SIZE + VERSION3_REFERRAL_SIZE * junction - > referral_count ;
uni_reqpathoffset2 = uni_reqpathoffset1 + reqpathlen ;
reply_size = uni_curroffset = uni_reqpathoffset2 + reqpathlen ;
for ( i = 0 ; i < junction - > referral_count ; i + + ) {
DEBUG ( 10 , ( " referral %u : %s \n " , i , junction - > referral_list [ i ] . alternate_path ) ) ;
reply_size + = ( strlen ( junction - > referral_list [ i ] . alternate_path ) + 1 ) * 2 ;
}
2001-08-12 21:30:01 +04:00
pdata = Realloc ( pdata , reply_size ) ;
2001-06-30 02:32:24 +04:00
if ( pdata = = NULL ) {
DEBUG ( 0 , ( " version3 referral setup: malloc failed for Realloc! \n " ) ) ;
return - 1 ;
2002-07-15 14:35:28 +04:00
} else
* ppdata = pdata ;
2001-06-30 02:32:24 +04:00
/* create the header */
2002-07-15 14:35:28 +04:00
SSVAL ( pdata , 0 , consumedcnt * 2 ) ; /* path consumed */
SSVAL ( pdata , 2 , junction - > referral_count ) ; /* number of referral */
2001-06-30 02:32:24 +04:00
if ( self_referral )
SIVAL ( pdata , 4 , DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER ) ;
else
SIVAL ( pdata , 4 , DFSREF_STORAGE_SERVER ) ;
2000-05-16 05:13:16 +04:00
2001-06-30 02:32:24 +04:00
/* copy in the reqpaths */
memcpy ( pdata + uni_reqpathoffset1 , uni_reqpath , reqpathlen ) ;
memcpy ( pdata + uni_reqpathoffset2 , uni_reqpath , reqpathlen ) ;
2000-05-16 05:13:16 +04:00
2001-06-30 02:32:24 +04:00
offset = 8 ;
for ( i = 0 ; i < junction - > referral_count ; i + + ) {
struct referral * ref = & ( junction - > referral_list [ i ] ) ;
int unilen ;
SSVAL ( pdata , offset , 3 ) ; /* version 3 */
SSVAL ( pdata , offset + 2 , VERSION3_REFERRAL_SIZE ) ;
if ( self_referral )
SSVAL ( pdata , offset + 4 , 1 ) ;
else
SSVAL ( pdata , offset + 4 , 0 ) ;
SSVAL ( pdata , offset + 6 , 0 ) ; /* ref_flags :use path_consumed bytes? */
SIVAL ( pdata , offset + 8 , ref - > ttl ) ;
2000-05-16 05:13:16 +04:00
2001-06-30 02:32:24 +04:00
SSVAL ( pdata , offset + 12 , uni_reqpathoffset1 - offset ) ;
SSVAL ( pdata , offset + 14 , uni_reqpathoffset2 - offset ) ;
/* copy referred path into current offset */
2002-07-15 14:35:28 +04:00
unilen = rpcstr_push ( pdata + uni_curroffset , ref - > alternate_path ,
- 1 , STR_UNICODE | STR_TERMINATE ) ;
2001-06-30 02:32:24 +04:00
SSVAL ( pdata , offset + 16 , uni_curroffset - offset ) ;
/* copy 0x10 bytes of 00's in the ServiceSite GUID */
memset ( pdata + offset + 18 , ' \0 ' , 16 ) ;
uni_curroffset + = unilen ;
offset + = VERSION3_REFERRAL_SIZE ;
}
return reply_size ;
2000-05-16 05:13:16 +04:00
}
2000-05-18 22:43:53 +04:00
/******************************************************************
* Set up the Dfs referral for the dfs pathname
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-06-30 02:32:24 +04:00
int setup_dfs_referral ( char * pathname , int max_referral_level , char * * ppdata )
2000-05-18 22:43:53 +04:00
{
2001-06-30 02:32:24 +04:00
struct junction_map junction ;
2002-07-15 14:35:28 +04:00
int consumedcnt ;
BOOL self_referral = False ;
pstring buf ;
2001-06-30 02:32:24 +04:00
int reply_size = 0 ;
2002-07-15 14:35:28 +04:00
char * pathnamep = pathname ;
2000-05-18 22:43:53 +04:00
2001-06-30 02:32:24 +04:00
ZERO_STRUCT ( junction ) ;
2000-05-18 22:43:53 +04:00
2002-07-15 14:35:28 +04:00
/* get the junction entry */
if ( ! pathnamep )
2001-06-30 02:32:24 +04:00
return - 1 ;
2000-03-09 01:14:30 +03:00
2002-07-15 14:35:28 +04:00
/* Trim pathname sent by client so it begins with only one backslash.
Two backslashes confuse some dfs clients
*/
while ( strlen ( pathnamep ) > 1 & & pathnamep [ 0 ] = = ' \\ '
& & pathnamep [ 1 ] = = ' \\ ' )
pathnamep + + ;
2003-02-24 22:37:20 +03:00
pstrcpy ( buf , pathnamep ) ;
2002-07-15 14:35:28 +04:00
if ( ! get_referred_path ( buf , & junction , & consumedcnt ,
& self_referral ) )
return - 1 ;
if ( ! self_referral )
{
pathnamep [ consumedcnt ] = ' \0 ' ;
2001-06-30 02:32:24 +04:00
if ( DEBUGLVL ( 3 ) ) {
int i = 0 ;
2002-07-15 14:35:28 +04:00
dbgtext ( " setup_dfs_referral: Path %s to alternate path(s): " , pathnamep ) ;
2001-06-30 02:32:24 +04:00
for ( i = 0 ; i < junction . referral_count ; i + + )
dbgtext ( " %s " , junction . referral_list [ i ] . alternate_path ) ;
dbgtext ( " . \n " ) ;
}
2000-03-09 01:14:30 +03:00
}
2002-12-27 23:08:35 +03:00
2001-06-30 02:32:24 +04:00
/* create the referral depeding on version */
DEBUG ( 10 , ( " max_referral_level :%d \n " , max_referral_level ) ) ;
if ( max_referral_level < 2 | | max_referral_level > 3 )
max_referral_level = 2 ;
switch ( max_referral_level ) {
case 2 :
{
2002-07-15 14:35:28 +04:00
reply_size = setup_ver2_dfs_referral ( pathnamep , ppdata , & junction ,
consumedcnt , self_referral ) ;
SAFE_FREE ( junction . referral_list ) ;
2001-06-30 02:32:24 +04:00
break ;
}
case 3 :
{
2002-07-15 14:35:28 +04:00
reply_size = setup_ver3_dfs_referral ( pathnamep , ppdata , & junction ,
consumedcnt , self_referral ) ;
SAFE_FREE ( junction . referral_list ) ;
2001-06-30 02:32:24 +04:00
break ;
}
default :
{
DEBUG ( 0 , ( " setup_dfs_referral: Invalid dfs referral version: %d \n " , max_referral_level ) ) ;
return - 1 ;
}
2000-03-09 01:14:30 +03:00
}
2001-06-30 02:32:24 +04:00
DEBUG ( 10 , ( " DFS Referral pdata: \n " ) ) ;
dump_data ( 10 , * ppdata , reply_size ) ;
return reply_size ;
2000-03-09 01:14:30 +03:00
}
2000-05-26 21:10:40 +04:00
/**********************************************************************
The following functions are called by the NETDFS RPC pipe functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-06-30 02:32:24 +04:00
2002-07-15 14:35:28 +04:00
/**********************************************************************
Creates a junction structure from a Dfs pathname
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL create_junction ( char * pathname , struct junction_map * jn )
{
struct dfs_path dp ;
parse_dfs_path ( pathname , & dp ) ;
/* check if path is dfs : validate first token */
if ( local_machine & & ( strcasecmp ( local_machine , dp . hostname ) ! = 0 ) ) {
/* Hostname mismatch, check if one of our IP addresses */
if ( ! ismyip ( * interpret_addr2 ( dp . hostname ) ) ) {
DEBUG ( 4 , ( " create_junction: Invalid hostname %s in dfs path %s \n " ,
dp . hostname , pathname ) ) ;
return False ;
}
}
/* Check for a non-DFS share */
if ( ! lp_msdfs_root ( lp_servicenumber ( dp . servicename ) ) ) {
DEBUG ( 4 , ( " create_junction: %s is not an msdfs root. \n " ,
dp . servicename ) ) ;
return False ;
}
pstrcpy ( jn - > service_name , dp . servicename ) ;
pstrcpy ( jn - > volume_name , dp . reqpath ) ;
return True ;
}
/**********************************************************************
Forms a valid Unix pathname from the junction
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL junction_to_local_path ( struct junction_map * jn , char * path ,
int max_pathlen , connection_struct * conn )
{
int snum ;
pstring conn_path ;
if ( ! path | | ! jn )
return False ;
snum = lp_servicenumber ( jn - > service_name ) ;
if ( snum < 0 )
return False ;
safe_strcpy ( path , lp_pathname ( snum ) , max_pathlen - 1 ) ;
safe_strcat ( path , " / " , max_pathlen - 1 ) ;
strlower ( jn - > volume_name ) ;
safe_strcat ( path , jn - > volume_name , max_pathlen - 1 ) ;
pstrcpy ( conn_path , lp_pathname ( snum ) ) ;
if ( ! create_conn_struct ( conn , snum , conn_path ) )
return False ;
return True ;
}
2000-05-26 21:10:40 +04:00
BOOL create_msdfs_link ( struct junction_map * jn , BOOL exists )
{
2001-06-30 02:32:24 +04:00
pstring path ;
pstring msdfs_link ;
connection_struct conns ;
connection_struct * conn = & conns ;
int i = 0 ;
2002-07-15 14:35:28 +04:00
BOOL insert_comma = False ;
2001-06-30 02:32:24 +04:00
2002-07-15 14:35:28 +04:00
if ( ! junction_to_local_path ( jn , path , sizeof ( path ) , conn ) )
2001-06-30 02:32:24 +04:00
return False ;
2000-05-26 21:10:40 +04:00
2001-06-30 02:32:24 +04:00
/* form the msdfs_link contents */
pstrcpy ( msdfs_link , " msdfs: " ) ;
for ( i = 0 ; i < jn - > referral_count ; i + + ) {
char * refpath = jn - > referral_list [ i ] . alternate_path ;
2000-05-26 21:10:40 +04:00
2001-06-30 02:32:24 +04:00
trim_string ( refpath , " \\ " , " \\ " ) ;
2002-07-15 14:35:28 +04:00
if ( * refpath = = ' \0 ' ) {
if ( i = = 0 )
insert_comma = False ;
2001-06-30 02:32:24 +04:00
continue ;
2002-07-15 14:35:28 +04:00
}
if ( i > 0 & & insert_comma )
2001-06-30 02:32:24 +04:00
pstrcat ( msdfs_link , " , " ) ;
2002-07-15 14:35:28 +04:00
2001-06-30 02:32:24 +04:00
pstrcat ( msdfs_link , refpath ) ;
2002-07-15 14:35:28 +04:00
if ( ! insert_comma )
insert_comma = True ;
2001-06-30 02:32:24 +04:00
}
DEBUG ( 5 , ( " create_msdfs_link: Creating new msdfs link: %s -> %s \n " , path , msdfs_link ) ) ;
if ( exists )
if ( conn - > vfs_ops . unlink ( conn , path ) ! = 0 )
return False ;
if ( conn - > vfs_ops . symlink ( conn , msdfs_link , path ) < 0 ) {
DEBUG ( 1 , ( " create_msdfs_link: symlink failed %s -> %s \n Error: %s \n " ,
path , msdfs_link , strerror ( errno ) ) ) ;
return False ;
}
return True ;
2000-05-26 21:10:40 +04:00
}
BOOL remove_msdfs_link ( struct junction_map * jn )
{
2001-06-30 02:32:24 +04:00
pstring path ;
connection_struct conns ;
connection_struct * conn = & conns ;
2000-05-26 21:10:40 +04:00
2002-07-15 14:35:28 +04:00
if ( ! junction_to_local_path ( jn , path , sizeof ( path ) , conn ) )
2001-06-30 02:32:24 +04:00
return False ;
2000-05-26 21:10:40 +04:00
2001-06-30 02:32:24 +04:00
if ( conn - > vfs_ops . unlink ( conn , path ) ! = 0 )
return False ;
2000-05-26 21:10:40 +04:00
2001-06-30 02:32:24 +04:00
return True ;
2000-05-26 21:10:40 +04:00
}
2000-05-16 05:13:16 +04:00
2000-05-18 22:43:53 +04:00
static BOOL form_junctions ( int snum , struct junction_map * jn , int * jn_count )
{
2001-06-30 02:32:24 +04:00
int cnt = * jn_count ;
DIR * dirp ;
char * dname ;
pstring connect_path ;
char * service_name = lp_servicename ( snum ) ;
connection_struct conns ;
connection_struct * conn = & conns ;
2002-12-28 03:18:23 +03:00
struct referral * ref = NULL ;
2000-05-18 22:43:53 +04:00
2001-06-30 02:32:24 +04:00
pstrcpy ( connect_path , lp_pathname ( snum ) ) ;
if ( * connect_path = = ' \0 ' )
return False ;
/*
* Fake up a connection struct for the VFS layer .
*/
if ( ! create_conn_struct ( conn , snum , connect_path ) )
return False ;
2002-12-28 03:18:23 +03:00
/* form a junction for the msdfs root - convention
DO NOT REMOVE THIS : NT clients will not work with us
if this is not present
*/
pstrcpy ( jn [ cnt ] . service_name , service_name ) ;
jn [ cnt ] . volume_name [ 0 ] = ' \0 ' ;
jn [ cnt ] . referral_count = 1 ;
ref = jn [ cnt ] . referral_list
= ( struct referral * ) malloc ( sizeof ( struct referral ) ) ;
if ( jn [ cnt ] . referral_list = = NULL ) {
DEBUG ( 0 , ( " Malloc failed! \n " ) ) ;
return False ;
2002-07-15 14:35:28 +04:00
}
2001-06-30 02:32:24 +04:00
2002-12-28 03:18:23 +03:00
ref - > proximity = 0 ;
ref - > ttl = REFERRAL_TTL ;
if ( * lp_msdfs_proxy ( snum ) ! = ' \0 ' ) {
pstrcpy ( ref - > alternate_path , lp_msdfs_proxy ( snum ) ) ;
2003-02-11 04:45:48 +03:00
* jn_count = + + cnt ;
2002-12-28 03:18:23 +03:00
return True ;
}
slprintf ( ref - > alternate_path , sizeof ( pstring ) - 1 ,
" \\ \\ %s \\ %s " , local_machine , service_name ) ;
cnt + + ;
/* Now enumerate all dfs links */
2001-07-04 11:15:53 +04:00
dirp = conn - > vfs_ops . opendir ( conn , connect_path ) ;
2001-06-30 02:32:24 +04:00
if ( ! dirp )
return False ;
while ( ( dname = vfs_readdirname ( conn , dirp ) ) ! = NULL ) {
pstring pathreal ;
2002-07-15 14:35:28 +04:00
2001-06-30 02:32:24 +04:00
pstrcpy ( pathreal , connect_path ) ;
pstrcat ( pathreal , " / " ) ;
pstrcat ( pathreal , dname ) ;
2000-05-18 22:43:53 +04:00
2002-07-15 14:35:28 +04:00
if ( is_msdfs_link ( conn , pathreal , & ( jn [ cnt ] . referral_list ) ,
& ( jn [ cnt ] . referral_count ) , NULL ) ) {
pstrcpy ( jn [ cnt ] . service_name , service_name ) ;
pstrcpy ( jn [ cnt ] . volume_name , dname ) ;
cnt + + ;
2001-06-30 02:32:24 +04:00
}
2000-05-18 22:43:53 +04:00
}
2002-07-15 14:35:28 +04:00
2001-06-30 02:32:24 +04:00
conn - > vfs_ops . closedir ( conn , dirp ) ;
* jn_count = cnt ;
return True ;
2000-05-18 22:43:53 +04:00
}
2000-05-26 21:10:40 +04:00
int enum_msdfs_links ( struct junction_map * jn )
2000-05-18 22:43:53 +04:00
{
2001-06-30 02:32:24 +04:00
int i = 0 ;
int jn_count = 0 ;
if ( ! lp_host_msdfs ( ) )
return - 1 ;
for ( i = 0 ; * lp_servicename ( i ) ; i + + ) {
if ( lp_msdfs_root ( i ) )
form_junctions ( i , jn , & jn_count ) ;
}
return jn_count ;
2000-05-18 22:43:53 +04:00
}
2002-07-15 14:35:28 +04:00