2000-03-09 01:14:30 +03:00
/*
Unix SMB / Netbios implementation .
Version 3.0
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 .
*/
# include "includes.h"
extern int DEBUGLEVEL ;
extern pstring global_myname ;
2000-05-18 22:43:53 +04:00
/**********************************************************************
Create a tcon relative path from a dfs_path structure
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-06-30 02:32:24 +04:00
2000-03-11 02:05:53 +03:00
static void create_nondfs_path ( char * pathname , struct dfs_path * pdp )
2000-03-09 01:14:30 +03:00
{
2001-06-30 02:32:24 +04:00
pstrcpy ( pathname , pdp - > volumename ) ;
pstrcat ( pathname , " \\ " ) ;
pstrcat ( pathname , pdp - > restofthepath ) ;
2000-03-09 01:14:30 +03:00
}
2000-05-18 22:43:53 +04:00
/**********************************************************************
Parse the pathname of the form \ hostname \ service \ volume \ restofthepath
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 */
2001-07-04 11:36:09 +04:00
p = strchr_m ( 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 ;
2001-07-04 11:36:09 +04:00
p = strchr_m ( temp , ' \\ ' ) ;
2001-06-30 02:32:24 +04:00
if ( p = = NULL ) {
pstrcpy ( pdp - > servicename , temp ) ;
return True ;
}
* p = ' \0 ' ;
pstrcpy ( pdp - > servicename , temp ) ;
DEBUG ( 10 , ( " servicename: %s \n " , pdp - > servicename ) ) ;
/* parse out volumename */
temp = p + 1 ;
2001-07-04 11:36:09 +04:00
p = strchr_m ( temp , ' \\ ' ) ;
2001-06-30 02:32:24 +04:00
if ( p = = NULL ) {
pstrcpy ( pdp - > volumename , temp ) ;
return True ;
}
* p = ' \0 ' ;
pstrcpy ( pdp - > volumename , temp ) ;
DEBUG ( 10 , ( " volumename: %s \n " , pdp - > volumename ) ) ;
/* remaining path .. */
pstrcpy ( pdp - > restofthepath , p + 1 ) ;
DEBUG ( 10 , ( " rest of the path: %s \n " , pdp - > restofthepath ) ) ;
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 ;
if ( ! vfs_init ( conn ) ) {
DEBUG ( 0 , ( " create_conn_struct: vfs init failed. \n " ) ) ;
return False ;
}
return True ;
2000-03-09 01:14:30 +03:00
}
2000-05-26 21:10:40 +04:00
/**********************************************************************
Forms a valid Unix pathname from the junction
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-06-30 02:32:24 +04:00
static BOOL form_path_from_junction ( struct junction_map * jn , char * path , int max_pathlen ,
connection_struct * conn )
2000-05-18 22:43:53 +04:00
{
2001-06-30 02:32:24 +04:00
int snum ;
2000-05-18 22:43:53 +04:00
2001-06-30 02:32:24 +04:00
if ( ! path | | ! jn )
return False ;
2000-05-18 22:43:53 +04:00
2001-06-30 02:32:24 +04:00
snum = lp_servicenumber ( jn - > service_name ) ;
if ( snum < 0 )
return False ;
2000-05-18 22:43:53 +04:00
2001-06-30 02:32:24 +04:00
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 ) ;
if ( ! create_conn_struct ( conn , snum , path ) )
return False ;
return True ;
2000-05-18 22:43:53 +04:00
}
2000-05-26 21:10:40 +04:00
/**********************************************************************
Creates a junction structure from the Dfs pathname
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-06-30 02:32:24 +04:00
2000-05-26 21:10:40 +04:00
BOOL create_junction ( char * pathname , struct junction_map * jn )
2000-05-18 22:43:53 +04:00
{
2001-06-30 02:32:24 +04:00
struct dfs_path dp ;
2000-05-18 22:43:53 +04:00
2001-06-30 02:32:24 +04:00
parse_dfs_path ( pathname , & dp ) ;
/* check if path is dfs : check hostname is the first token */
if ( global_myname & & ( strcasecmp ( global_myname , dp . hostname ) ! = 0 ) ) {
DEBUG ( 4 , ( " create_junction: Invalid hostname %s in dfs path %s \n " , dp . hostname , pathname ) ) ;
return False ;
}
2000-05-18 22:43:53 +04:00
2001-06-30 02:32:24 +04:00
/* 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 . volumename ) ;
return True ;
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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-06-30 02:32:24 +04:00
2000-05-16 05:13:16 +04:00
static BOOL parse_symlink ( char * buf , struct referral * * preflist , int * refcount )
{
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 , " : " ) ;
if ( ! strequal ( prot , " msdfs " ) )
return False ;
/* It's an msdfs referral */
if ( ! preflist )
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 ;
}
2000-05-16 05:13:16 +04:00
2001-06-30 02:32:24 +04:00
for ( i = 0 ; i < count ; i + + ) {
/* replace / in the alternate path by a \ */
2001-07-04 11:36:09 +04:00
char * p = strchr_m ( 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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-06-30 02:32:24 +04:00
2000-05-26 21:10:40 +04:00
BOOL is_msdfs_link ( connection_struct * conn , char * path )
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
2001-06-30 02:32:24 +04:00
if ( ! path | | ! conn )
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
2001-07-04 11:15:53 +04:00
if ( conn - > vfs_ops . lstat ( conn , path , & st ) ! = 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
2001-06-30 02:32:24 +04:00
if ( S_ISLNK ( st . st_mode ) ) {
/* open the link and read it */
referral_len = conn - > vfs_ops . readlink ( conn , path , referral , sizeof ( pstring ) ) ;
if ( referral_len = = - 1 )
DEBUG ( 0 , ( " is_msdfs_link: Error reading msdfs link %s: %s \n " , path , strerror ( errno ) ) ) ;
referral [ referral_len ] = ' \0 ' ;
DEBUG ( 5 , ( " is_msdfs_link: %s -> %s \n " , path , referral ) ) ;
if ( parse_symlink ( referral , NULL , NULL ) )
return True ;
}
return False ;
2000-05-16 05:13:16 +04:00
}
2000-05-26 21:10:40 +04:00
/**********************************************************************
Fills in the junction_map struct with the referrals from the
symbolic link
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-06-30 02:32:24 +04:00
2000-05-18 22:43:53 +04:00
BOOL get_referred_path ( struct junction_map * junction )
2000-05-16 05:13:16 +04:00
{
2001-06-30 02:32:24 +04:00
pstring path ;
pstring buf ;
SMB_STRUCT_STAT st ;
connection_struct conns ;
connection_struct * conn = & conns ;
if ( ! form_path_from_junction ( junction , path , sizeof ( path ) , conn ) )
return False ;
2000-05-16 05:13:16 +04:00
2001-06-30 02:32:24 +04:00
DEBUG ( 5 , ( " get_referred_path: lstat target: %s \n " , path ) ) ;
2000-05-16 05:13:16 +04:00
2001-07-04 11:15:53 +04:00
if ( conn - > vfs_ops . lstat ( conn , path , & st ) ! = 0 ) {
2001-06-30 02:32:24 +04:00
DEBUG ( 5 , ( " get_referred_path: %s does not exist. \n " , path ) ) ;
return False ;
}
2000-05-16 05:13:16 +04:00
2001-06-30 02:32:24 +04:00
if ( S_ISLNK ( st . st_mode ) ) {
/* open the link and read it to get the dfs referral */
int linkcnt = 0 ;
linkcnt = conn - > vfs_ops . readlink ( conn , path , buf , sizeof ( buf ) ) ;
buf [ linkcnt ] = ' \0 ' ;
DEBUG ( 5 , ( " get_referred_path: Referral: %s \n " , buf ) ) ;
if ( parse_symlink ( buf , & junction - > referral_list , & junction - > referral_count ) )
return True ;
}
return False ;
2000-05-16 05:13:16 +04:00
}
2000-03-09 01:14:30 +03:00
/**************************************************************
Decides if given pathname is Dfs and if it should be redirected
Converts pathname to non - dfs format if Dfs redirection not required
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-06-30 02:32:24 +04:00
2000-03-09 01:14:30 +03:00
BOOL dfs_redirect ( char * pathname , connection_struct * conn )
{
2001-06-30 02:32:24 +04:00
struct dfs_path dp ;
pstring temp ;
fstring path ;
pstrcpy ( temp , pathname ) ;
if ( ! lp_msdfs_root ( SNUM ( conn ) ) )
return False ;
parse_dfs_path ( pathname , & dp ) ;
if ( global_myname & & ( strcasecmp ( global_myname , dp . hostname ) ! = 0 ) )
return False ;
/* check if need to redirect */
fstrcpy ( path , conn - > connectpath ) ;
fstrcat ( path , " / " ) ;
fstrcat ( path , dp . volumename ) ;
if ( is_msdfs_link ( conn , path ) ) {
DEBUG ( 4 , ( " dfs_redirect: Redirecting %s \n " , temp ) ) ;
return True ;
} else {
create_nondfs_path ( pathname , & dp ) ;
DEBUG ( 4 , ( " dfs_redirect: Not redirecting %s. Converted to non-dfs pathname \' %s \' \n " ,
temp , pathname ) ) ;
return False ;
}
2000-03-09 01:14:30 +03:00
}
/*
Special DFS redirect call for findfirst ' s .
If the findfirst is for the dfs junction , then no redirection ,
if it is for the underlying directory contents , redirect .
*/
2001-06-30 02:32:24 +04:00
2000-03-09 01:14:30 +03:00
BOOL dfs_findfirst_redirect ( char * pathname , connection_struct * conn )
{
2001-06-30 02:32:24 +04:00
struct dfs_path dp ;
2000-03-09 01:14:30 +03:00
2001-06-30 02:32:24 +04:00
pstring temp ;
pstrcpy ( temp , pathname ) ;
/* Is the path Dfs-redirectable? */
if ( ! dfs_redirect ( temp , conn ) ) {
pstrcpy ( pathname , temp ) ;
return False ;
}
parse_dfs_path ( pathname , & dp ) ;
DEBUG ( 8 , ( " dfs_findfirst_redirect: path %s is in Dfs. dp.restofthepath=.%s. \n " ,
pathname , dp . restofthepath ) ) ;
if ( ! ( * ( dp . restofthepath ) ) ) {
create_nondfs_path ( pathname , & dp ) ;
return False ;
}
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 ,
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 " ) ) ;
2001-09-12 16:20:14 +04:00
requestedpathlen = rpcstr_push ( uni_requestedpath , pathname , - 1 ,
STR_TERMINATE ) ;
2001-06-30 02:32:24 +04:00
dump_data ( 10 , uni_requestedpath , requestedpathlen ) ;
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 ;
}
2001-08-12 21:30:01 +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 */
SSVAL ( pdata , 0 , requestedpathlen - 2 ) ; /* path consumed */
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 */
2001-09-12 16:20:14 +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 ) ;
free ( junction - > referral_list ) ;
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 ,
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
2001-09-12 16:20:14 +04:00
reqpathlen = rpcstr_push ( uni_reqpath , pathname , - 1 , STR_TERMINATE ) ;
2001-06-30 02:32:24 +04:00
dump_data ( 10 , uni_reqpath , reqpathlen ) ;
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 ;
}
2001-08-12 21:30:01 +04:00
else * ppdata = pdata ;
2000-05-16 05:13:16 +04:00
2001-06-30 02:32:24 +04:00
/* create the header */
SSVAL ( pdata , 0 , reqpathlen - 2 ) ; /* path consumed */
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 ) ;
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 */
2001-09-12 16:20:14 +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 + 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 ;
}
free ( junction - > referral_list ) ;
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 ;
2000-05-18 22:43:53 +04:00
2001-06-30 02:32:24 +04:00
BOOL self_referral ;
2000-05-18 22:43:53 +04:00
2001-06-30 02:32:24 +04:00
int reply_size = 0 ;
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
2001-06-30 02:32:24 +04:00
if ( ! create_junction ( pathname , & junction ) )
return - 1 ;
2000-03-09 01:14:30 +03:00
2001-06-30 02:32:24 +04:00
/* get the junction entry */
if ( ! get_referred_path ( & junction ) ) {
/* refer the same pathname, create a standard referral struct */
struct referral * ref ;
self_referral = True ;
junction . referral_count = 1 ;
if ( ( ref = ( struct referral * ) malloc ( sizeof ( struct referral ) ) ) = = NULL ) {
DEBUG ( 0 , ( " malloc failed for referral \n " ) ) ;
return - 1 ;
}
2000-03-09 01:14:30 +03:00
2001-06-30 02:32:24 +04:00
pstrcpy ( ref - > alternate_path , pathname ) ;
ref - > proximity = 0 ;
ref - > ttl = REFERRAL_TTL ;
junction . referral_list = ref ;
} else {
self_referral = False ;
if ( DEBUGLVL ( 3 ) ) {
int i = 0 ;
dbgtext ( " setup_dfs_referral: Path %s to alternate path(s): " , pathname ) ;
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
}
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 :
{
reply_size = setup_ver2_dfs_referral ( pathname , ppdata , & junction , self_referral ) ;
break ;
}
case 3 :
{
reply_size = setup_ver3_dfs_referral ( pathname , ppdata , & junction , self_referral ) ;
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
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 ;
if ( ! form_path_from_junction ( jn , path , sizeof ( path ) , conn ) )
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 , " \\ " , " \\ " ) ;
if ( * refpath = = ' \0 ' )
continue ;
2000-05-26 21:10:40 +04:00
2001-06-30 02:32:24 +04:00
if ( i > 0 )
pstrcat ( msdfs_link , " , " ) ;
2000-05-26 21:10:40 +04:00
2001-06-30 02:32:24 +04:00
pstrcat ( msdfs_link , refpath ) ;
}
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
2001-06-30 02:32:24 +04:00
if ( ! form_path_from_junction ( jn , path , sizeof ( path ) , conn ) )
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 ;
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 ;
/* form a junction for the msdfs root - convention */
/*
pstrpcy ( jn [ cnt ] . service_name , service_name ) ;
jn [ cnt ] . volume_name [ 0 ] = ' \0 ' ;
jn [ cnt ] . referral_count = 1 ;
2000-05-18 22:43:53 +04:00
2001-06-30 02:32:24 +04:00
slprintf ( alt_path , sizeof ( alt_path ) - 1 " \\ \\ %s \\ %s " , global_myname , service_name ) ;
jn [ cnt ] . referral_l
*/
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 ) {
SMB_STRUCT_STAT st ;
pstring pathreal ;
fstring buf ;
int buflen = 0 ;
pstrcpy ( pathreal , connect_path ) ;
pstrcat ( pathreal , " / " ) ;
pstrcat ( pathreal , dname ) ;
2000-05-18 22:43:53 +04:00
2001-06-30 02:32:24 +04:00
if ( conn - > vfs_ops . lstat ( conn , pathreal , & st ) ! = 0 ) {
DEBUG ( 4 , ( " lstat error for %s: %s \n " , pathreal , strerror ( errno ) ) ) ;
continue ;
}
if ( S_ISLNK ( st . st_mode ) ) {
2001-07-04 11:15:53 +04:00
buflen = conn - > vfs_ops . readlink ( conn , pathreal , buf , sizeof ( fstring ) ) ;
2001-06-30 02:32:24 +04:00
buf [ buflen ] = ' \0 ' ;
if ( parse_symlink ( buf , & ( jn [ cnt ] . referral_list ) , & ( jn [ cnt ] . referral_count ) ) ) {
pstrcpy ( jn [ cnt ] . service_name , service_name ) ;
pstrcpy ( jn [ cnt ] . volume_name , dname ) ;
cnt + + ;
}
}
2000-05-18 22:43:53 +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
}
2000-03-09 01:14:30 +03:00