2007-09-11 22:31:29 +04:00
/*
2002-07-15 14:35:28 +04:00
Unix SMB / Netbios implementation .
Version 3.0
2007-03-12 20:55:24 +03:00
MSDFS services for Samba
2000-03-09 01:14:30 +03:00
Copyright ( C ) Shirish Kalele 2000
2007-03-08 01:12:58 +03:00
Copyright ( C ) Jeremy Allison 2007
2015-02-27 17:52:46 +03:00
Copyright ( C ) Robin McCorkell 2015
2000-03-09 01:14:30 +03:00
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
2000-03-09 01:14:30 +03:00
( at your option ) any later version .
2007-09-11 22:31:29 +04:00
2000-03-09 01:14:30 +03:00
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 .
2007-09-11 22:31:29 +04:00
2000-03-09 01:14:30 +03:00
You should have received a copy of the GNU General Public License
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2002-07-15 14:35:28 +04:00
2000-03-09 01:14:30 +03:00
*/
2005-06-28 23:25:48 +04:00
# define DBGC_CLASS DBGC_MSDFS
2000-03-09 01:14:30 +03:00
# include "includes.h"
2011-02-26 01:20:06 +03:00
# include "system/filesys.h"
2011-03-22 18:57:01 +03:00
# include "smbd/smbd.h"
2009-01-08 14:03:45 +03:00
# include "smbd/globals.h"
2011-02-25 00:58:08 +03:00
# include "msdfs.h"
2011-03-24 15:46:20 +03:00
# include "auth.h"
2018-08-30 17:33:25 +03:00
# include "../auth/auth_util.h"
2011-06-29 09:33:54 +04:00
# include "lib/param/loadparm.h"
2011-07-11 20:09:44 +04:00
# include "libcli/security/security.h"
2011-10-01 11:13:50 +04:00
# include "librpc/gen_ndr/ndr_dfsblobs.h"
2017-03-21 17:45:34 +03:00
# include "lib/tsocket/tsocket.h"
2021-01-03 23:53:49 +03:00
# include "lib/global_contexts.h"
2021-11-10 22:18:07 +03:00
# include "source3/lib/substitute.h"
2000-03-09 01:14:30 +03:00
2022-08-18 00:17:23 +03:00
/**********************************************************************
Parse a DFS pathname of the form ( s )
\ hostname \ service - self referral
\ hostname \ service \ remainingpath - Windows referral path
FIXME ! Should we also parse :
\ hostname \ service / remainingpath - POSIX referral path
as currently nothing uses this ?
into the dfs_path components . Strict form .
Checks DFS path starts with separator .
Checks hostname is ours .
Ensures servicename ( share ) is sent , and
if so , terminates the name or is followed by
\ pathname .
If returned , remainingpath is untouched . Caller must call
2023-03-31 12:44:00 +03:00
check_path_syntax ( ) on it .
2022-08-18 00:17:23 +03:00
Called by all non - fileserver processing ( DFS RPC , FSCTL_DFS_GET_REFERRALS )
etc . Errors out on any inconsistency in the path .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS parse_dfs_path_strict ( TALLOC_CTX * ctx ,
const char * pathname ,
char * * _hostname ,
char * * _servicename ,
char * * _remaining_path )
{
char * pathname_local = NULL ;
char * p = NULL ;
const char * hostname = NULL ;
const char * servicename = NULL ;
const char * reqpath = NULL ;
bool my_hostname = false ;
NTSTATUS status ;
DBG_DEBUG ( " path = |%s| \n " , pathname ) ;
pathname_local = talloc_strdup ( talloc_tos ( ) , pathname ) ;
if ( pathname_local = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
/*
* parse_dfs_path_strict ( ) is called from
* get_referred_path ( ) and create_junction ( )
* which use Windows DFS paths of \ server \ share .
*/
/*
* Strict DFS paths * must * start with the
* path separator ' \\ ' .
*/
if ( pathname_local [ 0 ] ! = ' \\ ' ) {
DBG_ERR ( " path %s doesn't start with \\ \n " ,
pathname_local ) ;
status = NT_STATUS_NOT_FOUND ;
goto out ;
}
/* Now tokenize. */
/* Parse out hostname. */
p = strchr ( pathname_local + 1 , ' \\ ' ) ;
if ( p = = NULL ) {
DBG_ERR ( " can't parse hostname from path %s \n " ,
pathname_local ) ;
status = NT_STATUS_NOT_FOUND ;
goto out ;
}
* p = ' \0 ' ;
hostname = & pathname_local [ 1 ] ;
DBG_DEBUG ( " hostname: %s \n " , hostname ) ;
/* Is this really our hostname ? */
my_hostname = is_myname_or_ipaddr ( hostname ) ;
if ( ! my_hostname ) {
DBG_ERR ( " Hostname %s is not ours. \n " ,
hostname ) ;
status = NT_STATUS_NOT_FOUND ;
goto out ;
}
servicename = p + 1 ;
/*
* Find the end of servicename by looking for
* a directory separator character . The character
* should be ' \\ ' for a Windows path .
* If there is no separator , then this is a self - referral
* of " \ server \ share " .
*/
p = strchr ( servicename , ' \\ ' ) ;
if ( p ! = NULL ) {
* p = ' \0 ' ;
}
DBG_DEBUG ( " servicename: %s \n " , servicename ) ;
if ( p = = NULL ) {
/* Client sent self referral "\server\share". */
reqpath = " " ;
} else {
/* Step past the '\0' we just replaced '\\' with. */
reqpath = p + 1 ;
}
DBG_DEBUG ( " rest of the path: %s \n " , reqpath ) ;
if ( _hostname ! = NULL ) {
* _hostname = talloc_strdup ( ctx , hostname ) ;
if ( * _hostname = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
}
if ( _servicename ! = NULL ) {
* _servicename = talloc_strdup ( ctx , servicename ) ;
if ( * _servicename = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
}
if ( _remaining_path ! = NULL ) {
* _remaining_path = talloc_strdup ( ctx , reqpath ) ;
if ( * _remaining_path = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
}
status = NT_STATUS_OK ;
out :
TALLOC_FREE ( pathname_local ) ;
return status ;
}
2001-06-30 02:32:24 +04:00
/********************************************************
2012-10-10 06:47:49 +04:00
Fake up a connection struct for the VFS layer , for use in
applications ( such as the python bindings ) , that do not want the
global working directory changed under them .
2013-12-19 00:55:44 +04:00
SMB_VFS_CONNECT requires root privileges .
2001-06-30 02:32:24 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2013-12-19 00:55:44 +04:00
static NTSTATUS create_conn_struct_as_root ( TALLOC_CTX * ctx ,
2021-06-15 12:17:57 +03:00
struct tevent_context * ev ,
2012-05-23 15:06:55 +04:00
struct messaging_context * msg ,
connection_struct * * pconn ,
int snum ,
const char * path ,
2012-10-10 06:47:49 +04:00
const struct auth_session_info * session_info )
2001-06-30 02:32:24 +04:00
{
2008-04-28 12:31:49 +04:00
connection_struct * conn ;
2007-11-11 09:31:34 +03:00
char * connpath ;
2011-03-01 21:17:49 +03:00
const char * vfs_user ;
2013-01-09 01:02:23 +04:00
struct smbd_server_connection * sconn ;
2013-01-09 04:26:50 +04:00
const char * servicename = lp_const_servicename ( snum ) ;
2020-04-07 03:34:22 +03:00
bool ok ;
2005-08-03 00:50:16 +04:00
2013-01-09 01:02:23 +04:00
sconn = talloc_zero ( ctx , struct smbd_server_connection ) ;
if ( sconn = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2021-06-15 12:17:57 +03:00
sconn - > ev_ctx = ev ;
2013-01-09 01:02:23 +04:00
sconn - > msg_ctx = msg ;
conn = conn_new ( sconn ) ;
2008-04-28 12:31:49 +04:00
if ( conn = = NULL ) {
2013-01-09 01:02:23 +04:00
TALLOC_FREE ( sconn ) ;
2008-04-28 12:31:49 +04:00
return NT_STATUS_NO_MEMORY ;
}
2005-08-03 03:55:38 +04:00
2013-01-09 01:02:23 +04:00
/* Now we have conn, we need to make sconn a child of conn,
* for a proper talloc tree */
talloc_steal ( conn , sconn ) ;
2013-01-09 04:26:50 +04:00
if ( snum = = - 1 & & servicename = = NULL ) {
servicename = " Unknown Service (snum == -1) " ;
}
2008-04-28 12:31:49 +04:00
connpath = talloc_strdup ( conn , path ) ;
2007-11-11 09:31:34 +03:00
if ( ! connpath ) {
2008-04-28 12:31:49 +04:00
TALLOC_FREE ( conn ) ;
2007-11-11 09:31:34 +03:00
return NT_STATUS_NO_MEMORY ;
}
2008-04-28 12:31:49 +04:00
connpath = talloc_string_sub ( conn ,
2012-10-10 06:47:49 +04:00
connpath ,
" %S " ,
2013-01-09 04:26:50 +04:00
servicename ) ;
2007-11-11 09:31:34 +03:00
if ( ! connpath ) {
2008-04-28 12:31:49 +04:00
TALLOC_FREE ( conn ) ;
2007-11-11 09:31:34 +03:00
return NT_STATUS_NO_MEMORY ;
}
2005-08-03 00:50:16 +04:00
2003-08-08 09:10:12 +04:00
/* needed for smbd_vfs_init() */
2006-07-11 22:01:26 +04:00
conn - > params - > service = snum ;
2012-06-06 17:22:31 +04:00
conn - > cnum = TID_FIELD_INVALID ;
2007-03-12 20:55:24 +03:00
2019-12-16 17:24:23 +03:00
SMB_ASSERT ( session_info ! = NULL ) ;
conn - > session_info = copy_session_info ( conn , session_info ) ;
if ( conn - > session_info = = NULL ) {
DBG_ERR ( " copy_serverinfo failed \n " ) ;
TALLOC_FREE ( conn ) ;
return NT_STATUS_NO_MEMORY ;
}
/* unix_info could be NULL in session_info */
if ( conn - > session_info - > unix_info ! = NULL ) {
vfs_user = conn - > session_info - > unix_info - > unix_name ;
2011-03-01 21:17:49 +03:00
} else {
vfs_user = get_current_username ( ) ;
2008-11-24 00:21:26 +03:00
}
2021-01-12 22:44:44 +03:00
conn_setup_case_options ( conn ) ;
2005-12-12 21:21:59 +03:00
set_conn_connectpath ( conn , connpath ) ;
2005-08-03 03:55:38 +04:00
2011-07-11 20:09:44 +04:00
/*
2015-02-10 19:26:47 +03:00
* New code to check if there ' s a share security descriptor
2011-07-11 20:09:44 +04:00
* added from NT server manager . This is done after the
* smb . conf checks are done as we need a uid and token . JRA .
*
*/
2019-12-16 17:24:23 +03:00
share_access_check ( conn - > session_info - > security_token ,
servicename ,
MAXIMUM_ALLOWED_ACCESS ,
& conn - > share_access ) ;
if ( ( conn - > share_access & FILE_WRITE_DATA ) = = 0 ) {
if ( ( conn - > share_access & FILE_READ_DATA ) = = 0 ) {
/* No access, read or write. */
DBG_WARNING ( " connection to %s "
" denied due to security "
" descriptor. \n " ,
servicename ) ;
conn_free ( conn ) ;
return NT_STATUS_ACCESS_DENIED ;
2011-07-11 20:09:44 +04:00
}
conn - > read_only = true ;
}
2001-10-18 04:27:20 +04:00
if ( ! smbd_vfs_init ( conn ) ) {
2007-04-04 02:59:55 +04:00
NTSTATUS status = map_nt_error_from_unix ( errno ) ;
2002-07-15 14:35:28 +04:00
DEBUG ( 0 , ( " create_conn_struct: smbd_vfs_init failed. \n " ) ) ;
2009-08-07 13:48:03 +04:00
conn_free ( conn ) ;
2007-04-04 02:59:55 +04:00
return status ;
2001-06-30 02:32:24 +04:00
}
2004-03-10 05:38:39 +03:00
2011-03-01 21:17:49 +03:00
/* this must be the first filesystem operation that we do */
2013-01-09 04:26:50 +04:00
if ( SMB_VFS_CONNECT ( conn , servicename , vfs_user ) < 0 ) {
2011-03-01 21:17:49 +03:00
DEBUG ( 0 , ( " VFS connect failed! \n " ) ) ;
conn_free ( conn ) ;
return NT_STATUS_UNSUCCESSFUL ;
}
2020-04-07 03:34:22 +03:00
ok = canonicalize_connect_path ( conn ) ;
if ( ! ok ) {
DBG_ERR ( " Failed to canonicalize sharepath \n " ) ;
conn_free ( conn ) ;
return NT_STATUS_ACCESS_DENIED ;
2020-03-19 13:19:48 +03:00
}
2009-08-25 07:57:37 +04:00
conn - > fs_capabilities = SMB_VFS_FS_CAPABILITIES ( conn , & conn - > ts_res ) ;
2018-06-14 08:27:43 +03:00
conn - > tcon_done = true ;
2018-05-25 09:49:29 +03:00
* pconn = talloc_move ( ctx , & conn ) ;
2012-10-10 06:47:49 +04:00
return NT_STATUS_OK ;
}
2018-05-24 16:59:43 +03:00
static int conn_struct_tos_destructor ( struct conn_struct_tos * c )
{
if ( c - > oldcwd_fname ! = NULL ) {
vfs_ChDir ( c - > conn , c - > oldcwd_fname ) ;
TALLOC_FREE ( c - > oldcwd_fname ) ;
}
SMB_VFS_DISCONNECT ( c - > conn ) ;
conn_free ( c - > conn ) ;
return 0 ;
}
/********************************************************
Fake up a connection struct for the VFS layer , for use in
applications ( such as the python bindings ) , that do not want the
global working directory changed under them .
SMB_VFS_CONNECT requires root privileges .
This temporary uses become_root ( ) and unbecome_root ( ) .
But further impersonation has to be cone by the caller .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS create_conn_struct_tos ( struct messaging_context * msg ,
int snum ,
const char * path ,
const struct auth_session_info * session_info ,
struct conn_struct_tos * * _c )
{
struct conn_struct_tos * c = NULL ;
2021-06-15 12:17:57 +03:00
struct tevent_context * ev = NULL ;
2018-05-24 16:59:43 +03:00
NTSTATUS status ;
* _c = NULL ;
c = talloc_zero ( talloc_tos ( ) , struct conn_struct_tos ) ;
if ( c = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2021-06-15 12:17:57 +03:00
ev = samba_tevent_context_init ( c ) ;
if ( ev = = NULL ) {
TALLOC_FREE ( c ) ;
return NT_STATUS_NO_MEMORY ;
}
2018-05-25 09:49:29 +03:00
become_root ( ) ;
status = create_conn_struct_as_root ( c ,
2021-06-15 12:17:57 +03:00
ev ,
2018-05-25 09:49:29 +03:00
msg ,
& c - > conn ,
snum ,
path ,
session_info ) ;
unbecome_root ( ) ;
2018-05-24 16:59:43 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( c ) ;
return status ;
}
talloc_set_destructor ( c , conn_struct_tos_destructor ) ;
* _c = c ;
return NT_STATUS_OK ;
}
/********************************************************
Fake up a connection struct for the VFS layer .
Note : this performs a vfs connect and CHANGES CWD ! ! ! ! JRA .
See also the comment for create_conn_struct_tos ( ) above !
The CWD change is reverted by the destructor of
conn_struct_tos when the current talloc_tos ( ) is destroyed .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS create_conn_struct_tos_cwd ( struct messaging_context * msg ,
int snum ,
const char * path ,
const struct auth_session_info * session_info ,
struct conn_struct_tos * * _c )
{
struct conn_struct_tos * c = NULL ;
struct smb_filename smb_fname_connectpath = { 0 } ;
NTSTATUS status ;
* _c = NULL ;
status = create_conn_struct_tos ( msg ,
snum ,
path ,
session_info ,
& c ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
/*
* Windows seems to insist on doing trans2getdfsreferral ( ) calls on
* the IPC $ share as the anonymous user . If we try to chdir as that
* user we will fail . . . . WTF ? JRA .
*/
c - > oldcwd_fname = vfs_GetWd ( c , c - > conn ) ;
if ( c - > oldcwd_fname = = NULL ) {
status = map_nt_error_from_unix ( errno ) ;
DEBUG ( 3 , ( " vfs_GetWd failed: %s \n " , strerror ( errno ) ) ) ;
TALLOC_FREE ( c ) ;
return status ;
}
smb_fname_connectpath = ( struct smb_filename ) {
. base_name = c - > conn - > connectpath
} ;
if ( vfs_ChDir ( c - > conn , & smb_fname_connectpath ) ! = 0 ) {
status = map_nt_error_from_unix ( errno ) ;
DBG_NOTICE ( " Can't ChDir to new conn path %s. "
" Error was %s \n " ,
c - > conn - > connectpath , strerror ( errno ) ) ;
TALLOC_FREE ( c - > oldcwd_fname ) ;
TALLOC_FREE ( c ) ;
return status ;
}
* _c = c ;
return NT_STATUS_OK ;
}
2021-05-28 10:25:22 +03:00
/********************************************************
Fake up a connection struct for the VFS layer .
This takes an TALLOC_CTX and tevent_context from the
caller and the resulting connection_struct is stable
across the lifetime of mem_ctx and ev .
Note : this performs a vfs connect and changes cwd .
See also the comment for create_conn_struct_tos ( ) above !
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS create_conn_struct_cwd ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct messaging_context * msg ,
const struct auth_session_info * session_info ,
int snum ,
const char * path ,
struct connection_struct * * c )
{
NTSTATUS status ;
become_root ( ) ;
status = create_conn_struct_as_root ( mem_ctx ,
ev ,
msg ,
c ,
snum ,
path ,
session_info ) ;
unbecome_root ( ) ;
2021-08-24 03:42:40 +03:00
return status ;
2021-05-28 10:25:22 +03:00
}
2015-02-27 17:52:46 +03:00
static void shuffle_strlist ( char * * list , int count )
{
2015-07-09 17:28:05 +03:00
int i ;
uint32_t r ;
2015-02-27 17:52:46 +03:00
char * tmp ;
for ( i = count ; i > 1 ; i - - ) {
2015-07-09 17:28:05 +03:00
r = generate_random ( ) % i ;
2015-02-27 17:52:46 +03:00
tmp = list [ i - 1 ] ;
list [ i - 1 ] = list [ r ] ;
list [ r ] = tmp ;
}
}
2000-05-16 05:13:16 +04:00
/**********************************************************************
Parse the contents of a symlink to verify if it is an msdfs referral
2007-03-12 20:55:24 +03:00
A valid referral is of the form :
msdfs : server1 \ share1 , server2 \ share2
msdfs : server1 \ share1 \ pathname , server2 \ share2 \ pathname
msdfs : server1 / share1 , server2 / share2
msdfs : server1 / share1 / pathname , server2 / share2 / pathname .
Note that the alternate paths returned here must be of the canonicalized
form :
\ server \ share or
\ server \ share \ path \ to \ file ,
even in posix path mode . This is because we have no knowledge if the
server we ' re referring to understands posix paths .
2000-05-16 05:13:16 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-03-10 05:38:39 +03:00
2020-01-28 03:35:25 +03:00
bool parse_msdfs_symlink ( TALLOC_CTX * ctx ,
bool shuffle_referrals ,
const char * target ,
2020-01-28 20:28:30 +03:00
struct referral * * ppreflist ,
size_t * prefcount )
2000-05-16 05:13:16 +04:00
{
2007-09-11 22:31:29 +04:00
char * temp = NULL ;
2007-03-24 21:22:20 +03:00
char * prot ;
2007-09-11 22:31:29 +04:00
char * * alt_path = NULL ;
2019-12-13 20:52:31 +03:00
size_t count = 0 , i ;
2020-01-28 20:28:30 +03:00
struct referral * reflist = NULL ;
2008-01-23 13:04:10 +03:00
char * saveptr ;
2000-05-16 05:13:16 +04:00
2007-09-11 22:31:29 +04:00
temp = talloc_strdup ( ctx , target ) ;
if ( ! temp ) {
2020-01-28 03:42:11 +03:00
return false ;
2007-09-11 22:31:29 +04:00
}
2008-01-23 13:04:10 +03:00
prot = strtok_r ( temp , " : " , & saveptr ) ;
2007-03-24 21:22:20 +03:00
if ( ! prot ) {
DEBUG ( 0 , ( " parse_msdfs_symlink: invalid path ! \n " ) ) ;
2020-01-28 20:36:26 +03:00
TALLOC_FREE ( temp ) ;
2020-01-28 03:42:11 +03:00
return false ;
2007-03-24 21:22:20 +03:00
}
2001-06-30 02:32:24 +04:00
2011-06-07 05:30:12 +04:00
alt_path = talloc_array ( ctx , char * , MAX_REFERRAL_COUNT ) ;
2007-09-11 22:31:29 +04:00
if ( ! alt_path ) {
2020-01-28 20:36:26 +03:00
TALLOC_FREE ( temp ) ;
2020-01-28 03:42:11 +03:00
return false ;
2007-09-11 22:31:29 +04:00
}
2001-06-30 02:32:24 +04:00
/* parse out the alternate paths */
2006-06-13 23:40:28 +04:00
while ( ( count < MAX_REFERRAL_COUNT ) & &
2008-01-23 13:04:10 +03:00
( ( alt_path [ count ] = strtok_r ( NULL , " , " , & saveptr ) ) ! = NULL ) ) {
2001-06-30 02:32:24 +04:00
count + + ;
2005-08-03 03:24:32 +04:00
}
2001-06-30 02:32:24 +04:00
2015-02-27 17:52:46 +03:00
/* shuffle alternate paths */
2020-01-28 03:31:52 +03:00
if ( shuffle_referrals ) {
2015-02-27 17:52:46 +03:00
shuffle_strlist ( alt_path , count ) ;
}
2019-12-13 20:52:31 +03:00
DBG_DEBUG ( " count=%zu \n " , count ) ;
2001-06-30 02:32:24 +04:00
2007-04-30 06:51:26 +04:00
if ( count ) {
2020-01-28 03:45:20 +03:00
reflist = talloc_zero_array ( ctx ,
2007-09-11 22:31:29 +04:00
struct referral , count ) ;
2007-04-30 06:51:26 +04:00
if ( reflist = = NULL ) {
2020-01-28 20:36:26 +03:00
TALLOC_FREE ( temp ) ;
2007-09-11 22:31:29 +04:00
TALLOC_FREE ( alt_path ) ;
2020-01-28 03:42:11 +03:00
return false ;
2007-04-30 06:51:26 +04:00
}
} else {
2020-01-28 03:45:20 +03:00
reflist = NULL ;
2001-06-30 02:32:24 +04:00
}
2007-09-11 22:31:29 +04:00
2001-06-30 02:32:24 +04:00
for ( i = 0 ; i < count ; i + + ) {
2004-03-12 04:43:25 +03:00
char * p ;
2007-09-11 22:31:29 +04:00
/* Canonicalize link target.
* Replace all / ' s in the path by a \ */
2007-03-12 20:55:24 +03:00
string_replace ( alt_path [ i ] , ' / ' , ' \\ ' ) ;
2004-03-12 04:43:25 +03:00
/* Remove leading '\\'s */
2004-03-27 01:26:33 +03:00
p = alt_path [ i ] ;
2004-03-12 04:43:25 +03:00
while ( * p & & ( * p = = ' \\ ' ) ) {
p + + ;
}
2001-06-30 02:32:24 +04:00
2020-01-28 20:36:26 +03:00
reflist [ i ] . alternate_path = talloc_asprintf ( reflist ,
2007-09-11 22:31:29 +04:00
" \\ %s " ,
p ) ;
if ( ! reflist [ i ] . alternate_path ) {
2020-01-28 20:36:26 +03:00
TALLOC_FREE ( temp ) ;
TALLOC_FREE ( alt_path ) ;
TALLOC_FREE ( reflist ) ;
2020-01-28 03:42:11 +03:00
return false ;
2007-09-11 22:31:29 +04:00
}
2007-03-12 20:55:24 +03:00
2001-06-30 02:32:24 +04:00
reflist [ i ] . proximity = 0 ;
reflist [ i ] . ttl = REFERRAL_TTL ;
2020-01-28 03:42:11 +03:00
DBG_DEBUG ( " Created alt path: %s \n " ,
reflist [ i ] . alternate_path ) ;
2005-08-03 03:24:32 +04:00
}
2001-06-30 02:32:24 +04:00
2020-01-28 20:28:30 +03:00
if ( ppreflist ! = NULL ) {
* ppreflist = reflist ;
2020-01-28 20:36:26 +03:00
} else {
TALLOC_FREE ( reflist ) ;
2020-01-28 03:45:20 +03:00
}
2020-01-28 20:28:30 +03:00
if ( prefcount ! = NULL ) {
* prefcount = count ;
2020-01-28 03:45:20 +03:00
}
2020-01-28 20:36:26 +03:00
TALLOC_FREE ( temp ) ;
2007-09-11 22:31:29 +04:00
TALLOC_FREE ( alt_path ) ;
2020-01-28 03:42:11 +03:00
return true ;
2000-05-16 05:13:16 +04:00
}
2007-09-11 22:31:29 +04:00
/**********************************************************************
Returns true if the unix path is a valid msdfs symlink .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2021-07-13 03:44:10 +03:00
bool is_msdfs_link ( struct files_struct * dirfsp ,
struct smb_filename * atname )
2007-09-11 22:31:29 +04:00
{
2021-07-13 03:44:10 +03:00
NTSTATUS status = SMB_VFS_READ_DFS_PATHAT ( dirfsp - > conn ,
2020-02-12 00:35:53 +03:00
talloc_tos ( ) ,
2021-07-13 03:44:10 +03:00
dirfsp ,
atname ,
2020-02-12 00:35:53 +03:00
NULL ,
2017-06-08 01:03:37 +03:00
NULL ) ;
2020-02-12 00:35:53 +03:00
return ( NT_STATUS_IS_OK ( status ) ) ;
2000-05-16 05:13:16 +04:00
}
2022-08-09 22:07:30 +03: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 .
consumedcntp : how much of the dfs path is being redirected . the client
should try the remaining path on the redirected server .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS dfs_path_lookup ( TALLOC_CTX * ctx ,
connection_struct * conn ,
const char * dfspath , /* Incoming complete dfs path */
const char * reqpath , /* Parsed out remaining path. */
uint32_t ucf_flags ,
size_t * consumedcntp ,
struct referral * * ppreflist ,
size_t * preferral_count )
{
NTSTATUS status ;
struct smb_filename * parent_smb_fname = NULL ;
struct smb_filename * smb_fname_rel = NULL ;
NTTIME twrp = 0 ;
char * local_pathname = NULL ;
char * last_component = NULL ;
char * atname = NULL ;
size_t removed_components = 0 ;
bool posix = ( ucf_flags & UCF_POSIX_PATHNAMES ) ;
char * p = NULL ;
char * canon_dfspath = NULL ;
DBG_DEBUG ( " Conn path = %s reqpath = %s \n " , conn - > connectpath , reqpath ) ;
local_pathname = talloc_strdup ( ctx , reqpath ) ;
if ( local_pathname = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
/* We know reqpath isn't a DFS path. */
ucf_flags & = ~ UCF_DFS_PATHNAME ;
if ( ucf_flags & UCF_GMT_PATHNAME ) {
extract_snapshot_token ( local_pathname , & twrp ) ;
ucf_flags & = ~ UCF_GMT_PATHNAME ;
}
/*
* We should have been given a DFS path to resolve .
* This should return NT_STATUS_PATH_NOT_COVERED .
*
* Do a pathname walk , stripping off components
* until we get NT_STATUS_OK instead of
* NT_STATUS_PATH_NOT_COVERED .
*
* Fail on any other error .
*/
for ( ; ; ) {
TALLOC_CTX * frame = NULL ;
struct files_struct * dirfsp = NULL ;
struct smb_filename * smb_fname_walk = NULL ;
TALLOC_FREE ( parent_smb_fname ) ;
/*
* Use a local stackframe as filename_convert_dirfsp ( )
* opens handles on the last two components in the path .
* Allow these to be freed as we step back through
* the local_pathname .
*/
frame = talloc_stackframe ( ) ;
status = filename_convert_dirfsp ( frame ,
conn ,
local_pathname ,
ucf_flags ,
twrp ,
& dirfsp ,
& smb_fname_walk ) ;
/* If we got a name, save it. */
if ( smb_fname_walk ! = NULL ) {
parent_smb_fname = talloc_move ( ctx , & smb_fname_walk ) ;
}
TALLOC_FREE ( frame ) ;
if ( ! NT_STATUS_EQUAL ( status , NT_STATUS_PATH_NOT_COVERED ) ) {
/*
* For any other status than NT_STATUS_PATH_NOT_COVERED
* ( including NT_STATUS_OK ) we exit the walk .
* If it ' s an error we catch it outside the loop .
*/
break ;
}
/* Step back one component and save it off as last_component. */
TALLOC_FREE ( last_component ) ;
p = strrchr ( local_pathname , ' / ' ) ;
if ( p = = NULL ) {
/*
* We removed all components .
* Go around once more to make
* sure we can open the root ' \0 ' .
*/
last_component = talloc_strdup ( ctx , local_pathname ) ;
* local_pathname = ' \0 ' ;
} else {
last_component = talloc_strdup ( ctx , p + 1 ) ;
* p = ' \0 ' ;
}
if ( last_component = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
/* Integer wrap check. */
if ( removed_components + 1 < removed_components ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto out ;
}
removed_components + + ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_DEBUG ( " dfspath = %s. reqpath = %s. Error %s. \n " ,
dfspath ,
reqpath ,
nt_errstr ( status ) ) ;
goto out ;
}
if ( parent_smb_fname - > fsp = = NULL ) {
/* Unable to open parent. */
DBG_DEBUG ( " dfspath = %s. reqpath = %s. "
" Unable to open parent directory (%s). \n " ,
dfspath ,
reqpath ,
smb_fname_str_dbg ( parent_smb_fname ) ) ;
status = NT_STATUS_OBJECT_PATH_NOT_FOUND ;
goto out ;
}
if ( removed_components = = 0 ) {
/*
* We never got NT_STATUS_PATH_NOT_COVERED .
* There was no DFS redirect .
*/
DBG_DEBUG ( " dfspath = %s. reqpath = %s. "
" No removed components. \n " ,
dfspath ,
reqpath ) ;
status = NT_STATUS_OBJECT_PATH_NOT_FOUND ;
goto out ;
}
/*
* One of the removed_components was the MSDFS link
* at the end . We need to count this in the resolved
* path below , so remove one from removed_components .
*/
removed_components - - ;
/*
* Now parent_smb_fname - > fsp is the parent directory dirfsp ,
* last_component is the untranslated MS - DFS link name .
* Search for it in the parent directory to get the real
* filename on disk .
*/
status = get_real_filename_at ( parent_smb_fname - > fsp ,
last_component ,
ctx ,
& atname ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_DEBUG ( " dfspath = %s. reqpath = %s "
" get_real_filename_at(%s, %s) error (%s) \n " ,
dfspath ,
reqpath ,
smb_fname_str_dbg ( parent_smb_fname ) ,
last_component ,
nt_errstr ( status ) ) ;
goto out ;
}
smb_fname_rel = synthetic_smb_fname ( ctx ,
atname ,
NULL ,
NULL ,
twrp ,
posix ? SMB_FILENAME_POSIX_PATH : 0 ) ;
if ( smb_fname_rel = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
/* Get the referral to return. */
status = SMB_VFS_READ_DFS_PATHAT ( conn ,
ctx ,
parent_smb_fname - > fsp ,
smb_fname_rel ,
ppreflist ,
preferral_count ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_DEBUG ( " dfspath = %s. reqpath = %s. "
" SMB_VFS_READ_DFS_PATHAT(%s, %s) error (%s) \n " ,
dfspath ,
reqpath ,
smb_fname_str_dbg ( parent_smb_fname ) ,
smb_fname_str_dbg ( smb_fname_rel ) ,
nt_errstr ( status ) ) ;
goto out ;
}
/*
* Now we must work out how much of the
* given pathname we consumed .
*/
canon_dfspath = talloc_strdup ( ctx , dfspath ) ;
if ( ! canon_dfspath ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
/* Canonicalize the raw dfspath. */
string_replace ( canon_dfspath , ' \\ ' , ' / ' ) ;
/*
* reqpath comes out of parse_dfs_path ( ) , so it has
* no trailing backslash . Make sure that canon_dfspath hasn ' t either .
*/
trim_char ( canon_dfspath , 0 , ' / ' ) ;
DBG_DEBUG ( " Unconsumed path: %s \n " , canon_dfspath ) ;
while ( removed_components > 0 ) {
p = strrchr ( canon_dfspath , ' / ' ) ;
if ( p ! = NULL ) {
* p = ' \0 ' ;
}
removed_components - - ;
if ( p = = NULL & & removed_components ! = 0 ) {
2022-09-09 23:45:38 +03:00
DBG_ERR ( " Component mismatch. path = %s, "
2022-08-09 22:07:30 +03:00
" %zu components left \n " ,
canon_dfspath ,
removed_components ) ;
status = NT_STATUS_OBJECT_PATH_NOT_FOUND ;
goto out ;
}
}
* consumedcntp = strlen ( canon_dfspath ) ;
DBG_DEBUG ( " Path consumed: %s (%zu) \n " , canon_dfspath , * consumedcntp ) ;
status = NT_STATUS_OK ;
out :
TALLOC_FREE ( parent_smb_fname ) ;
TALLOC_FREE ( local_pathname ) ;
TALLOC_FREE ( last_component ) ;
TALLOC_FREE ( atname ) ;
TALLOC_FREE ( smb_fname_rel ) ;
TALLOC_FREE ( canon_dfspath ) ;
return status ;
}
2004-03-18 05:17:23 +03:00
/**********************************************************************
Return a self referral .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-04-04 02:59:55 +04:00
static NTSTATUS self_ref ( TALLOC_CTX * ctx ,
2007-03-12 20:55:24 +03:00
const char * dfs_path ,
struct junction_map * jucn ,
2022-08-04 23:23:28 +03:00
size_t * consumedcntp ,
2007-10-19 04:40:25 +04:00
bool * self_referralp )
2004-03-18 05:17:23 +03:00
{
struct referral * ref ;
2007-03-12 20:55:24 +03:00
* self_referralp = True ;
2004-03-18 05:17:23 +03:00
jucn - > referral_count = 1 ;
2011-06-07 05:44:43 +04:00
if ( ( ref = talloc_zero ( ctx , struct referral ) ) = = NULL ) {
2007-04-04 02:59:55 +04:00
return NT_STATUS_NO_MEMORY ;
2004-03-18 05:17:23 +03:00
}
2007-09-11 22:31:29 +04:00
ref - > alternate_path = talloc_strdup ( ctx , dfs_path ) ;
if ( ! ref - > alternate_path ) {
2012-07-30 16:45:25 +04:00
TALLOC_FREE ( ref ) ;
2007-09-11 22:31:29 +04:00
return NT_STATUS_NO_MEMORY ;
}
2004-03-18 05:17:23 +03:00
ref - > proximity = 0 ;
ref - > ttl = REFERRAL_TTL ;
jucn - > referral_list = ref ;
2007-03-12 20:55:24 +03:00
* consumedcntp = strlen ( dfs_path ) ;
2007-04-04 02:59:55 +04:00
return NT_STATUS_OK ;
2004-03-18 05:17:23 +03:00
}
2002-07-15 14:35:28 +04:00
/**********************************************************************
Gets valid referrals for a dfs path and fills up the
2005-08-03 03:24:32 +04:00
junction_map structure .
2004-03-18 05:17:23 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-10-28 03:51:21 +03:00
2007-04-04 02:59:55 +04:00
NTSTATUS get_referred_path ( TALLOC_CTX * ctx ,
2019-12-13 18:19:03 +03:00
struct auth_session_info * session_info ,
2017-03-21 17:32:37 +03:00
const char * dfs_path ,
const struct tsocket_address * remote_address ,
const struct tsocket_address * local_address ,
struct junction_map * jucn ,
2022-08-04 23:23:28 +03:00
size_t * consumedcntp ,
2017-03-21 17:32:37 +03:00
bool * self_referralp )
2000-03-09 01:14:30 +03:00
{
2018-05-24 18:40:27 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2019-10-31 20:56:10 +03:00
const struct loadparm_substitution * lp_sub =
loadparm_s3_global_substitution ( ) ;
2018-05-24 18:55:02 +03:00
struct conn_struct_tos * c = NULL ;
struct connection_struct * conn = NULL ;
2022-08-10 21:17:49 +03:00
char * servicename = NULL ;
char * reqpath = NULL ;
2002-07-15 14:35:28 +04:00
int snum ;
2007-04-04 02:59:55 +04:00
NTSTATUS status = NT_STATUS_NOT_FOUND ;
2004-03-18 05:17:23 +03:00
2007-03-12 20:55:24 +03:00
* self_referralp = False ;
2002-07-15 14:35:28 +04:00
2022-08-11 07:33:32 +03:00
status = parse_dfs_path_strict (
frame ,
2022-08-10 21:06:47 +03:00
dfs_path ,
2022-08-11 07:33:32 +03:00
NULL , /* hostname */
2022-08-10 21:17:49 +03:00
& servicename ,
& reqpath ) ;
2007-03-12 20:55:24 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2007-04-04 02:59:55 +04:00
return status ;
2007-03-12 20:55:24 +03:00
}
2001-06-30 02:32:24 +04:00
2022-08-12 09:55:58 +03:00
/* Path referrals are always non-POSIX. */
2023-03-31 12:44:00 +03:00
status = check_path_syntax ( reqpath , false ) ;
2022-08-12 09:55:58 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( frame ) ;
return status ;
}
2022-08-10 21:17:49 +03:00
jucn - > service_name = talloc_strdup ( ctx , servicename ) ;
jucn - > volume_name = talloc_strdup ( ctx , reqpath ) ;
2007-09-11 22:31:29 +04:00
if ( ! jucn - > service_name | | ! jucn - > volume_name ) {
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2007-09-11 22:31:29 +04:00
return NT_STATUS_NO_MEMORY ;
}
2002-07-15 14:35:28 +04:00
/* Verify the share is a dfs root */
2004-01-14 09:41:50 +03:00
snum = lp_servicenumber ( jucn - > service_name ) ;
2002-07-15 14:35:28 +04:00
if ( snum < 0 ) {
2010-11-10 02:07:49 +03:00
char * service_name = NULL ;
if ( ( snum = find_service ( ctx , jucn - > service_name , & service_name ) ) < 0 ) {
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2007-04-04 02:59:55 +04:00
return NT_STATUS_NOT_FOUND ;
2005-08-03 03:24:32 +04:00
}
2010-11-10 02:07:49 +03:00
if ( ! service_name ) {
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2010-11-10 02:07:49 +03:00
return NT_STATUS_NO_MEMORY ;
}
2007-09-11 22:31:29 +04:00
TALLOC_FREE ( jucn - > service_name ) ;
jucn - > service_name = talloc_strdup ( ctx , service_name ) ;
if ( ! jucn - > service_name ) {
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2007-09-11 22:31:29 +04:00
return NT_STATUS_NO_MEMORY ;
}
2002-07-15 14:35:28 +04:00
}
2004-03-18 05:17:23 +03:00
2019-10-31 20:56:10 +03:00
if ( ! lp_msdfs_root ( snum ) & & ( * lp_msdfs_proxy ( talloc_tos ( ) , lp_sub , snum ) = = ' \0 ' ) ) {
2007-09-11 22:31:29 +04:00
DEBUG ( 3 , ( " get_referred_path: |%s| in dfs path %s is not "
" a dfs root. \n " ,
2022-08-10 21:17:49 +03:00
servicename , dfs_path ) ) ;
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2007-04-04 02:59:55 +04:00
return NT_STATUS_NOT_FOUND ;
2004-03-25 17:41:56 +03:00
}
2004-03-18 05:17:23 +03:00
/*
* Self referrals are tested with a anonymous IPC connection and
2007-09-11 22:31:29 +04:00
* a GET_DFS_REFERRAL call to \ \ server \ share . ( which means
* dp . reqpath [ 0 ] points to an empty string ) . create_conn_struct cd ' s
* into the directory and will fail if it cannot ( as the anonymous
* user ) . Cope with this .
2004-03-18 05:17:23 +03:00
*/
2022-08-10 21:17:49 +03:00
if ( reqpath [ 0 ] = = ' \0 ' ) {
2007-09-26 03:26:05 +04:00
char * tmp ;
2007-03-12 20:55:24 +03:00
struct referral * ref ;
2019-12-13 20:52:31 +03:00
size_t refcount ;
2004-04-11 14:33:05 +04:00
2019-10-31 20:56:10 +03:00
if ( * lp_msdfs_proxy ( talloc_tos ( ) , lp_sub , snum ) = = ' \0 ' ) {
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2007-03-12 20:55:24 +03:00
return self_ref ( ctx ,
dfs_path ,
jucn ,
consumedcntp ,
self_referralp ) ;
2005-08-03 03:24:32 +04:00
}
2004-04-11 14:33:05 +04:00
2007-09-11 22:31:29 +04:00
/*
2007-03-12 20:55:24 +03:00
* It ' s an msdfs proxy share . Redirect to
* the configured target share .
*/
2018-05-24 18:40:27 +03:00
tmp = talloc_asprintf ( frame , " msdfs:%s " ,
2019-10-31 20:56:10 +03:00
lp_msdfs_proxy ( frame , lp_sub , snum ) ) ;
2013-10-30 17:22:05 +04:00
if ( tmp = = NULL ) {
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2007-04-04 02:59:55 +04:00
return NT_STATUS_NO_MEMORY ;
2002-12-27 23:08:35 +03:00
}
2020-01-28 03:29:46 +03:00
if ( ! parse_msdfs_symlink ( ctx ,
2020-01-28 03:31:52 +03:00
lp_msdfs_shuffle_referrals ( snum ) ,
2020-01-28 03:29:46 +03:00
tmp ,
& ref ,
& refcount ) ) {
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2013-10-30 17:22:05 +04:00
return NT_STATUS_INVALID_PARAMETER ;
2007-09-26 03:26:05 +04:00
}
2013-10-30 17:22:05 +04:00
jucn - > referral_count = refcount ;
2004-01-14 09:41:50 +03:00
jucn - > referral_list = ref ;
2007-03-12 20:55:24 +03:00
* consumedcntp = strlen ( dfs_path ) ;
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2007-04-04 02:59:55 +04:00
return NT_STATUS_OK ;
2002-12-27 23:08:35 +03:00
}
2018-08-21 21:09:16 +03:00
status = create_conn_struct_tos_cwd ( global_messaging_context ( ) ,
2018-05-24 18:55:02 +03:00
snum ,
2019-10-31 21:14:02 +03:00
lp_path ( frame , lp_sub , snum ) ,
2019-12-13 18:19:37 +03:00
session_info ,
2018-05-24 18:55:02 +03:00
& c ) ;
2007-04-04 02:59:55 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2007-04-04 02:59:55 +04:00
return status ;
2005-08-03 03:24:32 +04:00
}
2018-05-24 18:55:02 +03:00
conn = c - > conn ;
2004-04-11 14:33:05 +04:00
2017-03-21 17:45:34 +03:00
/*
* TODO
*
* The remote and local address should be passed down to
* create_conn_struct_cwd .
*/
if ( conn - > sconn - > remote_address = = NULL ) {
conn - > sconn - > remote_address =
tsocket_address_copy ( remote_address , conn - > sconn ) ;
if ( conn - > sconn - > remote_address = = NULL ) {
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2017-03-21 17:45:34 +03:00
return NT_STATUS_NO_MEMORY ;
}
}
if ( conn - > sconn - > local_address = = NULL ) {
conn - > sconn - > local_address =
tsocket_address_copy ( local_address , conn - > sconn ) ;
if ( conn - > sconn - > local_address = = NULL ) {
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2017-03-21 17:45:34 +03:00
return NT_STATUS_NO_MEMORY ;
}
}
2020-02-13 00:17:51 +03:00
status = dfs_path_lookup ( ctx ,
conn ,
dfs_path ,
2022-08-10 21:17:49 +03:00
reqpath ,
2020-02-13 00:17:51 +03:00
0 , /* ucf_flags */
consumedcntp ,
& jucn - > referral_list ,
& jucn - > referral_count ) ;
2007-03-12 20:55:24 +03:00
2022-08-09 22:11:07 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_NOTICE ( " No valid referrals for path %s (%s) \n " ,
dfs_path ,
nt_errstr ( status ) ) ;
2002-07-15 14:35:28 +04:00
}
2007-03-12 20:55:24 +03:00
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2011-03-01 21:17:49 +03:00
return status ;
2000-03-09 01:14:30 +03:00
}
2000-05-18 22:43:53 +04:00
/******************************************************************
2007-03-12 20:55:24 +03:00
Set up the DFS referral for the dfs pathname . This call returns
the amount of the path covered by this server , and where the
client should be redirected to . This is the meat of the
TRANS2_GET_DFS_REFERRAL call .
2005-08-03 03:24:32 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-06-30 02:32:24 +04:00
2007-03-12 20:55:24 +03:00
int setup_dfs_referral ( connection_struct * orig_conn ,
const char * dfs_path ,
int max_referral_level ,
2007-04-04 02:59:55 +04:00
char * * ppdata , NTSTATUS * pstatus )
2000-05-18 22:43:53 +04:00
{
2011-10-01 11:13:50 +04:00
char * pdata = * ppdata ;
2001-06-30 02:32:24 +04:00
int reply_size = 0 ;
2011-10-01 11:13:50 +04:00
struct dfs_GetDFSReferral * r ;
DATA_BLOB blob = data_blob_null ;
NTSTATUS status ;
enum ndr_err_code ndr_err ;
2005-08-03 03:24:32 +04:00
2011-10-01 11:13:50 +04:00
r = talloc_zero ( talloc_tos ( ) , struct dfs_GetDFSReferral ) ;
if ( r = = NULL ) {
2007-04-04 02:59:55 +04:00
* pstatus = NT_STATUS_NO_MEMORY ;
2005-08-03 03:24:32 +04:00
return - 1 ;
}
2000-05-18 22:43:53 +04:00
2011-10-01 11:13:50 +04:00
r - > in . req . max_referral_level = max_referral_level ;
r - > in . req . servername = talloc_strdup ( r , dfs_path ) ;
if ( r - > in . req . servername = = NULL ) {
talloc_free ( r ) ;
2007-09-11 22:31:29 +04:00
* pstatus = NT_STATUS_NO_MEMORY ;
return - 1 ;
}
2002-07-15 14:35:28 +04:00
2011-10-01 11:13:50 +04:00
status = SMB_VFS_GET_DFS_REFERRALS ( orig_conn , r ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( r ) ;
* pstatus = status ;
2007-09-11 22:31:29 +04:00
return - 1 ;
}
2011-10-01 11:13:50 +04:00
ndr_err = ndr_push_struct_blob ( & blob , r ,
r - > out . resp ,
( ndr_push_flags_fn_t ) ndr_push_dfs_referral_resp ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
TALLOC_FREE ( r ) ;
* pstatus = NT_STATUS_INVALID_PARAMETER ;
2002-07-15 14:35:28 +04:00
return - 1 ;
2003-10-28 03:51:21 +03:00
}
2002-12-27 23:08:35 +03:00
2011-10-01 11:13:50 +04:00
pdata = ( char * ) SMB_REALLOC ( pdata , blob . length ) ;
if ( pdata = = NULL ) {
TALLOC_FREE ( r ) ;
DEBUG ( 0 , ( " referral setup: "
" malloc failed for Realloc! \n " ) ) ;
2001-06-30 02:32:24 +04:00
return - 1 ;
2000-03-09 01:14:30 +03:00
}
2011-10-01 11:13:50 +04:00
* ppdata = pdata ;
reply_size = blob . length ;
memcpy ( pdata , blob . data , blob . length ) ;
TALLOC_FREE ( r ) ;
2007-09-11 22:31:29 +04:00
2007-04-04 02:59:55 +04:00
* pstatus = NT_STATUS_OK ;
2001-06-30 02:32:24 +04:00
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
2005-08-03 03:24:32 +04:00
/*********************************************************************
2007-03-12 20:55:24 +03:00
Creates a junction structure from a DFS pathname
2005-08-03 03:24:32 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-03-25 03:58:15 +03:00
2007-10-19 04:40:25 +04:00
bool create_junction ( TALLOC_CTX * ctx ,
2007-09-11 22:31:29 +04:00
const char * dfs_path ,
struct junction_map * jucn )
2002-07-15 14:35:28 +04:00
{
2019-10-15 17:54:45 +03:00
const struct loadparm_substitution * lp_sub =
loadparm_s3_global_substitution ( ) ;
2007-03-12 20:55:24 +03:00
int snum ;
2022-08-10 21:17:49 +03:00
char * servicename = NULL ;
char * reqpath = NULL ;
2007-09-11 22:31:29 +04:00
NTSTATUS status ;
2007-03-12 20:55:24 +03:00
2022-08-11 07:34:29 +03:00
status = parse_dfs_path_strict (
ctx ,
2022-08-10 21:06:47 +03:00
dfs_path ,
2022-08-18 07:50:19 +03:00
NULL ,
2022-08-10 21:17:49 +03:00
& servicename ,
& reqpath ) ;
2007-03-12 20:55:24 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return False ;
}
2002-07-15 14:35:28 +04:00
2005-08-03 03:24:32 +04:00
/* Check for a non-DFS share */
2022-08-10 21:17:49 +03:00
snum = lp_servicenumber ( servicename ) ;
2007-03-12 20:55:24 +03:00
if ( snum < 0 | | ! lp_msdfs_root ( snum ) ) {
DEBUG ( 4 , ( " create_junction: %s is not an msdfs root. \n " ,
2022-08-10 21:17:49 +03:00
servicename ) ) ;
2005-08-03 03:24:32 +04:00
return False ;
}
2002-07-15 14:35:28 +04:00
2022-08-12 09:57:51 +03:00
/* Junction create paths are always non-POSIX. */
2023-03-31 12:44:00 +03:00
status = check_path_syntax ( reqpath , false ) ;
2022-08-12 09:57:51 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return false ;
}
2022-08-10 21:17:49 +03:00
jucn - > service_name = talloc_strdup ( ctx , servicename ) ;
jucn - > volume_name = talloc_strdup ( ctx , reqpath ) ;
2019-10-15 17:54:45 +03:00
jucn - > comment = lp_comment ( ctx , lp_sub , snum ) ;
2007-09-11 22:31:29 +04:00
if ( ! jucn - > service_name | | ! jucn - > volume_name | | ! jucn - > comment ) {
return False ;
}
2005-08-03 03:24:32 +04:00
return True ;
2002-07-15 14:35:28 +04:00
}
/**********************************************************************
2007-09-11 22:31:29 +04:00
Forms a valid Unix pathname from the junction
2002-07-15 14:35:28 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2018-05-24 18:55:02 +03:00
static bool junction_to_local_path_tos ( const struct junction_map * jucn ,
2019-12-13 18:27:51 +03:00
struct auth_session_info * session_info ,
2018-05-24 18:55:02 +03:00
char * * pp_path_out ,
connection_struct * * conn_out )
2002-07-15 14:35:28 +04:00
{
2019-10-31 21:14:02 +03:00
const struct loadparm_substitution * lp_sub =
loadparm_s3_global_substitution ( ) ;
2018-05-24 18:55:02 +03:00
struct conn_struct_tos * c = NULL ;
2002-07-15 14:35:28 +04:00
int snum ;
2018-05-24 18:55:02 +03:00
char * path_out = NULL ;
2008-06-23 00:19:10 +04:00
NTSTATUS status ;
2002-07-15 14:35:28 +04:00
2004-01-14 09:41:50 +03:00
snum = lp_servicenumber ( jucn - > service_name ) ;
2005-08-03 03:24:32 +04:00
if ( snum < 0 ) {
2002-07-15 14:35:28 +04:00
return False ;
2005-08-03 03:24:32 +04:00
}
2018-08-21 21:09:16 +03:00
status = create_conn_struct_tos_cwd ( global_messaging_context ( ) ,
2018-05-24 18:55:02 +03:00
snum ,
2019-10-31 21:14:02 +03:00
lp_path ( talloc_tos ( ) , lp_sub , snum ) ,
2019-12-13 18:19:37 +03:00
session_info ,
2018-05-24 18:55:02 +03:00
& c ) ;
2008-06-23 00:19:10 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2002-07-15 14:35:28 +04:00
return False ;
2005-08-03 03:24:32 +04:00
}
2002-07-15 14:35:28 +04:00
2018-05-24 18:55:02 +03:00
path_out = talloc_asprintf ( c ,
2007-09-11 22:31:29 +04:00
" %s/%s " ,
2019-10-31 21:14:02 +03:00
lp_path ( talloc_tos ( ) , lp_sub , snum ) ,
2007-09-11 22:31:29 +04:00
jucn - > volume_name ) ;
2018-05-24 18:55:02 +03:00
if ( path_out = = NULL ) {
TALLOC_FREE ( c ) ;
2007-09-11 22:31:29 +04:00
return False ;
}
2018-05-24 18:55:02 +03:00
* pp_path_out = path_out ;
* conn_out = c - > conn ;
2002-07-15 14:35:28 +04:00
return True ;
}
2019-12-13 22:48:05 +03:00
/*
* Create a msdfs string in Samba format we can store
* in a filesystem object ( currently a symlink ) .
*/
char * msdfs_link_string ( TALLOC_CTX * ctx ,
const struct referral * reflist ,
size_t referral_count )
2000-05-26 21:10:40 +04:00
{
2019-12-13 22:48:05 +03:00
char * refpath = NULL ;
bool insert_comma = false ;
2007-09-11 22:31:29 +04:00
char * msdfs_link = NULL ;
2019-12-13 22:48:05 +03:00
size_t i ;
2007-09-11 22:31:29 +04:00
2007-03-12 20:55:24 +03:00
/* Form the msdfs_link contents */
2019-12-13 22:48:05 +03:00
msdfs_link = talloc_strdup ( ctx , " msdfs: " ) ;
if ( msdfs_link = = NULL ) {
goto err ;
2007-09-11 22:31:29 +04:00
}
2019-12-13 22:48:05 +03:00
for ( i = 0 ; i < referral_count ; i + + ) {
refpath = talloc_strdup ( ctx , reflist [ i ] . alternate_path ) ;
if ( refpath = = NULL ) {
goto err ;
}
2007-09-11 22:31:29 +04:00
2007-03-12 20:55:24 +03:00
/* Alternate paths always use Windows separators. */
2003-09-05 23:59:55 +04:00
trim_char ( refpath , ' \\ ' , ' \\ ' ) ;
2019-12-13 22:48:05 +03:00
if ( * refpath = = ' \0 ' ) {
2005-08-03 03:24:32 +04:00
if ( i = = 0 ) {
2019-12-13 22:48:05 +03:00
insert_comma = false ;
2005-08-03 03:24:32 +04:00
}
2001-06-30 02:32:24 +04:00
continue ;
2002-07-15 14:35:28 +04:00
}
2005-08-03 03:24:32 +04:00
if ( i > 0 & & insert_comma ) {
2007-09-15 02:27:27 +04:00
msdfs_link = talloc_asprintf_append_buffer ( msdfs_link ,
2007-09-12 03:57:59 +04:00
" ,%s " ,
2007-09-11 22:31:29 +04:00
refpath ) ;
} else {
2007-09-15 02:27:27 +04:00
msdfs_link = talloc_asprintf_append_buffer ( msdfs_link ,
2007-09-12 03:57:59 +04:00
" %s " ,
2007-09-11 22:31:29 +04:00
refpath ) ;
2005-08-03 03:24:32 +04:00
}
2002-07-15 14:35:28 +04:00
2019-12-13 22:48:05 +03:00
if ( msdfs_link = = NULL ) {
goto err ;
2007-09-11 22:31:29 +04:00
}
2019-12-13 22:48:05 +03:00
2005-08-03 03:24:32 +04:00
if ( ! insert_comma ) {
2019-12-13 22:48:05 +03:00
insert_comma = true ;
2005-08-03 03:24:32 +04:00
}
2019-12-13 22:48:05 +03:00
TALLOC_FREE ( refpath ) ;
}
return msdfs_link ;
err :
TALLOC_FREE ( refpath ) ;
TALLOC_FREE ( msdfs_link ) ;
return NULL ;
}
2019-12-13 18:23:38 +03:00
bool create_msdfs_link ( const struct junction_map * jucn ,
struct auth_session_info * session_info )
2019-12-13 22:48:05 +03:00
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
char * path = NULL ;
connection_struct * conn ;
struct smb_filename * smb_fname = NULL ;
2021-01-22 16:47:13 +03:00
struct smb_filename * parent_fname = NULL ;
struct smb_filename * at_fname = NULL ;
2019-12-13 22:48:05 +03:00
bool ok ;
2020-01-10 01:21:46 +03:00
NTSTATUS status ;
bool ret = false ;
2019-12-13 22:48:05 +03:00
2019-12-13 18:27:51 +03:00
ok = junction_to_local_path_tos ( jucn , session_info , & path , & conn ) ;
2019-12-13 22:48:05 +03:00
if ( ! ok ) {
goto out ;
2001-06-30 02:32:24 +04:00
}
2020-02-07 02:55:13 +03:00
if ( ! CAN_WRITE ( conn ) ) {
const struct loadparm_substitution * lp_sub =
loadparm_s3_global_substitution ( ) ;
int snum = lp_servicenumber ( jucn - > service_name ) ;
DBG_WARNING ( " Can't create DFS entry on read-only share %s \n " ,
lp_servicename ( frame , lp_sub , snum ) ) ;
goto out ;
}
2018-05-24 18:40:27 +03:00
smb_fname = synthetic_smb_fname ( frame ,
2017-06-09 02:25:58 +03:00
path ,
NULL ,
NULL ,
2020-04-30 12:48:32 +03:00
0 ,
2017-06-09 02:25:58 +03:00
0 ) ;
if ( smb_fname = = NULL ) {
goto out ;
}
2009-07-02 20:27:44 +04:00
2021-01-22 16:47:13 +03:00
status = parent_pathref ( frame ,
conn - > cwd_fsp ,
smb_fname ,
& parent_fname ,
& at_fname ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto out ;
}
2020-01-10 01:21:46 +03:00
status = SMB_VFS_CREATE_DFS_PATHAT ( conn ,
2021-01-22 16:49:01 +03:00
parent_fname - > fsp ,
at_fname ,
2020-01-10 01:21:46 +03:00
jucn - > referral_list ,
jucn - > referral_count ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
if ( NT_STATUS_EQUAL ( status , NT_STATUS_OBJECT_NAME_COLLISION ) ) {
int retval = SMB_VFS_UNLINKAT ( conn ,
2021-01-22 16:47:13 +03:00
parent_fname - > fsp ,
at_fname ,
2019-09-13 21:17:45 +03:00
0 ) ;
if ( retval ! = 0 ) {
2009-07-02 20:27:44 +04:00
goto out ;
}
2008-06-22 22:33:28 +04:00
}
2020-01-10 01:21:46 +03:00
status = SMB_VFS_CREATE_DFS_PATHAT ( conn ,
2021-01-22 16:49:01 +03:00
parent_fname - > fsp ,
at_fname ,
2020-01-10 01:21:46 +03:00
jucn - > referral_list ,
jucn - > referral_count ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_WARNING ( " SMB_VFS_CREATE_DFS_PATHAT failed "
" %s - Error: %s \n " ,
path ,
nt_errstr ( status ) ) ;
2003-08-08 09:10:12 +04:00
goto out ;
2005-08-03 03:24:32 +04:00
}
}
2001-06-30 02:32:24 +04:00
2020-01-10 01:21:46 +03:00
ret = true ;
2007-03-12 20:55:24 +03:00
2003-08-08 09:10:12 +04:00
out :
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2003-08-08 09:10:12 +04:00
return ret ;
2000-05-26 21:10:40 +04:00
}
2019-12-13 18:25:44 +03:00
bool remove_msdfs_link ( const struct junction_map * jucn ,
struct auth_session_info * session_info )
2000-05-26 21:10:40 +04:00
{
2018-05-24 18:40:27 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2007-09-11 22:31:29 +04:00
char * path = NULL ;
2008-04-28 12:31:49 +04:00
connection_struct * conn ;
2007-10-19 04:40:25 +04:00
bool ret = False ;
2013-04-15 13:08:15 +04:00
struct smb_filename * smb_fname ;
2021-01-22 16:51:33 +03:00
struct smb_filename * parent_fname = NULL ;
struct smb_filename * at_fname = NULL ;
NTSTATUS status ;
2018-05-24 18:55:02 +03:00
bool ok ;
2019-09-13 21:20:36 +03:00
int retval ;
2000-05-26 21:10:40 +04:00
2019-12-13 18:27:51 +03:00
ok = junction_to_local_path_tos ( jucn , session_info , & path , & conn ) ;
2018-05-24 18:55:02 +03:00
if ( ! ok ) {
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2008-06-23 00:19:10 +04:00
return false ;
}
2020-02-07 03:20:59 +03:00
if ( ! CAN_WRITE ( conn ) ) {
const struct loadparm_substitution * lp_sub =
loadparm_s3_global_substitution ( ) ;
int snum = lp_servicenumber ( jucn - > service_name ) ;
DBG_WARNING ( " Can't remove DFS entry on read-only share %s \n " ,
lp_servicename ( frame , lp_sub , snum ) ) ;
TALLOC_FREE ( frame ) ;
return false ;
}
2018-05-24 18:40:27 +03:00
smb_fname = synthetic_smb_fname ( frame ,
2016-03-19 07:19:38 +03:00
path ,
NULL ,
NULL ,
2020-04-30 12:48:32 +03:00
0 ,
2016-03-19 07:19:38 +03:00
0 ) ;
2013-04-15 13:08:15 +04:00
if ( smb_fname = = NULL ) {
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2013-04-15 13:08:15 +04:00
errno = ENOMEM ;
2009-07-02 20:27:44 +04:00
return false ;
}
2021-01-22 16:51:33 +03:00
status = parent_pathref ( frame ,
conn - > cwd_fsp ,
smb_fname ,
& parent_fname ,
& at_fname ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( frame ) ;
return false ;
}
2019-09-13 21:20:36 +03:00
retval = SMB_VFS_UNLINKAT ( conn ,
2021-01-22 16:51:33 +03:00
parent_fname - > fsp ,
at_fname ,
2019-09-13 21:20:36 +03:00
0 ) ;
if ( retval = = 0 ) {
2008-06-23 00:19:10 +04:00
ret = True ;
2003-08-08 09:10:12 +04:00
}
2005-08-03 03:24:32 +04:00
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2003-08-08 09:10:12 +04:00
return ret ;
2000-05-26 21:10:40 +04:00
}
2000-05-16 05:13:16 +04:00
2007-09-11 22:31:29 +04:00
/*********************************************************************
Return the number of DFS links at the root of this share .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2019-12-13 18:51:16 +03:00
static size_t count_dfs_links ( TALLOC_CTX * ctx ,
struct auth_session_info * session_info ,
int snum )
2007-09-11 22:31:29 +04:00
{
2018-05-24 18:40:27 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2019-10-31 20:56:10 +03:00
const struct loadparm_substitution * lp_sub =
loadparm_s3_global_substitution ( ) ;
2007-09-11 22:31:29 +04:00
size_t cnt = 0 ;
2009-11-16 11:49:23 +03:00
const char * dname = NULL ;
char * talloced = NULL ;
2019-10-31 21:14:02 +03:00
const char * connect_path = lp_path ( frame , lp_sub , snum ) ;
2019-10-31 20:56:10 +03:00
const char * msdfs_proxy = lp_msdfs_proxy ( frame , lp_sub , snum ) ;
2018-05-24 18:55:02 +03:00
struct conn_struct_tos * c = NULL ;
connection_struct * conn = NULL ;
2008-06-23 00:19:10 +04:00
NTSTATUS status ;
2016-02-27 01:53:12 +03:00
struct smb_filename * smb_fname = NULL ;
2020-03-18 14:05:06 +03:00
struct smb_Dir * dir_hnd = NULL ;
2007-09-11 22:31:29 +04:00
if ( * connect_path = = ' \0 ' ) {
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2007-09-11 22:31:29 +04:00
return 0 ;
}
/*
* Fake up a connection struct for the VFS layer .
*/
2018-08-21 21:09:16 +03:00
status = create_conn_struct_tos_cwd ( global_messaging_context ( ) ,
2018-05-24 18:55:02 +03:00
snum ,
connect_path ,
2019-12-13 18:19:37 +03:00
session_info ,
2018-05-24 18:55:02 +03:00
& c ) ;
2008-06-23 00:19:10 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 3 , ( " create_conn_struct failed: %s \n " ,
nt_errstr ( status ) ) ) ;
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2007-09-11 22:31:29 +04:00
return 0 ;
}
2018-05-24 18:55:02 +03:00
conn = c - > conn ;
2007-09-11 22:31:29 +04:00
/* Count a link for the msdfs root - convention */
cnt = 1 ;
/* No more links if this is an msdfs proxy. */
if ( * msdfs_proxy ! = ' \0 ' ) {
goto out ;
}
2018-05-24 18:40:27 +03:00
smb_fname = synthetic_smb_fname ( frame ,
2016-02-27 01:53:12 +03:00
" . " ,
NULL ,
2016-03-19 07:19:38 +03:00
NULL ,
2020-04-30 12:48:32 +03:00
0 ,
2016-03-19 07:19:38 +03:00
0 ) ;
2016-02-27 01:53:12 +03:00
if ( smb_fname = = NULL ) {
goto out ;
}
2007-09-11 22:31:29 +04:00
/* Now enumerate all dfs links */
2022-03-01 01:34:48 +03:00
status = OpenDir ( frame ,
conn ,
smb_fname ,
NULL ,
0 ,
& dir_hnd ) ;
2022-03-01 01:24:19 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
errno = map_errno_from_nt_status ( status ) ;
2007-09-11 22:31:29 +04:00
goto out ;
}
2023-06-20 13:25:45 +03:00
while ( ( dname = ReadDirName ( dir_hnd , & talloced ) ) ! = NULL ) {
2017-06-08 01:03:37 +03:00
struct smb_filename * smb_dname =
2018-05-24 18:40:27 +03:00
synthetic_smb_fname ( frame ,
2017-06-08 01:03:37 +03:00
dname ,
NULL ,
NULL ,
2020-04-30 12:48:32 +03:00
0 ,
2017-06-08 01:03:37 +03:00
0 ) ;
if ( smb_dname = = NULL ) {
goto out ;
}
2021-07-13 03:44:10 +03:00
if ( is_msdfs_link ( dir_hnd_fetch_fsp ( dir_hnd ) , smb_dname ) ) {
2019-12-13 20:39:55 +03:00
if ( cnt + 1 < cnt ) {
cnt = 0 ;
goto out ;
}
2007-09-11 22:31:29 +04:00
cnt + + ;
}
2009-11-16 11:49:23 +03:00
TALLOC_FREE ( talloced ) ;
2017-06-08 01:03:37 +03:00
TALLOC_FREE ( smb_dname ) ;
2007-09-11 22:31:29 +04:00
}
out :
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2007-09-11 22:31:29 +04:00
return cnt ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-03-12 20:55:24 +03:00
static int form_junctions ( TALLOC_CTX * ctx ,
2019-12-13 18:53:36 +03:00
struct auth_session_info * session_info ,
2007-03-12 20:55:24 +03:00
int snum ,
struct junction_map * jucn ,
2007-09-11 22:31:29 +04:00
size_t jn_remain )
2000-05-18 22:43:53 +04:00
{
2018-05-24 18:40:27 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2019-10-31 20:56:10 +03:00
const struct loadparm_substitution * lp_sub =
loadparm_s3_global_substitution ( ) ;
2007-09-11 22:31:29 +04:00
size_t cnt = 0 ;
2009-11-16 11:49:23 +03:00
const char * dname = NULL ;
char * talloced = NULL ;
2019-10-31 21:14:02 +03:00
const char * connect_path = lp_path ( frame , lp_sub , snum ) ;
2019-11-07 13:01:05 +03:00
char * service_name = lp_servicename ( frame , lp_sub , snum ) ;
2019-10-31 20:56:10 +03:00
const char * msdfs_proxy = lp_msdfs_proxy ( frame , lp_sub , snum ) ;
2018-05-24 18:55:02 +03:00
struct conn_struct_tos * c = NULL ;
connection_struct * conn = NULL ;
2002-12-28 03:18:23 +03:00
struct referral * ref = NULL ;
2016-02-27 01:53:12 +03:00
struct smb_filename * smb_fname = NULL ;
2020-03-18 18:12:09 +03:00
struct smb_Dir * dir_hnd = NULL ;
2008-06-23 00:19:10 +04:00
NTSTATUS status ;
2007-09-11 22:31:29 +04:00
if ( jn_remain = = 0 ) {
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2005-08-03 03:24:32 +04:00
return 0 ;
}
2005-06-28 23:25:48 +04:00
2005-08-03 03:24:32 +04:00
if ( * connect_path = = ' \0 ' ) {
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2005-06-28 23:25:48 +04:00
return 0 ;
2005-08-03 03:24:32 +04:00
}
2001-06-30 02:32:24 +04:00
/*
* Fake up a connection struct for the VFS layer .
*/
2018-08-21 21:09:16 +03:00
status = create_conn_struct_tos_cwd ( global_messaging_context ( ) ,
2018-05-24 18:55:02 +03:00
snum ,
connect_path ,
2019-12-13 18:19:37 +03:00
session_info ,
2018-05-24 18:55:02 +03:00
& c ) ;
2008-06-23 00:19:10 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 3 , ( " create_conn_struct failed: %s \n " ,
nt_errstr ( status ) ) ) ;
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2005-06-28 23:25:48 +04:00
return 0 ;
2005-08-03 03:24:32 +04:00
}
2018-05-24 18:55:02 +03:00
conn = c - > conn ;
2001-06-30 02:32:24 +04:00
2007-09-11 22:31:29 +04:00
/* form a junction for the msdfs root - convention
2002-12-28 03:18:23 +03:00
DO NOT REMOVE THIS : NT clients will not work with us
if this is not present
2007-09-11 22:31:29 +04:00
*/
jucn [ cnt ] . service_name = talloc_strdup ( ctx , service_name ) ;
jucn [ cnt ] . volume_name = talloc_strdup ( ctx , " " ) ;
2008-05-05 14:45:12 +04:00
if ( ! jucn [ cnt ] . service_name | | ! jucn [ cnt ] . volume_name ) {
2007-09-11 22:31:29 +04:00
goto out ;
}
2008-06-22 15:06:35 +04:00
jucn [ cnt ] . comment = " " ;
2004-01-14 09:41:50 +03:00
jucn [ cnt ] . referral_count = 1 ;
2002-12-28 03:18:23 +03:00
2011-06-07 05:44:43 +04:00
ref = jucn [ cnt ] . referral_list = talloc_zero ( ctx , struct referral ) ;
2004-01-14 09:41:50 +03:00
if ( jucn [ cnt ] . referral_list = = NULL ) {
2003-08-08 09:10:12 +04:00
goto out ;
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 ;
2007-09-11 22:31:29 +04:00
if ( * msdfs_proxy ! = ' \0 ' ) {
ref - > alternate_path = talloc_strdup ( ctx ,
msdfs_proxy ) ;
} else {
ref - > alternate_path = talloc_asprintf ( ctx ,
" \\ \\ %s \\ %s " ,
2007-03-12 20:55:24 +03:00
get_local_machine_name ( ) ,
service_name ) ;
2007-09-11 22:31:29 +04:00
}
if ( ! ref - > alternate_path ) {
goto out ;
}
2002-12-28 03:18:23 +03:00
cnt + + ;
2005-06-28 23:25:48 +04:00
2007-09-11 22:31:29 +04:00
/* Don't enumerate if we're an msdfs proxy. */
if ( * msdfs_proxy ! = ' \0 ' ) {
goto out ;
}
2018-05-24 18:40:27 +03:00
smb_fname = synthetic_smb_fname ( frame ,
2016-02-27 01:53:12 +03:00
" . " ,
NULL ,
2016-03-19 07:19:38 +03:00
NULL ,
2020-04-30 12:48:32 +03:00
0 ,
2016-03-19 07:19:38 +03:00
0 ) ;
2016-02-27 01:53:12 +03:00
if ( smb_fname = = NULL ) {
goto out ;
}
2002-12-28 03:18:23 +03:00
/* Now enumerate all dfs links */
2022-03-01 01:34:48 +03:00
status = OpenDir ( frame ,
conn ,
smb_fname ,
NULL ,
0 ,
& dir_hnd ) ;
2022-03-01 01:25:25 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
errno = map_errno_from_nt_status ( status ) ;
2003-08-08 09:10:12 +04:00
goto out ;
2005-08-03 03:24:32 +04:00
}
2001-06-30 02:32:24 +04:00
2023-06-20 13:25:45 +03:00
while ( ( dname = ReadDirName ( dir_hnd , & talloced ) ) ! = NULL ) {
2017-06-08 01:03:37 +03:00
struct smb_filename * smb_dname = NULL ;
2005-06-28 23:25:48 +04:00
if ( cnt > = jn_remain ) {
2007-09-11 22:31:29 +04:00
DEBUG ( 2 , ( " form_junctions: ran out of MSDFS "
2023-08-07 07:50:39 +03:00
" junction slots \n " ) ) ;
2009-11-16 11:49:23 +03:00
TALLOC_FREE ( talloced ) ;
2005-06-28 23:25:48 +04:00
goto out ;
}
2017-06-08 01:03:37 +03:00
smb_dname = synthetic_smb_fname ( talloc_tos ( ) ,
dname ,
NULL ,
NULL ,
2020-04-30 12:48:32 +03:00
0 ,
2017-06-08 01:03:37 +03:00
0 ) ;
if ( smb_dname = = NULL ) {
TALLOC_FREE ( talloced ) ;
goto out ;
}
2020-02-13 00:52:58 +03:00
status = SMB_VFS_READ_DFS_PATHAT ( conn ,
ctx ,
conn - > cwd_fsp ,
smb_dname ,
& jucn [ cnt ] . referral_list ,
& jucn [ cnt ] . referral_count ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
jucn [ cnt ] . service_name = talloc_strdup ( ctx ,
service_name ) ;
jucn [ cnt ] . volume_name = talloc_strdup ( ctx , dname ) ;
if ( ! jucn [ cnt ] . service_name | | ! jucn [ cnt ] . volume_name ) {
TALLOC_FREE ( talloced ) ;
goto out ;
2007-03-12 20:55:24 +03:00
}
2020-02-13 00:52:58 +03:00
jucn [ cnt ] . comment = " " ;
cnt + + ;
2001-06-30 02:32:24 +04:00
}
2009-11-16 11:49:23 +03:00
TALLOC_FREE ( talloced ) ;
2017-06-08 01:03:37 +03:00
TALLOC_FREE ( smb_dname ) ;
2000-05-18 22:43:53 +04:00
}
2005-08-03 03:24:32 +04:00
2003-08-08 09:10:12 +04:00
out :
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2005-06-28 23:25:48 +04:00
return cnt ;
2000-05-18 22:43:53 +04:00
}
2019-12-13 18:31:04 +03:00
struct junction_map * enum_msdfs_links ( TALLOC_CTX * ctx ,
struct auth_session_info * session_info ,
size_t * p_num_jn )
2000-05-18 22:43:53 +04:00
{
2007-09-11 22:31:29 +04:00
struct junction_map * jn = NULL ;
2001-06-30 02:32:24 +04:00
int i = 0 ;
2007-09-16 00:24:35 +04:00
size_t jn_count = 0 ;
2006-02-04 01:19:41 +03:00
int sharecount = 0 ;
2001-06-30 02:32:24 +04:00
2007-09-11 22:31:29 +04:00
* p_num_jn = 0 ;
2005-08-03 03:24:32 +04:00
if ( ! lp_host_msdfs ( ) ) {
2007-09-11 22:31:29 +04:00
return NULL ;
2005-08-03 03:24:32 +04:00
}
2001-06-30 02:32:24 +04:00
2006-02-04 01:19:41 +03:00
/* Ensure all the usershares are loaded. */
become_root ( ) ;
2006-11-30 10:38:40 +03:00
load_registry_shares ( ) ;
2011-12-13 15:24:03 +04:00
sharecount = load_usershare_shares ( NULL , connections_snum_used ) ;
2006-02-04 01:19:41 +03:00
unbecome_root ( ) ;
2007-09-11 22:31:29 +04:00
for ( i = 0 ; i < sharecount ; i + + ) {
2005-08-03 03:24:32 +04:00
if ( lp_msdfs_root ( i ) ) {
2019-12-13 18:51:16 +03:00
jn_count + = count_dfs_links ( ctx , session_info , i ) ;
2005-08-03 03:24:32 +04:00
}
2001-06-30 02:32:24 +04:00
}
2007-09-11 22:31:29 +04:00
if ( jn_count = = 0 ) {
return NULL ;
}
2011-06-07 05:30:12 +04:00
jn = talloc_array ( ctx , struct junction_map , jn_count ) ;
2007-09-11 22:31:29 +04:00
if ( ! jn ) {
return NULL ;
}
for ( i = 0 ; i < sharecount ; i + + ) {
if ( * p_num_jn > = jn_count ) {
break ;
}
if ( lp_msdfs_root ( i ) ) {
2019-12-13 18:53:36 +03:00
* p_num_jn + = form_junctions ( ctx ,
session_info ,
i ,
2007-09-11 22:31:29 +04:00
& jn [ * p_num_jn ] ,
jn_count - * p_num_jn ) ;
}
}
return jn ;
2000-05-18 22:43:53 +04:00
}