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
2000-05-18 22:43:53 +04:00
/**********************************************************************
2022-08-04 19:52:17 +03:00
Parse a DFS pathname of the form / hostname / service / reqpath
2007-03-12 20:55:24 +03:00
into the dfs_path structure .
2022-08-04 19:52:17 +03:00
NB . srvstr_get_path_internal ( ) now * always * calls
check_path_syntax_XXX ( ) on an incoming name , so
the path separator is now always ' / ' , even from
Windows clients .
2007-03-12 20:55:24 +03:00
Unfortunately , due to broken clients who might set the
SVAL ( inbuf , smb_flg2 ) & FLAGS2_DFS_PATHNAMES bit and then
send a local path , we have to cope with that too . . . .
2008-05-20 00:11:00 +04:00
If conn ! = NULL then ensure the provided service is
the one pointed to by the connection .
2007-09-11 22:31:29 +04:00
This version does everything using pointers within one copy of the
pathname string , talloced on the struct dfs_path pointer ( which
must be talloced ) . This may be too clever to live . . . .
2007-03-12 20:55:24 +03:00
JRA .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-06-30 02:32:24 +04:00
2008-05-20 00:11:00 +04:00
static NTSTATUS parse_dfs_path ( connection_struct * conn ,
const char * pathname ,
2011-09-24 07:28:08 +04:00
bool allow_broken_path ,
2020-09-30 03:14:22 +03:00
struct dfs_path * pdp ) /* MUST BE TALLOCED */
2000-03-09 01:14:30 +03:00
{
2019-11-07 13:01:05 +03:00
const struct loadparm_substitution * lp_sub =
loadparm_s3_global_substitution ( ) ;
2007-09-11 22:31:29 +04:00
char * pathname_local ;
2022-08-04 19:52:17 +03:00
char * p ;
2008-05-14 02:02:11 +04:00
char * servicename ;
2007-09-11 22:31:29 +04:00
char * eos_ptr ;
2007-03-12 20:55:24 +03:00
ZERO_STRUCTP ( pdp ) ;
2001-06-30 02:32:24 +04:00
2007-09-11 22:31:29 +04:00
/*
* This is the only talloc we should need to do
* on the struct dfs_path . All the pointers inside
* it should point to offsets within this string .
*/
pathname_local = talloc_strdup ( pdp , pathname ) ;
2022-08-04 19:52:17 +03:00
if ( pathname_local = = NULL ) {
2007-09-11 22:31:29 +04:00
return NT_STATUS_NO_MEMORY ;
}
2022-08-04 19:52:17 +03:00
/*
* parse_dfs_path ( ) can be called from
* get_referred_path ( ) and create_junction ( )
* which use Windows DFS paths of \ server \ share .
* Ensure we only have to cope with ' / ' separators .
*/
string_replace ( pathname_local , ' \\ ' , ' / ' ) ;
2007-09-11 22:31:29 +04:00
/* Get a pointer to the terminating '\0' */
eos_ptr = & pathname_local [ strlen ( pathname_local ) ] ;
2022-08-04 19:52:17 +03:00
p = pathname_local ;
2001-06-30 02:32:24 +04:00
2016-03-20 07:04:09 +03:00
/*
* Non - broken DFS paths * must * start with the
2022-08-04 19:52:17 +03:00
* path separator ' / ' .
2016-03-20 07:04:09 +03:00
*/
2001-06-30 02:32:24 +04:00
2022-08-04 19:52:17 +03:00
if ( allow_broken_path & & ( * p ! = ' / ' ) ) {
DBG_ERR ( " path %s doesn't start with / \n " , p ) ;
2007-03-12 20:55:24 +03:00
/*
* Possibly client sent a local path by mistake .
* Try and convert to a local path .
2016-03-20 07:04:09 +03:00
* Note that this is an SMB1 - only fallback
* to cope with known broken SMB1 clients .
2007-03-12 20:55:24 +03:00
*/
2001-06-30 02:32:24 +04:00
2007-09-11 22:31:29 +04:00
pdp - > hostname = eos_ptr ; /* "" */
pdp - > servicename = eos_ptr ; /* "" */
2007-03-12 20:55:24 +03:00
2022-08-04 19:52:17 +03:00
DBG_ERR ( " trying to convert %s to a local path \n " , p ) ;
2007-03-12 20:55:24 +03:00
goto local_path ;
2001-06-30 02:32:24 +04:00
}
2007-09-11 22:31:29 +04:00
/*
* Safe to use on talloc ' ed string as it only shrinks .
* It also doesn ' t affect the eos_ptr .
*/
2022-08-04 19:52:17 +03:00
trim_char ( p , ' / ' , ' / ' ) ;
2001-06-30 02:32:24 +04:00
2022-08-04 19:52:17 +03:00
DBG_ERR ( " p = |%s| after trimming /'s \n " , p ) ;
2004-03-10 05:38:39 +03:00
2007-03-12 20:55:24 +03:00
/* Now tokenize. */
/* Parse out hostname. */
2022-08-04 19:52:17 +03:00
p = strchr ( p , ' / ' ) ;
2007-03-12 20:55:24 +03:00
if ( p = = NULL ) {
2022-08-04 19:52:17 +03:00
DBG_ERR ( " can't parse hostname from path %s \n " , pathname_local ) ;
2007-03-12 20:55:24 +03:00
/*
* Possibly client sent a local path by mistake .
* Try and convert to a local path .
*/
2004-03-10 05:38:39 +03:00
2007-09-11 22:31:29 +04:00
pdp - > hostname = eos_ptr ; /* "" */
pdp - > servicename = eos_ptr ; /* "" */
2004-03-10 05:38:39 +03:00
2022-08-04 19:52:17 +03:00
p = pathname_local ;
DBG_ERR ( " trying to convert %s to a local path \n " , p ) ;
2007-03-12 20:55:24 +03:00
goto local_path ;
}
* p = ' \0 ' ;
2022-08-04 19:52:17 +03:00
pdp - > hostname = pathname_local ;
2007-09-11 22:31:29 +04:00
2022-08-04 19:52:17 +03:00
DBG_ERR ( " hostname: %s \n " , pdp - > hostname ) ;
2004-03-10 05:38:39 +03:00
2007-03-12 20:55:24 +03:00
/* Parse out servicename. */
2008-05-14 02:02:11 +04:00
servicename = p + 1 ;
2022-08-04 19:52:17 +03:00
p = strchr ( servicename , ' / ' ) ;
2008-05-14 02:02:11 +04:00
if ( p ) {
* p = ' \0 ' ;
}
/* Is this really our servicename ? */
2019-11-07 13:01:05 +03:00
if ( conn & & ! ( strequal ( servicename , lp_servicename ( talloc_tos ( ) , lp_sub , SNUM ( conn ) ) )
2008-05-20 00:11:00 +04:00
| | ( strequal ( servicename , HOMES_NAME )
2019-11-07 13:01:05 +03:00
& & strequal ( lp_servicename ( talloc_tos ( ) , lp_sub , SNUM ( conn ) ) ,
2008-05-20 00:11:00 +04:00
get_current_username ( ) ) ) ) ) {
2022-08-04 19:52:17 +03:00
DBG_ERR ( " %s is not our servicename \n " , servicename ) ;
2008-05-14 02:02:11 +04:00
/*
* Possibly client sent a local path by mistake .
* Try and convert to a local path .
*/
pdp - > hostname = eos_ptr ; /* "" */
pdp - > servicename = eos_ptr ; /* "" */
/* Repair the path - replace the sepchar's
we nulled out */
servicename - - ;
2022-08-04 19:52:17 +03:00
* servicename = ' / ' ;
2008-05-14 02:02:11 +04:00
if ( p ) {
2022-08-04 19:52:17 +03:00
* p = ' / ' ;
2008-05-14 02:02:11 +04:00
}
2022-08-04 19:52:17 +03:00
p = pathname_local ;
DBG_ERR ( " trying to convert %s to a local path \n " ,
pathname_local ) ;
2008-05-14 02:02:11 +04:00
goto local_path ;
}
pdp - > servicename = servicename ;
2022-08-04 19:52:17 +03:00
DBG_ERR ( " servicename: %s \n " , pdp - > servicename ) ;
2008-05-14 02:25:26 +04:00
2004-03-10 05:38:39 +03:00
if ( p = = NULL ) {
2008-05-14 02:02:11 +04:00
/* Client sent self referral \server\share. */
2007-09-11 22:31:29 +04:00
pdp - > reqpath = eos_ptr ; /* "" */
2007-03-12 20:55:24 +03:00
return NT_STATUS_OK ;
2004-03-10 05:38:39 +03:00
}
2008-05-14 02:02:11 +04:00
2007-03-12 20:55:24 +03:00
p + + ;
local_path :
2004-03-10 05:38:39 +03:00
2022-08-04 19:52:17 +03:00
/*
* As check_path_syntax_XXX ( ) has already been
* called we know this is a normal path containing
* ' / ' separators .
*/
2007-03-12 20:55:24 +03:00
2022-08-04 19:52:17 +03:00
pdp - > reqpath = p ;
DBG_ERR ( " rest of the path: %s \n " , pdp - > reqpath ) ;
2007-03-12 20:55:24 +03:00
return NT_STATUS_OK ;
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
}
2002-07-15 14:35:28 +04:00
/*****************************************************************
Used by other functions to decide if a dfs path is remote ,
2007-03-12 20:55:24 +03:00
and to get the list of referred locations for that remote path .
2007-09-11 22:31:29 +04:00
2007-03-12 20:55:24 +03:00
consumedcntp : how much of the dfs path is being redirected . the client
should try the remaining path on the redirected server .
2005-08-03 03:24:32 +04:00
2007-03-12 20:55:24 +03:00
If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
link redirect are in targetpath .
2002-07-15 14:35:28 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-10-28 03:51:21 +03:00
2007-09-11 22:31:29 +04:00
static NTSTATUS dfs_path_lookup ( TALLOC_CTX * ctx ,
connection_struct * conn ,
const char * dfspath , /* Incoming complete dfs path */
const struct dfs_path * pdp , /* Parsed out
server + share + extrapath . */
2016-03-25 21:34:30 +03:00
uint32_t ucf_flags ,
2021-12-04 03:00:26 +03:00
NTTIME * _twrp ,
2022-08-04 23:23:28 +03:00
size_t * consumedcntp ,
2020-02-13 00:17:51 +03:00
struct referral * * ppreflist ,
size_t * preferral_count )
2002-07-15 14:35:28 +04:00
{
2007-03-12 20:55:24 +03:00
char * p = NULL ;
char * q = NULL ;
2007-01-13 02:47:16 +03:00
NTSTATUS status ;
s3: Change unix_convert (and its callers) to use struct smb_filename
This is the first of a series of patches that change path based
operations to operate on a struct smb_filename instead of a char *.
This same concept already exists in source4.
My goals for this series of patches are to eventually:
1) Solve the stream vs. posix filename that contains a colon ambiguity
that currently exists.
2) Make unix_convert the only function that parses the stream name.
3) Clean up the unix_convert API.
4) Change all path based vfs operation to take a struct smb_filename.
5) Make is_ntfs_stream_name() a constant operation that can simply
check the state of struct smb_filename rather than re-parse the
filename.
6) Eliminate the need for split_ntfs_stream_name() to exist.
My strategy is to start from the inside at unix_convert() and work my
way out through the vfs layer, call by call. This first patch does
just that, by changing unix_convert and all of its callers to operate
on struct smb_filename. Since this is such a large change, I plan on
pushing the patches in phases, where each phase keeps full
compatibility and passes make test.
The API of unix_convert has been simplified from:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
bool allow_wcard_last_component,
char **pp_conv_path,
char **pp_saved_last_component,
SMB_STRUCT_STAT *pst)
to:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
struct smb_filename *smb_fname,
uint32_t ucf_flags)
Currently the smb_filename struct looks like:
struct smb_filename {
char *base_name;
char *stream_name;
char *original_lcomp;
SMB_STRUCT_STAT st;
};
One key point here is the decision to break up the base_name and
stream_name. I have introduced a helper function called
get_full_smb_filename() that takes an smb_filename struct and
allocates the full_name. I changed the callers of unix_convert() to
subsequently call get_full_smb_filename() for the time being, but I
plan to eventually eliminate get_full_smb_filename().
2009-04-08 00:39:57 +04:00
struct smb_filename * smb_fname = NULL ;
2021-07-13 03:53:19 +03:00
struct smb_filename * parent_fname = NULL ;
struct smb_filename * atname = NULL ;
2007-09-11 22:31:29 +04:00
char * canon_dfspath = NULL ; /* Canonicalized dfs path. (only '/'
components ) . */
2002-07-15 14:35:28 +04:00
2007-03-12 20:55:24 +03:00
DEBUG ( 10 , ( " dfs_path_lookup: Conn path = %s reqpath = %s \n " ,
conn - > connectpath , pdp - > reqpath ) ) ;
2003-10-28 03:51:21 +03:00
2007-09-11 22:31:29 +04:00
/*
2011-10-01 00:35:59 +04:00
* Note the unix path conversion here we ' re doing we
2007-02-08 01:20:31 +03:00
* throw away . We ' re looking for a symlink for a dfs
* resolution , if we don ' t find it we ' ll do another
* unix_convert later in the codepath .
*/
2007-01-13 02:47:16 +03:00
2020-04-30 17:04:54 +03:00
status = unix_convert ( ctx , conn , pdp - > reqpath , 0 , & smb_fname ,
2016-03-25 21:34:30 +03:00
ucf_flags ) ;
s3: Change unix_convert (and its callers) to use struct smb_filename
This is the first of a series of patches that change path based
operations to operate on a struct smb_filename instead of a char *.
This same concept already exists in source4.
My goals for this series of patches are to eventually:
1) Solve the stream vs. posix filename that contains a colon ambiguity
that currently exists.
2) Make unix_convert the only function that parses the stream name.
3) Clean up the unix_convert API.
4) Change all path based vfs operation to take a struct smb_filename.
5) Make is_ntfs_stream_name() a constant operation that can simply
check the state of struct smb_filename rather than re-parse the
filename.
6) Eliminate the need for split_ntfs_stream_name() to exist.
My strategy is to start from the inside at unix_convert() and work my
way out through the vfs layer, call by call. This first patch does
just that, by changing unix_convert and all of its callers to operate
on struct smb_filename. Since this is such a large change, I plan on
pushing the patches in phases, where each phase keeps full
compatibility and passes make test.
The API of unix_convert has been simplified from:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
bool allow_wcard_last_component,
char **pp_conv_path,
char **pp_saved_last_component,
SMB_STRUCT_STAT *pst)
to:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
struct smb_filename *smb_fname,
uint32_t ucf_flags)
Currently the smb_filename struct looks like:
struct smb_filename {
char *base_name;
char *stream_name;
char *original_lcomp;
SMB_STRUCT_STAT st;
};
One key point here is the decision to break up the base_name and
stream_name. I have introduced a helper function called
get_full_smb_filename() that takes an smb_filename struct and
allocates the full_name. I changed the callers of unix_convert() to
subsequently call get_full_smb_filename() for the time being, but I
plan to eventually eliminate get_full_smb_filename().
2009-04-08 00:39:57 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-07-25 03:05:44 +04:00
if ( ! NT_STATUS_EQUAL ( status ,
NT_STATUS_OBJECT_PATH_NOT_FOUND ) ) {
return status ;
}
2011-10-01 00:35:59 +04:00
if ( smb_fname = = NULL | | smb_fname - > base_name = = NULL ) {
2009-07-25 03:05:44 +04:00
return status ;
}
}
s3: Change unix_convert (and its callers) to use struct smb_filename
This is the first of a series of patches that change path based
operations to operate on a struct smb_filename instead of a char *.
This same concept already exists in source4.
My goals for this series of patches are to eventually:
1) Solve the stream vs. posix filename that contains a colon ambiguity
that currently exists.
2) Make unix_convert the only function that parses the stream name.
3) Clean up the unix_convert API.
4) Change all path based vfs operation to take a struct smb_filename.
5) Make is_ntfs_stream_name() a constant operation that can simply
check the state of struct smb_filename rather than re-parse the
filename.
6) Eliminate the need for split_ntfs_stream_name() to exist.
My strategy is to start from the inside at unix_convert() and work my
way out through the vfs layer, call by call. This first patch does
just that, by changing unix_convert and all of its callers to operate
on struct smb_filename. Since this is such a large change, I plan on
pushing the patches in phases, where each phase keeps full
compatibility and passes make test.
The API of unix_convert has been simplified from:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
bool allow_wcard_last_component,
char **pp_conv_path,
char **pp_saved_last_component,
SMB_STRUCT_STAT *pst)
to:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
struct smb_filename *smb_fname,
uint32_t ucf_flags)
Currently the smb_filename struct looks like:
struct smb_filename {
char *base_name;
char *stream_name;
char *original_lcomp;
SMB_STRUCT_STAT st;
};
One key point here is the decision to break up the base_name and
stream_name. I have introduced a helper function called
get_full_smb_filename() that takes an smb_filename struct and
allocates the full_name. I changed the callers of unix_convert() to
subsequently call get_full_smb_filename() for the time being, but I
plan to eventually eliminate get_full_smb_filename().
2009-04-08 00:39:57 +04:00
2007-03-12 20:55:24 +03:00
/* Optimization - check if we can redirect the whole path. */
2021-07-13 03:53:19 +03:00
status = parent_pathref ( ctx ,
conn - > cwd_fsp ,
smb_fname ,
& parent_fname ,
& atname ) ;
2020-02-13 00:41:56 +03:00
if ( NT_STATUS_IS_OK ( status ) ) {
2021-07-13 03:53:19 +03:00
/*
* We must have a parent_fname - > fsp before
* we can call SMB_VFS_READ_DFS_PATHAT ( ) .
*/
status = SMB_VFS_READ_DFS_PATHAT ( conn ,
ctx ,
parent_fname - > fsp ,
atname ,
ppreflist ,
preferral_count ) ;
/* We're now done with parent_fname and atname. */
TALLOC_FREE ( parent_fname ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
DBG_INFO ( " %s resolves to a valid dfs link \n " ,
dfspath ) ;
2007-03-12 20:55:24 +03:00
2021-07-13 03:53:19 +03:00
if ( consumedcntp ) {
* consumedcntp = strlen ( dfspath ) ;
}
status = NT_STATUS_PATH_NOT_COVERED ;
goto out ;
2005-08-03 03:24:32 +04:00
}
2005-03-25 03:58:15 +03:00
}
2002-07-15 14:35:28 +04:00
2007-03-08 06:00:42 +03:00
/* Prepare to test only for '/' components in the given path,
2007-03-12 20:55:24 +03:00
* so if a Windows path replace all ' \\ ' characters with ' / ' .
* For a POSIX DFS path we know all separators are already ' / ' . */
2007-03-08 06:00:42 +03:00
2007-09-11 22:31:29 +04:00
canon_dfspath = talloc_strdup ( ctx , dfspath ) ;
if ( ! canon_dfspath ) {
2009-07-25 03:05:44 +04:00
status = NT_STATUS_NO_MEMORY ;
goto out ;
2007-09-11 22:31:29 +04:00
}
2022-08-04 19:52:17 +03:00
string_replace ( canon_dfspath , ' \\ ' , ' / ' ) ;
2007-03-12 20:55:24 +03:00
2007-08-06 22:54:26 +04:00
/*
* localpath comes out of unix_convert , so it has
* no trailing backslash . Make sure that canon_dfspath hasn ' t either .
* Fix for bug # 4860 from Jan Martin < Jan . Martin @ rwedea . com > .
*/
trim_char ( canon_dfspath , 0 , ' / ' ) ;
2007-03-12 20:55:24 +03:00
/*
* Redirect if any component in the path is a link .
2007-09-11 22:31:29 +04:00
* We do this by walking backwards through the
2007-03-12 20:55:24 +03:00
* local path , chopping off the last component
* in both the local path and the canonicalized
* DFS path . If we hit a DFS link then we ' re done .
*/
2009-07-25 03:05:44 +04:00
p = strrchr_m ( smb_fname - > base_name , ' / ' ) ;
2007-03-12 20:55:24 +03:00
if ( consumedcntp ) {
q = strrchr_m ( canon_dfspath , ' / ' ) ;
}
2007-03-08 06:00:42 +03:00
2003-04-10 23:54:17 +04:00
while ( p ) {
2002-07-15 14:35:28 +04:00
* p = ' \0 ' ;
2007-03-12 20:55:24 +03:00
if ( q ) {
* q = ' \0 ' ;
}
2021-07-13 03:56:13 +03:00
/*
* Ensure parent_pathref ( ) calls vfs_stat ( ) on
* the newly truncated path .
*/
SET_STAT_INVALID ( smb_fname - > st ) ;
status = parent_pathref ( ctx ,
2020-02-13 00:41:56 +03:00
conn - > cwd_fsp ,
smb_fname ,
2021-07-13 03:56:13 +03:00
& parent_fname ,
& atname ) ;
2020-02-13 00:41:56 +03:00
if ( NT_STATUS_IS_OK ( status ) ) {
2021-07-13 03:56:13 +03:00
/*
* We must have a parent_fname - > fsp before
* we can call SMB_VFS_READ_DFS_PATHAT ( ) .
*/
status = SMB_VFS_READ_DFS_PATHAT ( conn ,
ctx ,
parent_fname - > fsp ,
atname ,
ppreflist ,
preferral_count ) ;
/* We're now done with parent_fname and atname. */
TALLOC_FREE ( parent_fname ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
DBG_INFO ( " Redirecting %s because "
" parent %s is a dfs link \n " ,
dfspath ,
smb_fname_str_dbg ( smb_fname ) ) ;
if ( consumedcntp ) {
* consumedcntp = strlen ( canon_dfspath ) ;
DBG_DEBUG ( " Path consumed: %s "
2022-08-04 23:23:28 +03:00
" (%zu) \n " ,
2021-07-13 03:56:13 +03:00
canon_dfspath ,
* consumedcntp ) ;
}
status = NT_STATUS_PATH_NOT_COVERED ;
goto out ;
2002-07-15 14:35:28 +04:00
}
2007-03-12 20:55:24 +03:00
}
/* Step back on the filesystem. */
2009-07-25 03:05:44 +04:00
p = strrchr_m ( smb_fname - > base_name , ' / ' ) ;
2007-03-12 20:55:24 +03:00
if ( consumedcntp ) {
/* And in the canonicalized dfs path. */
q = strrchr_m ( canon_dfspath , ' / ' ) ;
2002-07-15 14:35:28 +04:00
}
2001-06-30 02:32:24 +04:00
}
2005-08-03 03:24:32 +04:00
2021-12-04 03:00:26 +03:00
if ( ( ucf_flags & UCF_GMT_PATHNAME ) & & _twrp ! = NULL ) {
* _twrp = smb_fname - > twrp ;
}
2009-07-25 03:05:44 +04:00
status = NT_STATUS_OK ;
out :
2020-02-12 01:21:12 +03:00
2021-07-13 03:56:13 +03:00
/* This should already be free, but make sure. */
TALLOC_FREE ( parent_fname ) ;
2009-07-25 03:05:44 +04:00
TALLOC_FREE ( smb_fname ) ;
return status ;
2000-05-16 05:13:16 +04:00
}
2000-03-09 01:14:30 +03:00
2002-07-15 14:35:28 +04:00
/*****************************************************************
2007-03-12 20:55:24 +03:00
Decides if a dfs pathname should be redirected or not .
If not , the pathname is converted to a tcon - relative local unix path
2007-09-11 22:31:29 +04:00
search_wcard_flag : this flag performs 2 functions both related
2007-03-12 20:55:24 +03:00
to searches . See resolve_dfs_path ( ) and parse_dfs_path_XX ( )
for details .
This function can return NT_STATUS_OK , meaning use the returned path as - is
( mapped into a local path ) .
or NT_STATUS_NOT_COVERED meaning return a DFS redirect , or
any other NT_STATUS error which is a genuine error to be
2007-09-11 22:31:29 +04:00
returned to the client .
2002-07-15 14:35:28 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-10-28 03:51:21 +03:00
2020-09-30 00:24:10 +03:00
NTSTATUS dfs_redirect ( TALLOC_CTX * ctx ,
2007-09-11 22:31:29 +04:00
connection_struct * conn ,
const char * path_in ,
2016-03-25 21:26:39 +03:00
uint32_t ucf_flags ,
2011-09-24 07:35:20 +04:00
bool allow_broken_path ,
2021-12-04 03:14:08 +03:00
NTTIME * _twrp ,
2020-09-30 00:21:08 +03:00
char * * pp_path_out )
2000-03-09 01:14:30 +03:00
{
2019-11-07 13:01:05 +03:00
const struct loadparm_substitution * lp_sub =
loadparm_s3_global_substitution ( ) ;
2007-03-12 20:55:24 +03:00
NTSTATUS status ;
2011-06-07 05:38:41 +04:00
struct dfs_path * pdp = talloc ( ctx , struct dfs_path ) ;
2007-09-11 22:31:29 +04:00
if ( ! pdp ) {
return NT_STATUS_NO_MEMORY ;
}
2022-08-04 23:08:51 +03:00
status = parse_dfs_path ( conn , path_in ,
2020-09-30 03:14:22 +03:00
allow_broken_path , pdp ) ;
2007-03-12 20:55:24 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2007-09-11 22:31:29 +04:00
TALLOC_FREE ( pdp ) ;
2007-03-12 20:55:24 +03:00
return status ;
}
2007-09-11 22:31:29 +04:00
if ( pdp - > reqpath [ 0 ] = = ' \0 ' ) {
TALLOC_FREE ( pdp ) ;
* pp_path_out = talloc_strdup ( ctx , " " ) ;
if ( ! * pp_path_out ) {
return NT_STATUS_NO_MEMORY ;
}
2007-03-12 20:55:24 +03:00
DEBUG ( 5 , ( " dfs_redirect: self-referral. \n " ) ) ;
return NT_STATUS_OK ;
2005-08-03 03:24:32 +04:00
}
2001-06-30 02:32:24 +04:00
2007-03-12 20:55:24 +03:00
/* If dfs pathname for a non-dfs share, convert to tcon-relative
path and return OK */
2001-06-30 02:32:24 +04:00
2002-07-15 14:35:28 +04:00
if ( ! lp_msdfs_root ( SNUM ( conn ) ) ) {
2007-09-11 22:31:29 +04:00
* pp_path_out = talloc_strdup ( ctx , pdp - > reqpath ) ;
TALLOC_FREE ( pdp ) ;
if ( ! * pp_path_out ) {
return NT_STATUS_NO_MEMORY ;
}
2007-03-12 20:55:24 +03:00
return NT_STATUS_OK ;
2002-07-15 14:35:28 +04:00
}
2007-03-12 20:55:24 +03:00
/* If it looked like a local path (zero hostname/servicename)
2007-09-11 22:31:29 +04:00
* just treat as a tcon - relative path . */
2007-03-12 20:55:24 +03:00
2007-09-11 22:31:29 +04:00
if ( pdp - > hostname [ 0 ] = = ' \0 ' & & pdp - > servicename [ 0 ] = = ' \0 ' ) {
* pp_path_out = talloc_strdup ( ctx , pdp - > reqpath ) ;
TALLOC_FREE ( pdp ) ;
if ( ! * pp_path_out ) {
return NT_STATUS_NO_MEMORY ;
}
2007-03-12 20:55:24 +03:00
return NT_STATUS_OK ;
2005-08-03 03:24:32 +04:00
}
2001-06-30 02:32:24 +04:00
2019-11-07 13:01:05 +03:00
if ( ! ( strequal ( pdp - > servicename , lp_servicename ( talloc_tos ( ) , lp_sub , SNUM ( conn ) ) )
2008-05-11 13:26:33 +04:00
| | ( strequal ( pdp - > servicename , HOMES_NAME )
2019-11-07 13:01:05 +03:00
& & strequal ( lp_servicename ( talloc_tos ( ) , lp_sub , SNUM ( conn ) ) ,
2011-07-15 09:55:31 +04:00
conn - > session_info - > unix_info - > sanitized_username ) ) ) ) {
2008-05-11 13:26:33 +04:00
/* The given sharename doesn't match this connection. */
TALLOC_FREE ( pdp ) ;
return NT_STATUS_OBJECT_PATH_NOT_FOUND ;
}
2020-02-13 00:17:51 +03:00
status = dfs_path_lookup ( ctx ,
conn ,
path_in ,
pdp ,
ucf_flags ,
2021-12-04 03:14:08 +03:00
_twrp , /* twrp. */
2022-08-04 23:23:28 +03:00
NULL , /* size_t *consumedcntp */
2020-02-13 00:17:51 +03:00
NULL , /* struct referral **ppreflist */
NULL ) ; /* size_t *preferral_count */
2007-03-12 20:55:24 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
if ( NT_STATUS_EQUAL ( status , NT_STATUS_PATH_NOT_COVERED ) ) {
2007-09-11 22:31:29 +04:00
DEBUG ( 3 , ( " dfs_redirect: Redirecting %s \n " , path_in ) ) ;
2007-03-12 20:55:24 +03:00
} else {
2007-09-11 22:31:29 +04:00
DEBUG ( 10 , ( " dfs_redirect: dfs_path_lookup "
" failed for %s with %s \n " ,
path_in , nt_errstr ( status ) ) ) ;
2007-03-12 20:55:24 +03:00
}
return status ;
2001-06-30 02:32:24 +04:00
}
2003-09-22 21:53:59 +04:00
2007-09-11 22:31:29 +04:00
DEBUG ( 3 , ( " dfs_redirect: Not redirecting %s. \n " , path_in ) ) ;
2007-03-12 20:55:24 +03:00
/* Form non-dfs tcon-relative path */
2007-09-11 22:31:29 +04:00
* pp_path_out = talloc_strdup ( ctx , pdp - > reqpath ) ;
TALLOC_FREE ( pdp ) ;
if ( ! * pp_path_out ) {
return NT_STATUS_NO_MEMORY ;
}
DEBUG ( 3 , ( " dfs_redirect: Path %s converted to non-dfs path %s \n " ,
path_in ,
* pp_path_out ) ) ;
2007-03-12 20:55:24 +03:00
return NT_STATUS_OK ;
2000-03-09 01:14:30 +03:00
}
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 ,
bool allow_broken_path ,
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 ;
2002-07-15 14:35:28 +04:00
int snum ;
2007-04-04 02:59:55 +04:00
NTSTATUS status = NT_STATUS_NOT_FOUND ;
2018-05-24 18:40:27 +03:00
struct dfs_path * pdp = talloc_zero ( frame , struct dfs_path ) ;
2002-07-15 14:35:28 +04:00
2007-09-11 22:31:29 +04:00
if ( ! pdp ) {
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2007-09-11 22:31:29 +04:00
return NT_STATUS_NO_MEMORY ;
}
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-04 23:08:51 +03:00
status = parse_dfs_path ( NULL , dfs_path , allow_broken_path , pdp ) ;
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
2007-09-11 22:31:29 +04:00
jucn - > service_name = talloc_strdup ( ctx , pdp - > servicename ) ;
jucn - > volume_name = talloc_strdup ( ctx , pdp - > reqpath ) ;
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 " ,
pdp - > 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
*/
2007-09-11 22:31:29 +04:00
if ( pdp - > 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 ;
}
}
2007-03-12 20:55:24 +03:00
/* If this is a DFS path dfs_lookup should return
* NT_STATUS_PATH_NOT_COVERED . */
2020-02-13 00:17:51 +03:00
status = dfs_path_lookup ( ctx ,
conn ,
dfs_path ,
pdp ,
0 , /* ucf_flags */
2021-12-04 03:00:26 +03:00
NULL ,
2020-02-13 00:17:51 +03:00
consumedcntp ,
& jucn - > referral_list ,
& jucn - > referral_count ) ;
2007-03-12 20:55:24 +03:00
if ( ! NT_STATUS_EQUAL ( status , NT_STATUS_PATH_NOT_COVERED ) ) {
DEBUG ( 3 , ( " get_referred_path: No valid referrals for path %s \n " ,
dfs_path ) ) ;
2013-01-25 22:21:48 +04:00
if ( NT_STATUS_IS_OK ( status ) ) {
/*
* We are in an error path here ( we
* know it ' s not a DFS path ) , but
* dfs_path_lookup ( ) can return
* NT_STATUS_OK . Ensure we always
* return a valid error code .
*
* # 9588 - ACLs are not inherited to directories
* for DFS shares .
*/
status = NT_STATUS_NOT_FOUND ;
}
2011-03-01 21:17:49 +03:00
goto err_exit ;
2002-07-15 14:35:28 +04:00
}
2007-03-12 20:55:24 +03:00
2011-03-01 21:17:49 +03:00
status = NT_STATUS_OK ;
err_exit :
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 ,
2011-09-24 07:53:28 +04:00
bool allow_broken_path ,
2007-09-11 22:31:29 +04:00
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 ;
2011-06-07 05:38:41 +04:00
struct dfs_path * pdp = talloc ( ctx , struct dfs_path ) ;
2007-09-11 22:31:29 +04:00
NTSTATUS status ;
2007-03-12 20:55:24 +03:00
2007-09-11 22:31:29 +04:00
if ( ! pdp ) {
return False ;
}
2022-08-04 23:08:51 +03:00
status = parse_dfs_path ( NULL , dfs_path , allow_broken_path , pdp ) ;
2007-03-12 20:55:24 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return False ;
}
2002-07-15 14:35:28 +04:00
2007-03-12 20:55:24 +03:00
/* check if path is dfs : validate first token */
2007-09-11 22:31:29 +04:00
if ( ! is_myname_or_ipaddr ( pdp - > hostname ) ) {
DEBUG ( 4 , ( " create_junction: Invalid hostname %s "
" in dfs path %s \n " ,
pdp - > hostname , dfs_path ) ) ;
TALLOC_FREE ( pdp ) ;
2006-08-02 20:18:45 +04:00
return False ;
2005-08-03 03:24:32 +04:00
}
2002-07-15 14:35:28 +04:00
2005-08-03 03:24:32 +04:00
/* Check for a non-DFS share */
2007-09-11 22:31:29 +04:00
snum = lp_servicenumber ( pdp - > 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 " ,
2007-09-11 22:31:29 +04:00
pdp - > servicename ) ) ;
TALLOC_FREE ( pdp ) ;
2005-08-03 03:24:32 +04:00
return False ;
}
2002-07-15 14:35:28 +04:00
2007-09-11 22:31:29 +04:00
jucn - > service_name = talloc_strdup ( ctx , pdp - > servicename ) ;
jucn - > volume_name = talloc_strdup ( ctx , pdp - > 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
TALLOC_FREE ( pdp ) ;
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 ;
long offset = 0 ;
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 ;
}
2020-03-18 14:05:06 +03:00
while ( ( dname = ReadDirName ( dir_hnd , & offset , NULL , & 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 ;
long offset = 0 ;
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
2020-03-18 18:12:09 +03:00
while ( ( dname = ReadDirName ( dir_hnd , & offset , NULL , & 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 "
" junction slots " ) ) ;
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
}