2007-11-30 04:25:41 +03:00
/*
2005-02-22 06:31:22 +03:00
Unix SMB / CIFS implementation .
client connect / disconnect routines
2005-02-25 00:54:52 +03:00
Copyright ( C ) Andrew Tridgell 1994 - 1998
2005-02-23 20:29:28 +03:00
Copyright ( C ) Gerald ( Jerry ) Carter 2004
2009-03-13 03:59:24 +03:00
Copyright ( C ) Jeremy Allison 2007 - 2009
2007-11-30 04:25:41 +03:00
2005-02-22 06:31:22 +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
2005-02-22 06:31:22 +03:00
( at your option ) any later version .
2007-11-30 04:25:41 +03:00
2005-02-22 06:31:22 +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-11-30 04:25:41 +03:00
2005-02-22 06:31:22 +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/>.
2005-02-22 06:31:22 +03:00
*/
# include "includes.h"
2011-05-06 13:47:43 +04:00
# include "libsmb/libsmb.h"
2011-02-24 12:46:55 +03:00
# include "libsmb/clirap.h"
2011-02-25 00:58:08 +03:00
# include "msdfs.h"
2011-02-25 02:03:01 +03:00
# include "trans2.h"
2011-03-23 16:18:59 +03:00
# include "libsmb/nmblib.h"
2012-05-19 19:31:50 +04:00
# include "../libcli/smb/smbXcli_base.h"
2016-12-12 08:07:56 +03:00
# include "auth/credentials/credentials.h"
2005-02-22 06:31:22 +03:00
2007-03-09 02:54:57 +03:00
/********************************************************************
Important point .
2007-03-12 20:55:24 +03:00
DFS paths are * always * of the form \ server \ share \ < pathname > ( the \ characters
2007-03-09 02:54:57 +03:00
are not C escaped here ) .
- but if we ' re using POSIX paths then < pathname > may contain
' / ' separators , not ' \\ ' separators . So cope with ' \\ ' or ' / '
as a separator when looking at the pathname part . . . . JRA .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-02-22 06:31:22 +03:00
2007-12-30 09:39:52 +03:00
/********************************************************************
Ensure a connection is encrypted .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-07-06 12:05:59 +03:00
static NTSTATUS cli_cm_force_encryption_creds ( struct cli_state * c ,
struct cli_credentials * creds ,
const char * sharename )
2007-12-30 09:39:52 +03:00
{
2016-11-03 16:50:28 +03:00
uint16_t major , minor ;
uint32_t caplow , caphigh ;
2013-08-16 21:44:34 +04:00
NTSTATUS status ;
2021-08-11 15:33:24 +03:00
bool temp_ipc = false ;
2013-08-16 21:44:34 +04:00
if ( smbXcli_conn_protocol ( c - > conn ) > = PROTOCOL_SMB2_02 ) {
status = smb2cli_session_encryption_on ( c - > smb2 . session ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NOT_SUPPORTED ) ) {
d_printf ( " Encryption required and "
" server doesn't support "
" SMB3 encryption - failing connect \n " ) ;
} else if ( ! NT_STATUS_IS_OK ( status ) ) {
d_printf ( " Encryption required and "
" setup failed with error %s. \n " ,
nt_errstr ( status ) ) ;
}
return status ;
}
2016-11-03 16:50:28 +03:00
if ( ! SERVER_HAS_UNIX_CIFS ( c ) ) {
2007-12-30 09:39:52 +03:00
d_printf ( " Encryption required and "
" server that doesn't support "
" UNIX extensions - failing connect \n " ) ;
2016-11-03 16:50:28 +03:00
return NT_STATUS_NOT_SUPPORTED ;
}
2021-08-11 15:33:24 +03:00
if ( c - > smb1 . tcon = = NULL ) {
status = cli_tree_connect_creds ( c , " IPC$ " , " IPC " , creds ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
d_printf ( " Encryption required and "
" can't connect to IPC$ to check "
" UNIX CIFS extensions. \n " ) ;
return NT_STATUS_UNKNOWN_REVISION ;
}
temp_ipc = true ;
}
2016-11-03 16:50:28 +03:00
status = cli_unix_extensions_version ( c , & major , & minor , & caplow ,
& caphigh ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2007-12-30 09:39:52 +03:00
d_printf ( " Encryption required and "
" can't get UNIX CIFS extensions "
" version from server. \n " ) ;
2021-08-11 15:33:24 +03:00
if ( temp_ipc ) {
cli_tdis ( c ) ;
}
2016-11-03 16:50:28 +03:00
return NT_STATUS_UNKNOWN_REVISION ;
}
if ( ! ( caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP ) ) {
2007-12-30 09:39:52 +03:00
d_printf ( " Encryption required and "
" share %s doesn't support "
" encryption. \n " , sharename ) ;
2021-08-11 15:33:24 +03:00
if ( temp_ipc ) {
cli_tdis ( c ) ;
}
2016-11-03 16:50:28 +03:00
return NT_STATUS_UNSUPPORTED_COMPRESSION ;
}
2016-11-03 19:26:41 +03:00
status = cli_smb1_setup_encryption ( c , creds ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
d_printf ( " Encryption required and "
" setup failed with error %s. \n " ,
nt_errstr ( status ) ) ;
2021-08-11 15:33:24 +03:00
if ( temp_ipc ) {
cli_tdis ( c ) ;
}
2016-11-03 19:26:41 +03:00
return status ;
}
2021-08-11 15:33:24 +03:00
if ( temp_ipc ) {
cli_tdis ( c ) ;
}
2016-11-03 19:26:41 +03:00
return NT_STATUS_OK ;
}
2005-02-25 00:54:52 +03:00
/********************************************************************
Return a connection to a server .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-07-03 14:08:54 +04:00
static NTSTATUS do_connect ( TALLOC_CTX * ctx ,
2007-11-30 04:25:41 +03:00
const char * server ,
const char * share ,
2020-08-18 18:15:09 +03:00
struct cli_credentials * creds ,
2018-08-23 10:20:49 +03:00
const struct sockaddr_storage * dest_ss ,
2009-01-15 03:08:19 +03:00
int port ,
2011-07-03 14:08:54 +04:00
int name_type ,
struct cli_state * * pcli )
2005-02-25 00:54:52 +03:00
{
2006-07-11 22:01:26 +04:00
struct cli_state * c = NULL ;
2007-11-30 04:25:41 +03:00
char * servicename ;
2005-02-25 00:54:52 +03:00
char * sharename ;
2007-11-30 04:25:41 +03:00
char * newserver , * newshare ;
2007-06-20 21:38:42 +04:00
NTSTATUS status ;
2011-09-07 22:35:51 +04:00
int flags = 0 ;
2017-08-16 13:42:48 +03:00
enum protocol_types protocol = PROTOCOL_NONE ;
2020-08-18 18:15:09 +03:00
enum smb_signing_setting signing_state =
cli_credentials_get_smb_signing ( creds ) ;
enum smb_encryption_setting encryption_state =
cli_credentials_get_smb_encryption ( creds ) ;
2015-09-30 22:17:02 +03:00
2020-08-18 18:15:09 +03:00
if ( encryption_state > = SMB_ENCRYPTION_DESIRED ) {
2015-09-30 22:17:02 +03:00
signing_state = SMB_SIGNING_REQUIRED ;
}
2007-11-30 04:25:41 +03:00
2005-02-25 00:54:52 +03:00
/* make a copy so we don't modify the global string 'service' */
2007-11-30 04:25:41 +03:00
servicename = talloc_strdup ( ctx , share ) ;
if ( ! servicename ) {
2011-07-03 14:08:54 +04:00
return NT_STATUS_NO_MEMORY ;
2007-11-30 04:25:41 +03:00
}
2005-02-25 00:54:52 +03:00
sharename = servicename ;
if ( * sharename = = ' \\ ' ) {
2009-01-02 23:49:49 +03:00
sharename + = 2 ;
if ( server = = NULL ) {
server = sharename ;
}
sharename = strchr_m ( sharename , ' \\ ' ) ;
2007-11-30 04:25:41 +03:00
if ( ! sharename ) {
2011-07-03 14:08:54 +04:00
return NT_STATUS_NO_MEMORY ;
2007-11-30 04:25:41 +03:00
}
2005-02-25 00:54:52 +03:00
* sharename = 0 ;
sharename + + ;
}
2011-05-29 15:17:23 +04:00
if ( server = = NULL ) {
2011-07-03 14:08:54 +04:00
return NT_STATUS_INVALID_PARAMETER ;
2005-02-25 00:54:52 +03:00
}
2009-01-15 03:08:19 +03:00
2011-05-29 15:17:23 +04:00
status = cli_connect_nb (
2018-08-23 10:20:49 +03:00
server , dest_ss , port , name_type , NULL ,
2015-09-30 22:17:02 +03:00
signing_state ,
2011-09-07 22:35:51 +04:00
flags , & c ) ;
2011-05-29 15:17:23 +04:00
2007-06-20 21:38:42 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2018-12-17 22:40:33 +03:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NOT_SUPPORTED ) ) {
DBG_ERR ( " NetBIOS support disabled, unable to connect " ) ;
}
2018-09-03 13:11:39 +03:00
DBG_WARNING ( " Connection to %s failed (Error %s) \n " ,
server ,
nt_errstr ( status ) ) ;
2011-07-03 14:08:54 +04:00
return status ;
2007-06-20 21:38:42 +04:00
}
2005-02-25 00:54:52 +03:00
DEBUG ( 4 , ( " session request ok \n " ) ) ;
2013-08-11 16:00:45 +04:00
status = smbXcli_negprot ( c - > conn , c - > timeout ,
2014-02-04 06:09:08 +04:00
lp_client_min_protocol ( ) ,
2020-08-27 17:46:29 +03:00
lp_client_max_protocol ( ) ) ;
2008-09-11 20:57:49 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
d_printf ( " protocol negotiation failed: %s \n " ,
nt_errstr ( status ) ) ;
2005-02-25 00:54:52 +03:00
cli_shutdown ( c ) ;
2011-07-03 14:08:54 +04:00
return status ;
2005-02-25 00:54:52 +03:00
}
2017-08-16 13:42:48 +03:00
protocol = smbXcli_conn_protocol ( c - > conn ) ;
DEBUG ( 4 , ( " negotiated dialect[%s] against server[%s] \n " ,
smb_protocol_types_string ( protocol ) ,
smbXcli_conn_remote_name ( c - > conn ) ) ) ;
2005-02-25 00:54:52 +03:00
2017-08-16 13:42:48 +03:00
if ( protocol > = PROTOCOL_SMB2_02 ) {
2013-08-09 22:15:48 +04:00
/* Ensure we ask for some initial credits. */
smb2cli_conn_set_max_credits ( c - > conn , DEFAULT_SMB2_MAX_CREDITS ) ;
}
2016-10-30 18:45:39 +03:00
status = cli_session_setup_creds ( c , creds ) ;
2011-07-03 14:04:24 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2007-11-30 04:25:41 +03:00
/* If a password was not supplied then
* try again with a null username . */
2020-08-18 18:15:09 +03:00
if ( encryption_state = = SMB_ENCRYPTION_REQUIRED | |
smbXcli_conn_signing_mandatory ( c - > conn ) | |
2016-12-12 08:07:56 +03:00
cli_credentials_authentication_requested ( creds ) | |
cli_credentials_is_anonymous ( creds ) | |
2016-10-28 13:15:20 +03:00
! NT_STATUS_IS_OK ( status = cli_session_setup_anon ( c ) ) )
{
2011-07-03 14:04:24 +04:00
d_printf ( " session setup failed: %s \n " ,
nt_errstr ( status ) ) ;
2011-11-16 19:37:24 +04:00
if ( NT_STATUS_EQUAL ( status ,
NT_STATUS_MORE_PROCESSING_REQUIRED ) )
2005-02-25 00:54:52 +03:00
d_printf ( " did you forget to run kinit? \n " ) ;
cli_shutdown ( c ) ;
2011-07-03 14:08:54 +04:00
return status ;
2005-02-25 00:54:52 +03:00
}
d_printf ( " Anonymous login successful \n " ) ;
2009-10-23 02:06:38 +04:00
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " cli_init_creds() failed: %s \n " , nt_errstr ( status ) ) ) ;
cli_shutdown ( c ) ;
2011-07-03 14:08:54 +04:00
return status ;
2005-02-25 00:54:52 +03:00
}
DEBUG ( 4 , ( " session setup ok \n " ) ) ;
2021-08-11 15:33:24 +03:00
if ( encryption_state > = SMB_ENCRYPTION_DESIRED ) {
status = cli_cm_force_encryption_creds ( c ,
creds ,
sharename ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
switch ( encryption_state ) {
case SMB_ENCRYPTION_DESIRED :
break ;
case SMB_ENCRYPTION_REQUIRED :
default :
cli_shutdown ( c ) ;
return status ;
}
}
}
2005-05-10 02:39:20 +04:00
/* here's the fun part....to support 'msdfs proxy' shares
2007-11-30 04:25:41 +03:00
( on Samba or windows ) we have to issues a TRANS_GET_DFS_REFERRAL
2005-05-10 02:39:20 +04:00
here before trying to connect to the original share .
2009-10-28 22:48:36 +03:00
cli_check_msdfs_proxy ( ) will fail if it is a normal share . */
2005-05-10 02:39:20 +04:00
2013-05-17 22:46:24 +04:00
if ( smbXcli_conn_dfs_supported ( c - > conn ) & &
2007-11-30 04:25:41 +03:00
cli_check_msdfs_proxy ( ctx , c , sharename ,
2007-12-30 09:39:52 +03:00
& newserver , & newshare ,
2020-08-27 16:52:11 +03:00
creds ) ) {
2005-05-10 02:39:20 +04:00
cli_shutdown ( c ) ;
2007-12-30 09:39:52 +03:00
return do_connect ( ctx , newserver ,
2020-08-18 18:15:09 +03:00
newshare , creds ,
2018-08-23 10:20:49 +03:00
NULL , port , name_type , pcli ) ;
2005-05-10 02:39:20 +04:00
}
/* must be a normal share */
2016-12-09 11:06:38 +03:00
status = cli_tree_connect_creds ( c , sharename , " ????? " , creds ) ;
2009-01-26 10:37:13 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
d_printf ( " tree connect failed: %s \n " , nt_errstr ( status ) ) ;
2005-02-25 00:54:52 +03:00
cli_shutdown ( c ) ;
2011-07-03 14:08:54 +04:00
return status ;
2005-02-25 00:54:52 +03:00
}
DEBUG ( 4 , ( " tconx ok \n " ) ) ;
2011-07-03 14:08:54 +04:00
* pcli = c ;
return NT_STATUS_OK ;
2005-02-25 00:54:52 +03:00
}
/********************************************************************
2009-03-13 03:59:24 +03:00
Add a new connection to the list .
referring_cli = = NULL means a new initial connection .
2005-02-25 00:54:52 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-07-03 14:12:45 +04:00
static NTSTATUS cli_cm_connect ( TALLOC_CTX * ctx ,
struct cli_state * referring_cli ,
const char * server ,
const char * share ,
2020-08-18 18:18:16 +03:00
struct cli_credentials * creds ,
2018-08-23 10:20:49 +03:00
const struct sockaddr_storage * dest_ss ,
2011-07-03 14:12:45 +04:00
int port ,
int name_type ,
struct cli_state * * pcli )
2005-02-25 00:54:52 +03:00
{
2019-08-13 17:27:35 +03:00
struct cli_state * cli = NULL ;
2011-07-03 14:08:54 +04:00
NTSTATUS status ;
2007-11-30 00:24:54 +03:00
2011-07-03 14:08:54 +04:00
status = do_connect ( ctx , server , share ,
2020-08-18 18:15:09 +03:00
creds ,
2018-08-23 10:20:49 +03:00
dest_ss , port , name_type , & cli ) ;
2005-02-25 00:54:52 +03:00
2011-07-03 14:08:54 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-07-03 14:12:45 +04:00
return status ;
2005-02-25 00:54:52 +03:00
}
2019-08-13 17:27:35 +03:00
/*
* This can ' t happen , this test is to satisfy static
* checkers ( clang )
*/
if ( cli = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2009-03-13 03:59:24 +03:00
/* Enter into the list. */
if ( referring_cli ) {
2016-02-05 13:32:18 +03:00
DLIST_ADD_END ( referring_cli , cli ) ;
2009-03-13 03:59:24 +03:00
}
2005-02-26 17:42:55 +03:00
2010-04-14 05:41:14 +04:00
if ( referring_cli & & referring_cli - > requested_posix_capabilities ) {
2015-05-01 05:22:21 +03:00
uint16_t major , minor ;
uint32_t caplow , caphigh ;
2009-11-13 01:07:21 +03:00
status = cli_unix_extensions_version ( cli , & major , & minor ,
& caplow , & caphigh ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
2009-03-13 03:59:24 +03:00
cli_set_unix_extensions_capabilities ( cli ,
2007-12-07 04:17:03 +03:00
major , minor ,
2007-12-07 04:16:33 +03:00
caplow , caphigh ) ;
}
}
2005-02-25 00:54:52 +03:00
2011-07-03 14:12:45 +04:00
* pcli = cli ;
return NT_STATUS_OK ;
2005-02-25 00:54:52 +03:00
}
/********************************************************************
2009-03-13 03:59:24 +03:00
Return a connection to a server on a particular share .
2005-02-25 00:54:52 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-03-13 03:59:24 +03:00
static struct cli_state * cli_cm_find ( struct cli_state * cli ,
const char * server ,
const char * share )
2005-02-25 00:54:52 +03:00
{
2009-03-13 03:59:24 +03:00
struct cli_state * p ;
2005-02-25 00:54:52 +03:00
2009-03-13 03:59:24 +03:00
if ( cli = = NULL ) {
return NULL ;
}
/* Search to the start of the list. */
2010-02-06 04:40:38 +03:00
for ( p = cli ; p ; p = DLIST_PREV ( p ) ) {
2011-07-22 18:31:18 +04:00
const char * remote_name =
2012-05-19 19:31:50 +04:00
smbXcli_conn_remote_name ( p - > conn ) ;
2011-07-22 18:31:18 +04:00
if ( strequal ( server , remote_name ) & &
2009-03-13 03:59:24 +03:00
strequal ( share , p - > share ) ) {
return p ;
}
}
/* Search to the end of the list. */
for ( p = cli - > next ; p ; p = p - > next ) {
2011-07-22 18:31:18 +04:00
const char * remote_name =
2012-05-19 19:31:50 +04:00
smbXcli_conn_remote_name ( p - > conn ) ;
2011-07-22 18:31:18 +04:00
if ( strequal ( server , remote_name ) & &
2009-03-13 03:59:24 +03:00
strequal ( share , p - > share ) ) {
return p ;
2007-11-30 04:25:41 +03:00
}
2005-02-25 00:54:52 +03:00
}
return NULL ;
}
/****************************************************************************
2009-03-13 03:59:24 +03:00
Open a client connection to a \ \ server \ share .
2005-02-25 00:54:52 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-07-03 21:59:37 +04:00
NTSTATUS cli_cm_open ( TALLOC_CTX * ctx ,
2020-08-18 18:26:54 +03:00
struct cli_state * referring_cli ,
const char * server ,
const char * share ,
struct cli_credentials * creds ,
const struct sockaddr_storage * dest_ss ,
int port ,
int name_type ,
struct cli_state * * pcli )
2005-02-25 00:54:52 +03:00
{
2009-03-13 03:59:24 +03:00
/* Try to reuse an existing connection in this list. */
struct cli_state * c = cli_cm_find ( referring_cli , server , share ) ;
2011-07-03 14:12:45 +04:00
NTSTATUS status ;
2007-11-30 04:25:41 +03:00
2009-03-13 03:59:24 +03:00
if ( c ) {
2011-07-03 21:59:37 +04:00
* pcli = c ;
return NT_STATUS_OK ;
2009-03-13 03:59:24 +03:00
}
2005-02-25 00:54:52 +03:00
2020-08-18 18:26:54 +03:00
if ( creds = = NULL ) {
2009-03-18 00:53:06 +03:00
/* Can't do a new connection
* without auth info . */
d_printf ( " cli_cm_open() Unable to open connection [ \\ %s \\ %s] "
2020-08-18 18:26:54 +03:00
" without client credentials \n " ,
2009-03-18 00:53:06 +03:00
server , share ) ;
2011-07-03 21:59:37 +04:00
return NT_STATUS_INVALID_PARAMETER ;
2009-03-18 00:53:06 +03:00
}
2011-07-03 14:12:45 +04:00
status = cli_cm_connect ( ctx ,
2009-03-18 00:53:06 +03:00
referring_cli ,
server ,
share ,
2020-08-18 18:18:16 +03:00
creds ,
2018-08-23 10:21:41 +03:00
dest_ss ,
2009-03-18 00:53:06 +03:00
port ,
2011-07-03 14:12:45 +04:00
name_type ,
& c ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-07-03 21:59:37 +04:00
return status ;
2011-07-03 14:12:45 +04:00
}
2011-07-03 21:59:37 +04:00
* pcli = c ;
return NT_STATUS_OK ;
2005-02-25 00:54:52 +03:00
}
/****************************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-07-22 18:05:54 +04:00
void cli_cm_display ( struct cli_state * cli )
2005-02-25 00:54:52 +03:00
{
int i ;
2009-03-13 03:59:24 +03:00
for ( i = 0 ; cli ; cli = cli - > next , i + + ) {
2007-11-30 04:25:41 +03:00
d_printf ( " %d: \t server=%s, share=%s \n " ,
2012-05-19 19:31:50 +04:00
i , smbXcli_conn_remote_name ( cli - > conn ) , cli - > share ) ;
2005-02-25 00:54:52 +03:00
}
}
2007-02-03 20:20:53 +03:00
/**********************************************************************
split a dfs path into the server , share name , and extrapath components
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-02-22 06:31:22 +03:00
2010-11-11 16:04:06 +03:00
static bool split_dfs_path ( TALLOC_CTX * ctx ,
2007-11-30 04:25:41 +03:00
const char * nodepath ,
char * * pp_server ,
char * * pp_share ,
char * * pp_extrapath )
2005-02-22 06:31:22 +03:00
{
2007-02-03 20:20:53 +03:00
char * p , * q ;
2007-11-30 04:25:41 +03:00
char * path ;
2005-02-22 06:31:22 +03:00
2007-11-30 04:25:41 +03:00
* pp_server = NULL ;
* pp_share = NULL ;
* pp_extrapath = NULL ;
path = talloc_strdup ( ctx , nodepath ) ;
if ( ! path ) {
2010-11-11 16:04:06 +03:00
goto fail ;
2007-11-30 04:25:41 +03:00
}
2005-02-22 06:31:22 +03:00
2007-03-12 20:55:24 +03:00
if ( path [ 0 ] ! = ' \\ ' ) {
2010-11-11 16:04:06 +03:00
goto fail ;
2007-03-12 20:55:24 +03:00
}
2005-02-22 06:31:22 +03:00
2007-02-03 20:20:53 +03:00
p = strchr_m ( path + 1 , ' \\ ' ) ;
2007-03-12 20:55:24 +03:00
if ( ! p ) {
2010-11-11 16:04:06 +03:00
goto fail ;
2007-03-12 20:55:24 +03:00
}
2005-02-22 06:31:22 +03:00
* p = ' \0 ' ;
p + + ;
2007-02-03 20:20:53 +03:00
/* Look for any extra/deep path */
q = strchr_m ( p , ' \\ ' ) ;
if ( q ! = NULL ) {
* q = ' \0 ' ;
q + + ;
2007-11-30 04:25:41 +03:00
* pp_extrapath = talloc_strdup ( ctx , q ) ;
2007-02-03 20:20:53 +03:00
} else {
2007-11-30 04:25:41 +03:00
* pp_extrapath = talloc_strdup ( ctx , " " ) ;
2007-02-03 20:20:53 +03:00
}
2010-11-11 16:04:06 +03:00
if ( * pp_extrapath = = NULL ) {
goto fail ;
}
2007-11-30 04:25:41 +03:00
* pp_share = talloc_strdup ( ctx , p ) ;
2010-11-11 16:04:06 +03:00
if ( * pp_share = = NULL ) {
goto fail ;
}
2007-11-30 04:25:41 +03:00
* pp_server = talloc_strdup ( ctx , & path [ 1 ] ) ;
2010-11-11 16:04:06 +03:00
if ( * pp_server = = NULL ) {
goto fail ;
}
TALLOC_FREE ( path ) ;
return true ;
fail :
TALLOC_FREE ( * pp_share ) ;
TALLOC_FREE ( * pp_extrapath ) ;
TALLOC_FREE ( path ) ;
return false ;
2005-02-22 06:31:22 +03:00
}
2005-02-23 20:29:28 +03:00
/****************************************************************************
2007-03-12 20:55:24 +03:00
Return the original path truncated at the directory component before
2007-11-30 04:25:41 +03:00
the first wildcard character . Trust the caller to provide a NULL
2005-02-23 20:29:28 +03:00
terminated string
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-11-30 04:25:41 +03:00
static char * clean_path ( TALLOC_CTX * ctx , const char * path )
2005-02-23 20:29:28 +03:00
{
2007-03-12 20:55:24 +03:00
size_t len ;
char * p1 , * p2 , * p ;
2007-11-30 04:25:41 +03:00
char * path_out ;
2007-03-12 20:55:24 +03:00
/* No absolute paths. */
while ( IS_DIRECTORY_SEP ( * path ) ) {
path + + ;
}
2007-11-30 04:25:41 +03:00
path_out = talloc_strdup ( ctx , path ) ;
if ( ! path_out ) {
return NULL ;
}
2007-03-12 20:55:24 +03:00
p1 = strchr_m ( path_out , ' * ' ) ;
p2 = strchr_m ( path_out , ' ? ' ) ;
if ( p1 | | p2 ) {
if ( p1 & & p2 ) {
p = MIN ( p1 , p2 ) ;
} else if ( ! p1 ) {
p = p2 ;
} else {
p = p1 ;
2005-02-23 20:29:28 +03:00
}
2007-03-12 20:55:24 +03:00
* p = ' \0 ' ;
/* Now go back to the start of this component. */
p1 = strrchr_m ( path_out , ' / ' ) ;
p2 = strrchr_m ( path_out , ' \\ ' ) ;
p = MAX ( p1 , p2 ) ;
if ( p ) {
2005-02-23 20:29:28 +03:00
* p = ' \0 ' ;
}
}
2007-03-12 20:55:24 +03:00
/* Strip any trailing separator */
len = strlen ( path_out ) ;
if ( ( len > 0 ) & & IS_DIRECTORY_SEP ( path_out [ len - 1 ] ) ) {
path_out [ len - 1 ] = ' \0 ' ;
}
2007-11-30 04:25:41 +03:00
return path_out ;
2005-02-23 20:29:28 +03:00
}
/****************************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-11-30 04:25:41 +03:00
static char * cli_dfs_make_full_path ( TALLOC_CTX * ctx ,
struct cli_state * cli ,
const char * dir )
2005-02-23 20:29:28 +03:00
{
2009-03-19 06:56:48 +03:00
char path_sep = ' \\ ' ;
2007-03-12 20:55:24 +03:00
/* Ensure the extrapath doesn't start with a separator. */
while ( IS_DIRECTORY_SEP ( * dir ) ) {
dir + + ;
2005-02-23 20:29:28 +03:00
}
2010-04-14 05:41:14 +04:00
if ( cli - > requested_posix_capabilities & CIFS_UNIX_POSIX_PATHNAMES_CAP ) {
2009-03-19 06:56:48 +03:00
path_sep = ' / ' ;
}
return talloc_asprintf ( ctx , " %c%s%c%s%c%s " ,
path_sep ,
2012-05-19 19:31:50 +04:00
smbXcli_conn_remote_name ( cli - > conn ) ,
2009-03-19 06:56:48 +03:00
path_sep ,
cli - > share ,
path_sep ,
dir ) ;
2005-02-23 20:29:28 +03:00
}
2022-08-20 00:59:04 +03:00
/********************************************************************
Check if a path has already been converted to DFS .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool cli_dfs_is_already_full_path ( struct cli_state * cli , const char * path )
{
const char * server = smbXcli_conn_remote_name ( cli - > conn ) ;
size_t server_len = strlen ( server ) ;
bool found_server = false ;
const char * share = cli - > share ;
size_t share_len = strlen ( share ) ;
bool found_share = false ;
if ( ! IS_DIRECTORY_SEP ( path [ 0 ] ) ) {
return false ;
}
path + + ;
found_server = ( strncasecmp_m ( path , server , server_len ) = = 0 ) ;
if ( ! found_server ) {
return false ;
}
path + = server_len ;
if ( ! IS_DIRECTORY_SEP ( path [ 0 ] ) ) {
return false ;
}
path + + ;
found_share = ( strncasecmp_m ( path , share , share_len ) = = 0 ) ;
if ( ! found_share ) {
return false ;
}
path + = share_len ;
if ( path [ 0 ] = = ' \0 ' ) {
return true ;
}
if ( IS_DIRECTORY_SEP ( path [ 0 ] ) ) {
return true ;
}
return false ;
}
2005-02-22 06:31:22 +03:00
/********************************************************************
2007-11-30 04:25:41 +03:00
Get the dfs referral link .
2005-02-22 06:31:22 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2017-06-26 19:43:31 +03:00
NTSTATUS cli_dfs_get_referral_ex ( TALLOC_CTX * ctx ,
2007-12-07 23:02:44 +03:00
struct cli_state * cli ,
2007-11-30 04:25:41 +03:00
const char * path ,
2017-06-26 19:43:31 +03:00
uint16_t max_referral_level ,
2009-11-21 23:36:01 +03:00
struct client_dfs_referral * * refs ,
2007-03-12 20:55:24 +03:00
size_t * num_refs ,
2009-07-01 02:29:08 +04:00
size_t * consumed )
2005-02-22 06:31:22 +03:00
{
unsigned int param_len = 0 ;
2011-07-06 15:04:26 +04:00
uint16_t recv_flags2 ;
2010-11-11 16:54:25 +03:00
uint8_t * param = NULL ;
uint8_t * rdata = NULL ;
2005-02-22 06:31:22 +03:00
char * p ;
2007-12-07 23:02:44 +03:00
char * endp ;
2009-07-01 02:29:08 +04:00
smb_ucs2_t * path_ucs ;
char * consumed_path = NULL ;
uint16_t consumed_ucs ;
2015-05-01 05:22:21 +03:00
uint16_t num_referrals ;
2009-11-21 23:36:01 +03:00
struct client_dfs_referral * referrals = NULL ;
2010-11-11 16:54:25 +03:00
NTSTATUS status ;
2011-07-07 10:58:25 +04:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2007-11-30 04:25:41 +03:00
2007-12-07 23:02:44 +03:00
* num_refs = 0 ;
* refs = NULL ;
2011-07-06 20:36:29 +04:00
param = talloc_array ( talloc_tos ( ) , uint8_t , 2 ) ;
2007-12-07 23:02:44 +03:00
if ( ! param ) {
2010-11-11 16:54:25 +03:00
status = NT_STATUS_NO_MEMORY ;
2009-07-01 02:29:08 +04:00
goto out ;
2007-12-07 23:02:44 +03:00
}
2017-06-26 19:43:31 +03:00
SSVAL ( param , 0 , max_referral_level ) ;
2005-02-22 06:31:22 +03:00
2012-05-26 14:14:51 +04:00
param = trans2_bytes_push_str ( param , smbXcli_conn_use_unicode ( cli - > conn ) ,
2011-07-06 20:36:29 +04:00
path , strlen ( path ) + 1 ,
NULL ) ;
if ( ! param ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
param_len = talloc_get_size ( param ) ;
path_ucs = ( smb_ucs2_t * ) & param [ 2 ] ;
2005-02-22 06:31:22 +03:00
2013-10-13 18:54:18 +04:00
if ( smbXcli_conn_protocol ( cli - > conn ) > = PROTOCOL_SMB2_02 ) {
DATA_BLOB in_input_buffer ;
DATA_BLOB in_output_buffer = data_blob_null ;
DATA_BLOB out_input_buffer = data_blob_null ;
DATA_BLOB out_output_buffer = data_blob_null ;
in_input_buffer . data = param ;
in_input_buffer . length = param_len ;
status = smb2cli_ioctl ( cli - > conn ,
cli - > timeout ,
cli - > smb2 . session ,
cli - > smb2 . tcon ,
UINT64_MAX , /* in_fid_persistent */
UINT64_MAX , /* in_fid_volatile */
FSCTL_DFS_GET_REFERRALS ,
0 , /* in_max_input_length */
& in_input_buffer ,
CLI_BUFFER_SIZE , /* in_max_output_length */
& in_output_buffer ,
SMB2_IOCTL_FLAG_IS_FSCTL ,
talloc_tos ( ) ,
& out_input_buffer ,
& out_output_buffer ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto out ;
}
2007-11-30 04:25:41 +03:00
2013-10-13 18:54:18 +04:00
if ( out_output_buffer . length < 4 ) {
status = NT_STATUS_INVALID_NETWORK_RESPONSE ;
goto out ;
}
recv_flags2 = FLAGS2_UNICODE_STRINGS ;
rdata = out_output_buffer . data ;
endp = ( char * ) rdata + out_output_buffer . length ;
} else {
unsigned int data_len = 0 ;
uint16_t setup [ 1 ] ;
SSVAL ( setup , 0 , TRANSACT2_GET_DFS_REFERRAL ) ;
status = cli_trans ( talloc_tos ( ) , cli , SMBtrans2 ,
NULL , 0xffff , 0 , 0 ,
setup , 1 , 0 ,
param , param_len , 2 ,
NULL , 0 , CLI_BUFFER_SIZE ,
& recv_flags2 ,
NULL , 0 , NULL , /* rsetup */
NULL , 0 , NULL ,
& rdata , 4 , & data_len ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto out ;
}
endp = ( char * ) rdata + data_len ;
}
2007-12-07 23:02:44 +03:00
2009-07-01 02:29:08 +04:00
consumed_ucs = SVAL ( rdata , 0 ) ;
2007-12-07 23:02:44 +03:00
num_referrals = SVAL ( rdata , 2 ) ;
2009-07-01 02:29:08 +04:00
/* consumed_ucs is the number of bytes
* of the UCS2 path consumed not counting any
* terminating null . We need to convert
* back to unix charset and count again
* to get the number of bytes consumed from
* the incoming path . */
2011-07-06 17:57:22 +04:00
errno = 0 ;
2009-07-01 02:29:08 +04:00
if ( pull_string_talloc ( talloc_tos ( ) ,
NULL ,
0 ,
& consumed_path ,
path_ucs ,
consumed_ucs ,
STR_UNICODE ) = = 0 ) {
2011-07-06 17:57:22 +04:00
if ( errno ! = 0 ) {
status = map_nt_error_from_unix ( errno ) ;
} else {
status = NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
2009-07-01 02:29:08 +04:00
goto out ;
}
if ( consumed_path = = NULL ) {
2011-07-06 17:57:22 +04:00
status = map_nt_error_from_unix ( errno ) ;
2009-07-01 02:29:08 +04:00
goto out ;
}
* consumed = strlen ( consumed_path ) ;
2007-12-07 23:02:44 +03:00
if ( num_referrals ! = 0 ) {
2015-05-01 05:22:21 +03:00
uint16_t ref_version ;
uint16_t ref_size ;
2005-02-22 06:31:22 +03:00
int i ;
2015-05-01 05:22:21 +03:00
uint16_t node_offset ;
2007-03-12 20:55:24 +03:00
2009-11-21 23:36:01 +03:00
referrals = talloc_array ( ctx , struct client_dfs_referral ,
num_referrals ) ;
2007-03-12 20:55:24 +03:00
2007-12-07 23:02:44 +03:00
if ( ! referrals ) {
2011-07-06 17:57:22 +04:00
status = NT_STATUS_NO_MEMORY ;
2007-12-07 23:02:44 +03:00
goto out ;
}
2005-02-22 06:31:22 +03:00
/* start at the referrals array */
2007-11-30 04:25:41 +03:00
2010-11-11 16:54:25 +03:00
p = ( char * ) rdata + 8 ;
2007-12-07 23:02:44 +03:00
for ( i = 0 ; i < num_referrals & & p < endp ; i + + ) {
if ( p + 18 > endp ) {
goto out ;
}
ref_version = SVAL ( p , 0 ) ;
ref_size = SVAL ( p , 2 ) ;
node_offset = SVAL ( p , 16 ) ;
2007-11-30 04:25:41 +03:00
2007-12-07 23:02:44 +03:00
if ( ref_version ! = 3 ) {
2005-02-22 06:31:22 +03:00
p + = ref_size ;
continue ;
}
2007-11-30 04:25:41 +03:00
2007-12-07 23:02:44 +03:00
referrals [ i ] . proximity = SVAL ( p , 8 ) ;
referrals [ i ] . ttl = SVAL ( p , 10 ) ;
2005-02-22 06:31:22 +03:00
2007-12-07 23:02:44 +03:00
if ( p + node_offset > endp ) {
2011-07-06 17:57:22 +04:00
status = NT_STATUS_INVALID_NETWORK_RESPONSE ;
2007-12-07 23:02:44 +03:00
goto out ;
}
2020-05-17 13:57:32 +03:00
pull_string_talloc ( referrals ,
2011-07-06 15:04:26 +04:00
( const char * ) rdata ,
recv_flags2 ,
2009-01-26 05:38:05 +03:00
& referrals [ i ] . dfspath ,
2011-03-24 05:00:37 +03:00
p + node_offset ,
2011-07-06 15:04:26 +04:00
PTR_DIFF ( endp , p + node_offset ) ,
2009-01-26 05:38:05 +03:00
STR_TERMINATE | STR_UNICODE ) ;
2005-02-22 06:31:22 +03:00
2007-12-07 23:02:44 +03:00
if ( ! referrals [ i ] . dfspath ) {
2011-07-06 17:57:22 +04:00
status = map_nt_error_from_unix ( errno ) ;
2007-12-07 23:02:44 +03:00
goto out ;
}
2005-02-22 06:31:22 +03:00
p + = ref_size ;
}
2007-12-07 23:02:44 +03:00
if ( i < num_referrals ) {
2011-07-06 17:57:22 +04:00
status = NT_STATUS_INVALID_NETWORK_RESPONSE ;
2007-12-07 23:02:44 +03:00
goto out ;
}
2005-02-22 06:31:22 +03:00
}
2007-11-30 04:25:41 +03:00
2005-02-22 06:31:22 +03:00
* num_refs = num_referrals ;
* refs = referrals ;
2007-12-07 23:02:44 +03:00
out :
2011-07-07 10:58:25 +04:00
TALLOC_FREE ( frame ) ;
2010-11-11 16:54:25 +03:00
return status ;
2005-02-22 06:31:22 +03:00
}
2017-06-26 19:43:31 +03:00
NTSTATUS cli_dfs_get_referral ( TALLOC_CTX * ctx ,
struct cli_state * cli ,
const char * path ,
struct client_dfs_referral * * refs ,
size_t * num_refs ,
size_t * consumed )
{
return cli_dfs_get_referral_ex ( ctx ,
cli ,
path ,
3 ,
refs , /* Max referral level we want */
num_refs ,
consumed ) ;
}
2020-10-14 08:06:15 +03:00
static bool cli_conn_have_dfs ( struct cli_state * cli )
{
struct smbXcli_conn * conn = cli - > conn ;
struct smbXcli_tcon * tcon = NULL ;
bool ok ;
if ( smbXcli_conn_protocol ( conn ) < PROTOCOL_SMB2_02 ) {
uint32_t capabilities = smb1cli_conn_capabilities ( conn ) ;
if ( ( capabilities & CAP_STATUS32 ) = = 0 ) {
return false ;
}
if ( ( capabilities & CAP_UNICODE ) = = 0 ) {
return false ;
}
tcon = cli - > smb1 . tcon ;
} else {
tcon = cli - > smb2 . tcon ;
}
ok = smbXcli_tcon_is_dfs_share ( tcon ) ;
return ok ;
}
2005-02-23 20:29:28 +03:00
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-01-16 18:21:22 +03:00
struct cli_dfs_path_split {
char * server ;
char * share ;
char * extrapath ;
} ;
2005-02-23 20:29:28 +03:00
2011-07-03 22:53:55 +04:00
NTSTATUS cli_resolve_path ( TALLOC_CTX * ctx ,
const char * mountpt ,
2020-08-18 18:42:25 +03:00
struct cli_credentials * creds ,
2011-07-03 22:53:55 +04:00
struct cli_state * rootcli ,
const char * path ,
struct cli_state * * targetcli ,
char * * pp_targetpath )
2005-02-23 20:29:28 +03:00
{
2009-11-21 23:36:01 +03:00
struct client_dfs_referral * refs = NULL ;
2007-12-07 23:02:44 +03:00
size_t num_refs = 0 ;
2009-07-01 02:29:08 +04:00
size_t consumed = 0 ;
2007-11-30 04:25:41 +03:00
struct cli_state * cli_ipc = NULL ;
char * dfs_path = NULL ;
char * cleanpath = NULL ;
char * extrapath = NULL ;
2005-02-23 20:29:28 +03:00
int pathlen ;
2007-11-30 04:25:41 +03:00
struct cli_state * newcli = NULL ;
2015-01-16 18:21:22 +03:00
struct cli_state * ccli = NULL ;
2019-05-30 10:55:11 +03:00
size_t count = 0 ;
2007-11-30 04:25:41 +03:00
char * newpath = NULL ;
char * newmount = NULL ;
char * ppath = NULL ;
2005-02-23 20:29:28 +03:00
SMB_STRUCT_STAT sbuf ;
2015-05-01 05:22:21 +03:00
uint32_t attributes ;
2010-02-07 16:07:17 +03:00
NTSTATUS status ;
2013-09-27 07:44:33 +04:00
struct smbXcli_tcon * target_tcon = NULL ;
2015-01-16 18:21:22 +03:00
struct cli_dfs_path_split * dfs_refs = NULL ;
2020-10-14 08:06:15 +03:00
bool ok ;
2022-09-02 21:44:47 +03:00
bool is_already_dfs = false ;
2007-11-30 04:25:41 +03:00
2007-03-09 02:54:57 +03:00
if ( ! rootcli | | ! path | | ! targetcli ) {
2011-07-03 22:53:55 +04:00
return NT_STATUS_INVALID_PARAMETER ;
2007-03-09 02:54:57 +03:00
}
2007-11-30 04:25:41 +03:00
2017-06-19 15:13:37 +03:00
/*
* Avoid more than one leading directory separator
*/
while ( IS_DIRECTORY_SEP ( path [ 0 ] ) & & IS_DIRECTORY_SEP ( path [ 1 ] ) ) {
path + + ;
}
2020-10-14 08:06:15 +03:00
ok = cli_conn_have_dfs ( rootcli ) ;
if ( ! ok ) {
2005-02-23 20:29:28 +03:00
* targetcli = rootcli ;
2007-11-30 04:25:41 +03:00
* pp_targetpath = talloc_strdup ( ctx , path ) ;
if ( ! * pp_targetpath ) {
2011-07-03 22:53:55 +04:00
return NT_STATUS_NO_MEMORY ;
2007-11-30 04:25:41 +03:00
}
2011-07-03 22:53:55 +04:00
return NT_STATUS_OK ;
2005-02-23 20:29:28 +03:00
}
2007-03-12 20:55:24 +03:00
* targetcli = NULL ;
2022-09-02 21:44:47 +03:00
is_already_dfs = cli_dfs_is_already_full_path ( rootcli , path ) ;
if ( is_already_dfs ) {
const char * localpath = NULL ;
/*
* Given path is already converted to DFS .
* Convert to a local path so clean_path ( )
* can correctly strip any wildcards .
*/
status = cli_dfs_target_check ( ctx ,
rootcli ,
path ,
& localpath ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
path = localpath ;
}
2007-03-12 20:55:24 +03:00
/* Send a trans2_query_path_info to check for a referral. */
2007-11-30 04:25:41 +03:00
cleanpath = clean_path ( ctx , path ) ;
if ( ! cleanpath ) {
2011-07-03 22:53:55 +04:00
return NT_STATUS_NO_MEMORY ;
2007-11-30 04:25:41 +03:00
}
dfs_path = cli_dfs_make_full_path ( ctx , rootcli , cleanpath ) ;
if ( ! dfs_path ) {
2011-07-03 22:53:55 +04:00
return NT_STATUS_NO_MEMORY ;
2007-11-30 04:25:41 +03:00
}
2007-03-12 20:55:24 +03:00
2010-02-07 16:07:17 +03:00
status = cli_qpathinfo_basic ( rootcli , dfs_path , & sbuf , & attributes ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
2007-03-12 20:55:24 +03:00
/* This is an ordinary path, just return it. */
* targetcli = rootcli ;
2007-11-30 04:25:41 +03:00
* pp_targetpath = talloc_strdup ( ctx , path ) ;
if ( ! * pp_targetpath ) {
2011-07-03 22:53:55 +04:00
return NT_STATUS_NO_MEMORY ;
2007-11-30 04:25:41 +03:00
}
2007-03-12 20:55:24 +03:00
goto done ;
}
/* Special case where client asked for a path that does not exist */
2005-05-10 16:21:02 +04:00
2020-10-14 08:09:13 +03:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ) {
2005-05-10 16:21:02 +04:00
* targetcli = rootcli ;
2007-11-30 04:25:41 +03:00
* pp_targetpath = talloc_strdup ( ctx , path ) ;
if ( ! * pp_targetpath ) {
2011-07-03 22:53:55 +04:00
return NT_STATUS_NO_MEMORY ;
2007-11-30 04:25:41 +03:00
}
2007-03-09 02:54:57 +03:00
goto done ;
2005-05-10 16:21:02 +04:00
}
2007-03-12 20:55:24 +03:00
/* We got an error, check for DFS referral. */
2020-10-14 08:09:13 +03:00
if ( ! NT_STATUS_EQUAL ( status , NT_STATUS_PATH_NOT_COVERED ) ) {
2011-07-03 22:53:55 +04:00
return status ;
2007-03-09 02:54:57 +03:00
}
2005-02-23 20:29:28 +03:00
2007-03-12 20:55:24 +03:00
/* Check for the referral. */
2005-02-23 20:29:28 +03:00
2011-07-03 21:59:37 +04:00
status = cli_cm_open ( ctx ,
rootcli ,
2012-05-19 19:31:50 +04:00
smbXcli_conn_remote_name ( rootcli - > conn ) ,
2011-07-03 21:59:37 +04:00
" IPC$ " ,
2020-08-18 18:26:54 +03:00
creds ,
2018-08-23 10:21:41 +03:00
NULL , /* dest_ss not needed, we reuse the transport */
2011-07-03 21:59:37 +04:00
0 ,
0x20 ,
& cli_ipc ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-07-03 22:53:55 +04:00
return status ;
2007-03-09 02:54:57 +03:00
}
2007-11-30 04:25:41 +03:00
2010-11-11 16:54:25 +03:00
status = cli_dfs_get_referral ( ctx , cli_ipc , dfs_path , & refs ,
& num_refs , & consumed ) ;
2015-09-10 13:34:27 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-07-03 22:53:55 +04:00
return status ;
2005-02-23 20:29:28 +03:00
}
2007-11-30 04:25:41 +03:00
2015-09-10 13:34:27 +03:00
if ( ! num_refs | | ! refs [ 0 ] . dfspath ) {
2011-07-03 22:53:55 +04:00
return NT_STATUS_NOT_FOUND ;
2007-12-07 23:02:44 +03:00
}
2015-01-16 18:21:22 +03:00
/*
* Bug # 10123 - DFS referal entries can be provided in a random order ,
* so check the connection cache for each item to avoid unnecessary
* reconnections .
*/
dfs_refs = talloc_array ( ctx , struct cli_dfs_path_split , num_refs ) ;
if ( dfs_refs = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
for ( count = 0 ; count < num_refs ; count + + ) {
if ( ! split_dfs_path ( dfs_refs , refs [ count ] . dfspath ,
& dfs_refs [ count ] . server ,
& dfs_refs [ count ] . share ,
& dfs_refs [ count ] . extrapath ) ) {
TALLOC_FREE ( dfs_refs ) ;
return NT_STATUS_NOT_FOUND ;
}
ccli = cli_cm_find ( rootcli , dfs_refs [ count ] . server ,
dfs_refs [ count ] . share ) ;
if ( ccli ! = NULL ) {
extrapath = dfs_refs [ count ] . extrapath ;
* targetcli = ccli ;
break ;
}
}
/*
* If no cached connection was found , then connect to the first live
* referral server in the list .
*/
for ( count = 0 ; ( ccli = = NULL ) & & ( count < num_refs ) ; count + + ) {
/* Connect to the target server & share */
status = cli_cm_connect ( ctx , rootcli ,
dfs_refs [ count ] . server ,
dfs_refs [ count ] . share ,
2020-08-18 18:18:16 +03:00
creds ,
2018-08-23 10:20:49 +03:00
NULL , /* dest_ss */
0 , /* port */
2015-01-16 18:21:22 +03:00
0x20 ,
targetcli ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
d_printf ( " Unable to follow dfs referral [ \\ %s \\ %s] \n " ,
dfs_refs [ count ] . server ,
dfs_refs [ count ] . share ) ;
continue ;
} else {
extrapath = dfs_refs [ count ] . extrapath ;
break ;
}
}
/* No available referral server for the connection */
if ( * targetcli = = NULL ) {
TALLOC_FREE ( dfs_refs ) ;
return status ;
2007-11-30 04:25:41 +03:00
}
2007-03-12 20:55:24 +03:00
/* Make sure to recreate the original string including any wildcards. */
2007-11-30 04:25:41 +03:00
dfs_path = cli_dfs_make_full_path ( ctx , rootcli , path ) ;
if ( ! dfs_path ) {
2015-01-16 18:21:22 +03:00
TALLOC_FREE ( dfs_refs ) ;
2011-07-03 22:53:55 +04:00
return NT_STATUS_NO_MEMORY ;
2007-11-30 04:25:41 +03:00
}
2009-07-01 02:29:08 +04:00
pathlen = strlen ( dfs_path ) ;
2007-11-30 04:25:41 +03:00
consumed = MIN ( pathlen , consumed ) ;
2009-07-01 02:29:08 +04:00
* pp_targetpath = talloc_strdup ( ctx , & dfs_path [ consumed ] ) ;
2007-11-30 04:25:41 +03:00
if ( ! * pp_targetpath ) {
2015-01-16 18:21:22 +03:00
TALLOC_FREE ( dfs_refs ) ;
2011-07-03 22:53:55 +04:00
return NT_STATUS_NO_MEMORY ;
2007-11-30 04:25:41 +03:00
}
2009-07-01 02:29:08 +04:00
dfs_path [ consumed ] = ' \0 ' ;
2007-03-12 20:55:24 +03:00
/*
2007-11-30 04:25:41 +03:00
* * pp_targetpath is now the unconsumed part of the path .
* dfs_path is now the consumed part of the path
* ( in \ server \ share \ path format ) .
2007-03-12 20:55:24 +03:00
*/
2007-11-30 04:25:41 +03:00
if ( extrapath & & strlen ( extrapath ) > 0 ) {
2011-03-27 01:39:27 +03:00
/* EMC Celerra NAS version 5.6.50 (at least) doesn't appear to */
2020-10-18 18:40:30 +03:00
/* put the trailing \ on the path, so to be safe we put one in if needed */
2011-03-27 01:39:27 +03:00
if ( extrapath [ strlen ( extrapath ) - 1 ] ! = ' \\ ' & & * * pp_targetpath ! = ' \\ ' ) {
* pp_targetpath = talloc_asprintf ( ctx ,
" %s \\ %s " ,
extrapath ,
* pp_targetpath ) ;
} else {
* pp_targetpath = talloc_asprintf ( ctx ,
" %s%s " ,
extrapath ,
* pp_targetpath ) ;
}
2007-11-30 04:25:41 +03:00
if ( ! * pp_targetpath ) {
2015-01-16 18:21:22 +03:00
TALLOC_FREE ( dfs_refs ) ;
2011-07-03 22:53:55 +04:00
return NT_STATUS_NO_MEMORY ;
2007-11-30 04:25:41 +03:00
}
2007-03-12 20:55:24 +03:00
}
2007-11-30 04:25:41 +03:00
2005-02-26 18:03:16 +03:00
/* parse out the consumed mount path */
/* trim off the \server\share\ */
2005-02-23 23:00:26 +03:00
2007-03-12 20:55:24 +03:00
ppath = dfs_path ;
if ( * ppath ! = ' \\ ' ) {
2007-11-30 04:25:41 +03:00
d_printf ( " cli_resolve_path: "
" dfs_path (%s) not in correct format. \n " ,
2007-03-12 20:55:24 +03:00
dfs_path ) ;
2015-01-16 18:21:22 +03:00
TALLOC_FREE ( dfs_refs ) ;
2011-07-03 22:53:55 +04:00
return NT_STATUS_NOT_FOUND ;
2007-03-09 02:54:57 +03:00
}
2007-03-12 20:55:24 +03:00
ppath + + ; /* Now pointing at start of server name. */
2007-11-30 04:25:41 +03:00
2007-03-12 20:55:24 +03:00
if ( ( ppath = strchr_m ( dfs_path , ' \\ ' ) ) = = NULL ) {
2015-01-16 18:21:22 +03:00
TALLOC_FREE ( dfs_refs ) ;
2011-07-03 22:53:55 +04:00
return NT_STATUS_NOT_FOUND ;
2007-03-09 02:54:57 +03:00
}
2007-03-12 20:55:24 +03:00
ppath + + ; /* Now pointing at start of share name. */
2007-03-09 02:54:57 +03:00
2007-03-12 20:55:24 +03:00
if ( ( ppath = strchr_m ( ppath + 1 , ' \\ ' ) ) = = NULL ) {
2015-01-16 18:21:22 +03:00
TALLOC_FREE ( dfs_refs ) ;
2011-07-03 22:53:55 +04:00
return NT_STATUS_NOT_FOUND ;
2007-03-09 02:54:57 +03:00
}
2007-03-12 20:55:24 +03:00
ppath + + ; /* Now pointing at path component. */
2007-11-30 04:25:41 +03:00
newmount = talloc_asprintf ( ctx , " %s \\ %s " , mountpt , ppath ) ;
if ( ! newmount ) {
2015-01-16 18:21:22 +03:00
TALLOC_FREE ( dfs_refs ) ;
2011-07-03 22:53:55 +04:00
return NT_STATUS_NOT_FOUND ;
2007-11-30 04:25:41 +03:00
}
2007-03-12 20:55:24 +03:00
2007-11-30 04:25:41 +03:00
/* Check for another dfs referral, note that we are not
2007-03-12 20:55:24 +03:00
checking for loops here . */
2005-02-23 23:00:26 +03:00
2007-11-30 04:25:41 +03:00
if ( ! strequal ( * pp_targetpath , " \\ " ) & & ! strequal ( * pp_targetpath , " / " ) ) {
2011-07-03 22:53:55 +04:00
status = cli_resolve_path ( ctx ,
newmount ,
2020-08-18 18:42:25 +03:00
creds ,
2011-07-03 22:53:55 +04:00
* targetcli ,
* pp_targetpath ,
& newcli ,
& newpath ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
2007-03-12 20:55:24 +03:00
/*
* When cli_resolve_path returns true here it ' s always
* returning the complete path in newpath , so we ' re done
* here .
*/
2005-02-24 22:10:28 +03:00
* targetcli = newcli ;
2007-11-30 04:25:41 +03:00
* pp_targetpath = newpath ;
2015-01-16 18:21:22 +03:00
TALLOC_FREE ( dfs_refs ) ;
2011-07-03 22:53:55 +04:00
return status ;
2005-02-24 22:10:28 +03:00
}
2005-02-23 23:00:26 +03:00
}
2005-02-26 18:03:16 +03:00
2007-03-09 02:54:57 +03:00
done :
2013-09-27 07:44:33 +04:00
if ( smbXcli_conn_protocol ( ( * targetcli ) - > conn ) > = PROTOCOL_SMB2_02 ) {
target_tcon = ( * targetcli ) - > smb2 . tcon ;
} else {
target_tcon = ( * targetcli ) - > smb1 . tcon ;
}
2007-11-30 04:25:41 +03:00
/* If returning true ensure we return a dfs root full path. */
2013-09-27 07:44:33 +04:00
if ( smbXcli_tcon_is_dfs_share ( target_tcon ) ) {
2007-11-30 04:25:41 +03:00
dfs_path = talloc_strdup ( ctx , * pp_targetpath ) ;
if ( ! dfs_path ) {
2015-01-16 18:21:22 +03:00
TALLOC_FREE ( dfs_refs ) ;
2011-07-03 22:53:55 +04:00
return NT_STATUS_NO_MEMORY ;
2007-11-30 04:25:41 +03:00
}
* pp_targetpath = cli_dfs_make_full_path ( ctx , * targetcli , dfs_path ) ;
2011-07-03 22:53:55 +04:00
if ( * pp_targetpath = = NULL ) {
2015-01-16 18:21:22 +03:00
TALLOC_FREE ( dfs_refs ) ;
2011-07-03 22:53:55 +04:00
return NT_STATUS_NO_MEMORY ;
}
2007-03-09 02:54:57 +03:00
}
2015-01-16 18:21:22 +03:00
TALLOC_FREE ( dfs_refs ) ;
2011-07-03 22:53:55 +04:00
return NT_STATUS_OK ;
2007-11-30 04:25:41 +03:00
}
2005-05-10 02:39:20 +04:00
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-10-28 22:48:36 +03:00
bool cli_check_msdfs_proxy ( TALLOC_CTX * ctx ,
2007-11-30 04:25:41 +03:00
struct cli_state * cli ,
const char * sharename ,
char * * pp_newserver ,
2007-12-30 09:39:52 +03:00
char * * pp_newshare ,
2016-11-04 14:25:34 +03:00
struct cli_credentials * creds )
2005-05-10 02:39:20 +04:00
{
2009-11-21 23:36:01 +03:00
struct client_dfs_referral * refs = NULL ;
2007-12-07 23:02:44 +03:00
size_t num_refs = 0 ;
2009-07-01 02:29:08 +04:00
size_t consumed = 0 ;
2007-11-30 04:25:41 +03:00
char * fullpath = NULL ;
2007-10-19 04:40:25 +04:00
bool res ;
2017-06-14 02:56:48 +03:00
struct smbXcli_tcon * orig_tcon = NULL ;
2022-08-24 03:28:21 +03:00
char * orig_share = NULL ;
2007-11-30 04:25:41 +03:00
char * newextrapath = NULL ;
2010-01-03 20:46:57 +03:00
NTSTATUS status ;
2011-07-24 17:21:32 +04:00
const char * remote_name ;
2020-08-27 16:52:11 +03:00
enum smb_encryption_setting encryption_state =
cli_credentials_get_smb_encryption ( creds ) ;
2007-11-30 04:25:41 +03:00
if ( ! cli | | ! sharename ) {
return false ;
}
2005-05-10 02:39:20 +04:00
2012-05-19 19:31:50 +04:00
remote_name = smbXcli_conn_remote_name ( cli - > conn ) ;
2006-02-04 01:19:41 +03:00
2005-05-10 02:39:20 +04:00
/* special case. never check for a referral on the IPC$ share */
2007-11-30 04:25:41 +03:00
if ( strequal ( sharename , " IPC$ " ) ) {
return false ;
2007-03-12 20:55:24 +03:00
}
2007-11-30 04:25:41 +03:00
2005-05-10 02:39:20 +04:00
/* send a trans2_query_path_info to check for a referral */
2007-11-30 04:25:41 +03:00
2011-07-22 18:31:18 +04:00
fullpath = talloc_asprintf ( ctx , " \\ %s \\ %s " , remote_name , sharename ) ;
2007-11-30 04:25:41 +03:00
if ( ! fullpath ) {
return false ;
}
2005-05-10 02:39:20 +04:00
2017-06-14 02:56:48 +03:00
/* Store tcon state. */
if ( cli_state_has_tcon ( cli ) ) {
2022-08-24 03:28:21 +03:00
cli_state_save_tcon_share ( cli , & orig_tcon , & orig_share ) ;
2017-06-14 02:56:48 +03:00
}
2005-05-10 02:39:20 +04:00
/* check for the referral */
2016-12-08 09:13:57 +03:00
if ( ! NT_STATUS_IS_OK ( cli_tree_connect ( cli , " IPC$ " , " IPC " , NULL ) ) ) {
2022-08-24 03:28:21 +03:00
cli_state_restore_tcon_share ( cli , orig_tcon , orig_share ) ;
2007-11-30 04:25:41 +03:00
return false ;
2006-02-04 01:19:41 +03:00
}
2020-08-27 16:52:11 +03:00
if ( encryption_state > = SMB_ENCRYPTION_DESIRED ) {
2016-11-04 14:25:34 +03:00
status = cli_cm_force_encryption_creds ( cli , creds , " IPC$ " ) ;
2008-01-05 11:23:35 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2020-08-27 16:52:11 +03:00
switch ( encryption_state ) {
case SMB_ENCRYPTION_DESIRED :
break ;
case SMB_ENCRYPTION_REQUIRED :
default :
2021-01-29 01:32:53 +03:00
/*
* Failed to set up encryption .
* Disconnect the temporary IPC $
* tcon before restoring the original
* tcon so we don ' t leak it .
*/
cli_tdis ( cli ) ;
2022-08-24 03:28:21 +03:00
cli_state_restore_tcon_share ( cli ,
orig_tcon ,
orig_share ) ;
2020-08-27 16:52:11 +03:00
return false ;
}
2008-01-05 11:23:35 +03:00
}
2007-12-30 09:39:52 +03:00
}
2010-11-11 16:54:25 +03:00
status = cli_dfs_get_referral ( ctx , cli , fullpath , & refs ,
& num_refs , & consumed ) ;
res = NT_STATUS_IS_OK ( status ) ;
2006-02-04 01:19:41 +03:00
2010-01-03 20:46:57 +03:00
status = cli_tdis ( cli ) ;
2017-06-14 02:56:48 +03:00
2022-08-24 03:28:21 +03:00
cli_state_restore_tcon_share ( cli , orig_tcon , orig_share ) ;
2017-06-14 02:56:48 +03:00
2010-01-03 20:46:57 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2007-11-30 04:25:41 +03:00
return false ;
2006-02-04 01:19:41 +03:00
}
2007-11-30 04:25:41 +03:00
if ( ! res | | ! num_refs ) {
2007-12-07 23:02:44 +03:00
return false ;
}
if ( ! refs [ 0 ] . dfspath ) {
2007-11-30 04:25:41 +03:00
return false ;
}
2010-11-11 16:04:06 +03:00
if ( ! split_dfs_path ( ctx , refs [ 0 ] . dfspath , pp_newserver ,
pp_newshare , & newextrapath ) ) {
2007-11-30 04:25:41 +03:00
return false ;
2005-05-10 02:39:20 +04:00
}
/* check that this is not a self-referral */
2011-07-22 18:31:18 +04:00
if ( strequal ( remote_name , * pp_newserver ) & &
2007-11-30 04:25:41 +03:00
strequal ( sharename , * pp_newshare ) ) {
return false ;
2006-07-29 00:35:00 +04:00
}
2007-11-30 04:25:41 +03:00
return true ;
2005-05-10 02:39:20 +04:00
}
2022-02-03 22:15:30 +03:00
/********************************************************************
Windows and NetApp ( and arguably the SMB1 / 2 / 3 specs ) expect a non - DFS
path for the targets of rename and hardlink . If we have been given
a DFS path for these calls , convert it back into a local path by
stripping off the DFS prefix .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_dfs_target_check ( TALLOC_CTX * mem_ctx ,
struct cli_state * cli ,
const char * fname_dst ,
const char * * fname_dst_out )
{
char * dfs_prefix = NULL ;
size_t prefix_len = 0 ;
struct smbXcli_tcon * tcon = NULL ;
if ( ! smbXcli_conn_dfs_supported ( cli - > conn ) ) {
goto copy_fname_out ;
}
if ( smbXcli_conn_protocol ( cli - > conn ) > = PROTOCOL_SMB2_02 ) {
tcon = cli - > smb2 . tcon ;
} else {
tcon = cli - > smb1 . tcon ;
}
if ( ! smbXcli_tcon_is_dfs_share ( tcon ) ) {
goto copy_fname_out ;
}
dfs_prefix = cli_dfs_make_full_path ( mem_ctx , cli , " " ) ;
if ( dfs_prefix = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
prefix_len = strlen ( dfs_prefix ) ;
if ( strncmp ( fname_dst , dfs_prefix , prefix_len ) ! = 0 ) {
/*
* Prefix doesn ' t match . Assume it was
* already stripped or not added in the
* first place .
*/
goto copy_fname_out ;
}
/* Return the trailing name after the prefix. */
* fname_dst_out = & fname_dst [ prefix_len ] ;
TALLOC_FREE ( dfs_prefix ) ;
return NT_STATUS_OK ;
copy_fname_out :
/*
* No change to the destination name . Just
* point it at the incoming destination name .
*/
* fname_dst_out = fname_dst ;
TALLOC_FREE ( dfs_prefix ) ;
return NT_STATUS_OK ;
}
2022-09-02 02:07:10 +03:00
/********************************************************************
Convert a pathname into a DFS path if it hasn ' t already been converted .
Always returns a talloc ' ed path , makes it easy to pass const paths in .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
char * smb1_dfs_share_path ( TALLOC_CTX * ctx ,
struct cli_state * cli ,
const char * path )
{
bool is_dfs = smbXcli_conn_dfs_supported ( cli - > conn ) & &
smbXcli_tcon_is_dfs_share ( cli - > smb1 . tcon ) ;
bool is_already_dfs_path = false ;
bool posix = ( cli - > requested_posix_capabilities &
CIFS_UNIX_POSIX_PATHNAMES_CAP ) ;
char sepchar = ( posix ? ' / ' : ' \\ ' ) ;
if ( ! is_dfs ) {
return talloc_strdup ( ctx , path ) ;
}
is_already_dfs_path = cli_dfs_is_already_full_path ( cli , path ) ;
if ( is_already_dfs_path ) {
return talloc_strdup ( ctx , path ) ;
}
/*
* We don ' t use cli_dfs_make_full_path ( ) as ,
* when given a null path , cli_dfs_make_full_path
* deliberately adds a trailing ' \\ ' ( this is by
* design to check for an existing DFS prefix match ) .
*/
if ( path [ 0 ] = = ' \0 ' ) {
return talloc_asprintf ( ctx ,
" %c%s%c%s " ,
sepchar ,
smbXcli_conn_remote_name ( cli - > conn ) ,
sepchar ,
cli - > share ) ;
}
while ( * path = = sepchar ) {
path + + ;
}
return talloc_asprintf ( ctx ,
" %c%s%c%s%c%s " ,
sepchar ,
smbXcli_conn_remote_name ( cli - > conn ) ,
sepchar ,
cli - > share ,
sepchar ,
path ) ;
}