2013-06-21 19:56:08 +04:00
/*
2008-02-28 19:23:20 +03:00
Unix SMB / Netbios implementation .
SMB client library implementation
Copyright ( C ) Andrew Tridgell 1998
Copyright ( C ) Richard Sharpe 2000 , 2002
Copyright ( C ) John Terpstra 2000
2013-06-21 19:56:08 +04:00
Copyright ( C ) Tom Jansen ( Ninja ISD ) 2002
2008-02-28 19:23:20 +03:00
Copyright ( C ) Derrell Lipman 2003 - 2008
Copyright ( C ) Jeremy Allison 2007 , 2008
2009-10-28 22:48:36 +03:00
Copyright ( C ) SATOH Fumiyasu < fumiyas @ osstech . co . jp > 2009.
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +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
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +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 .
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
2011-05-06 13:47:43 +04:00
# include "libsmb/libsmb.h"
2008-02-28 19:23:20 +03:00
# include "libsmbclient.h"
# include "libsmb_internal.h"
2010-05-05 03:39:16 +04:00
# include "../librpc/gen_ndr/ndr_lsa.h"
2011-02-28 12:19:44 +03:00
# include "rpc_client/cli_pipe.h"
2010-05-18 20:26:16 +04:00
# include "rpc_client/cli_lsarpc.h"
2010-10-12 08:27:50 +04:00
# include "libcli/security/security.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"
2008-02-28 19:23:20 +03:00
2013-06-21 19:56:08 +04:00
/*
2008-02-28 19:23:20 +03:00
* Check a server for being alive and well .
2013-06-21 19:56:08 +04:00
* returns 0 if the server is in shape . Returns 1 on error
*
2008-02-28 19:23:20 +03:00
* Also useable outside libsmbclient to enable external cache
* to do some checks too .
*/
int
SMBC_check_server ( SMBCCTX * context ,
2013-06-21 19:56:08 +04:00
SMBCSRV * server )
2008-02-28 19:23:20 +03:00
{
2015-03-19 00:15:16 +03:00
time_t now ;
2011-07-11 16:15:21 +04:00
if ( ! cli_state_is_connected ( server - > cli ) ) {
return 1 ;
}
2008-09-11 20:45:26 +04:00
2015-03-19 00:15:16 +03:00
now = time_mono ( NULL ) ;
if ( server - > last_echo_time = = ( time_t ) 0 | |
now > server - > last_echo_time +
( server - > cli - > timeout / 1000 ) ) {
unsigned char data [ 16 ] = { 0 } ;
NTSTATUS status = cli_echo ( server - > cli ,
1 ,
data_blob_const ( data , sizeof ( data ) ) ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2017-09-09 02:20:34 +03:00
/*
* Some NetApp servers return
* NT_STATUS_INVALID_PARAMETER . That ' s OK , they still
* replied .
* BUG : https : //bugzilla.samba.org/show_bug.cgi?id=13007
*/
if ( ! NT_STATUS_EQUAL ( status ,
NT_STATUS_INVALID_PARAMETER ) ) {
return 1 ;
}
2015-03-19 00:15:16 +03:00
}
server - > last_echo_time = now ;
}
2011-07-11 16:15:21 +04:00
return 0 ;
2008-02-28 19:23:20 +03:00
}
2013-06-21 19:56:08 +04:00
/*
2008-02-28 19:23:20 +03:00
* Remove a server from the cached server list it ' s unused .
* On success , 0 is returned . 1 is returned if the server could not be removed .
2013-06-21 19:56:08 +04:00
*
2008-02-28 19:23:20 +03:00
* Also useable outside libsmbclient
*/
int
SMBC_remove_unused_server ( SMBCCTX * context ,
SMBCSRV * srv )
{
SMBCFILE * file ;
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
/* are we being fooled ? */
2008-02-29 21:34:35 +03:00
if ( ! context | | ! context - > internal - > initialized | | ! srv ) {
2008-02-28 19:23:20 +03:00
return 1 ;
}
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
/* Check all open files/directories for a relation with this server */
2008-02-29 21:34:35 +03:00
for ( file = context - > internal - > files ; file ; file = file - > next ) {
2008-02-28 19:23:20 +03:00
if ( file - > srv = = srv ) {
/* Still used */
DEBUG ( 3 , ( " smbc_remove_usused_server: "
" %p still used by %p. \n " ,
srv , file ) ) ;
return 1 ;
}
}
2008-09-11 20:45:26 +04:00
2008-02-29 21:34:35 +03:00
DLIST_REMOVE ( context - > internal - > servers , srv ) ;
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
cli_shutdown ( srv - > cli ) ;
srv - > cli = NULL ;
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
DEBUG ( 3 , ( " smbc_remove_usused_server: %p removed. \n " , srv ) ) ;
2008-09-11 20:45:26 +04:00
2008-03-04 02:13:33 +03:00
smbc_getFunctionRemoveCachedServer ( context ) ( context , srv ) ;
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
SAFE_FREE ( srv ) ;
return 0 ;
}
/****************************************************************
* Call the auth_fn with fixed size ( fstring ) buffers .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-06-11 12:15:08 +04:00
static void
2008-02-28 19:23:20 +03:00
SMBC_call_auth_fn ( TALLOC_CTX * ctx ,
SMBCCTX * context ,
const char * server ,
const char * share ,
char * * pp_workgroup ,
char * * pp_username ,
char * * pp_password )
{
2016-06-07 11:07:21 +03:00
fstring workgroup = { 0 } ;
fstring username = { 0 } ;
fstring password = { 0 } ;
2008-03-17 18:34:25 +03:00
smbc_get_auth_data_with_context_fn auth_with_context_fn ;
2008-09-11 20:45:26 +04:00
2016-06-07 11:07:21 +03:00
if ( * pp_workgroup ! = NULL ) {
strlcpy ( workgroup , * pp_workgroup , sizeof ( workgroup ) ) ;
}
if ( * pp_username ! = NULL ) {
strlcpy ( username , * pp_username , sizeof ( username ) ) ;
}
if ( * pp_password ! = NULL ) {
strlcpy ( password , * pp_password , sizeof ( password ) ) ;
}
2008-09-11 20:45:26 +04:00
2008-03-17 18:34:25 +03:00
/* See if there's an authentication with context function provided */
auth_with_context_fn = smbc_getFunctionAuthDataWithContext ( context ) ;
if ( auth_with_context_fn )
{
( * auth_with_context_fn ) ( context ,
server , share ,
workgroup , sizeof ( workgroup ) ,
username , sizeof ( username ) ,
password , sizeof ( password ) ) ;
}
else
{
smbc_getFunctionAuthData ( context ) ( server , share ,
workgroup , sizeof ( workgroup ) ,
username , sizeof ( username ) ,
password , sizeof ( password ) ) ;
}
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( * pp_workgroup ) ;
TALLOC_FREE ( * pp_username ) ;
TALLOC_FREE ( * pp_password ) ;
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
* pp_workgroup = talloc_strdup ( ctx , workgroup ) ;
* pp_username = talloc_strdup ( ctx , username ) ;
* pp_password = talloc_strdup ( ctx , password ) ;
}
void
SMBC_get_auth_data ( const char * server , const char * share ,
char * workgroup_buf , int workgroup_buf_len ,
char * username_buf , int username_buf_len ,
char * password_buf , int password_buf_len )
{
/* Default function just uses provided data. Nothing to do. */
}
SMBCSRV *
SMBC_find_server ( TALLOC_CTX * ctx ,
SMBCCTX * context ,
const char * server ,
const char * share ,
char * * pp_workgroup ,
char * * pp_username ,
char * * pp_password )
{
SMBCSRV * srv ;
int auth_called = 0 ;
2008-09-11 20:45:26 +04:00
2008-03-06 17:00:37 +03:00
if ( ! pp_workgroup | | ! pp_username | | ! pp_password ) {
return NULL ;
}
2008-09-11 20:45:26 +04:00
2008-03-02 04:44:21 +03:00
check_server_cache :
2008-09-11 20:45:26 +04:00
2008-03-04 02:13:33 +03:00
srv = smbc_getFunctionGetCachedServer ( context ) ( context ,
server , share ,
* pp_workgroup ,
* pp_username ) ;
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
if ( ! auth_called & & ! srv & & ( ! * pp_username | | ! ( * pp_username ) [ 0 ] | |
2008-03-02 04:44:21 +03:00
! * pp_password | | ! ( * pp_password ) [ 0 ] ) ) {
2008-02-28 19:23:20 +03:00
SMBC_call_auth_fn ( ctx , context , server , share ,
2008-03-02 04:44:21 +03:00
pp_workgroup , pp_username , pp_password ) ;
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
/*
* However , smbc_auth_fn may have picked up info relating to
* an existing connection , so try for an existing connection
* again . . .
*/
auth_called = 1 ;
goto check_server_cache ;
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
}
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
if ( srv ) {
2008-03-04 02:13:33 +03:00
if ( smbc_getFunctionCheckServer ( context ) ( context , srv ) ) {
2008-02-28 19:23:20 +03:00
/*
* This server is no good anymore
* Try to remove it and check for more possible
* servers in the cache
*/
2008-03-04 02:13:33 +03:00
if ( smbc_getFunctionRemoveUnusedServer ( context ) ( context ,
2013-06-21 19:56:08 +04:00
srv ) ) {
2008-02-28 19:23:20 +03:00
/*
* We could not remove the server completely ,
* remove it from the cache so we will not get
* it again . It will be removed when the last
* file / dir is closed .
*/
2008-03-04 02:13:33 +03:00
smbc_getFunctionRemoveCachedServer ( context ) ( context ,
srv ) ;
2008-02-28 19:23:20 +03:00
}
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
/*
* Maybe there are more cached connections to this
* server
*/
goto check_server_cache ;
}
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
return srv ;
}
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
return NULL ;
}
/*
* Connect to a server , possibly on an existing connection
*
* Here , what we want to do is : If the server and username
* match an existing connection , reuse that , otherwise , establish a
* new connection .
*
* If we have to create a new connection , call the auth_fn to get the
* info we need , unless the username and password were passed in .
*/
2009-10-28 22:48:36 +03:00
static SMBCSRV *
SMBC_server_internal ( TALLOC_CTX * ctx ,
2008-02-28 19:23:20 +03:00
SMBCCTX * context ,
bool connect_if_not_found ,
const char * server ,
2013-04-17 01:13:57 +04:00
uint16_t port ,
2008-02-28 19:23:20 +03:00
const char * share ,
char * * pp_workgroup ,
char * * pp_username ,
2009-10-28 22:48:36 +03:00
char * * pp_password ,
bool * in_cache )
2008-02-28 19:23:20 +03:00
{
SMBCSRV * srv = NULL ;
2009-02-20 07:00:46 +03:00
char * workgroup = NULL ;
2011-06-19 21:23:47 +04:00
struct cli_state * c = NULL ;
2008-02-28 19:23:20 +03:00
const char * server_n = server ;
2009-01-17 21:33:25 +03:00
int is_ipc = ( share ! = NULL & & strcmp ( share , " IPC$ " ) = = 0 ) ;
2015-05-10 02:59:45 +03:00
uint32_t fs_attrs = 0 ;
2016-10-25 12:31:07 +03:00
const char * username_used = NULL ;
const char * password_used = NULL ;
2008-02-28 19:23:20 +03:00
NTSTATUS status ;
2009-10-28 22:48:36 +03:00
char * newserver , * newshare ;
2011-09-07 22:35:51 +04:00
int flags = 0 ;
2013-09-27 08:06:32 +04:00
struct smbXcli_tcon * tcon = NULL ;
2015-09-30 22:17:02 +03:00
int signing_state = SMB_SIGNING_DEFAULT ;
2016-10-30 18:42:45 +03:00
struct cli_credentials * creds = NULL ;
bool use_kerberos = false ;
bool fallback_after_kerberos = false ;
bool use_ccache = false ;
bool pw_nt_hash = false ;
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
ZERO_STRUCT ( c ) ;
2009-10-28 22:48:36 +03:00
* in_cache = false ;
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
if ( server [ 0 ] = = 0 ) {
errno = EPERM ;
return NULL ;
}
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
/* Look for a cached connection */
srv = SMBC_find_server ( ctx , context , server , share ,
2008-03-02 04:44:21 +03:00
pp_workgroup , pp_username , pp_password ) ;
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
/*
* If we found a connection and we ' re only allowed one share per
* server . . .
*/
2008-03-04 02:13:33 +03:00
if ( srv & &
2012-12-18 19:06:19 +04:00
share ! = NULL & & * share ! = ' \0 ' & &
2008-03-04 02:13:33 +03:00
smbc_getOptionOneSharePerServer ( context ) ) {
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
/*
* . . . then if there ' s no current connection to the share ,
* connect to it . SMBC_find_server ( ) , or rather the function
2008-03-04 02:13:33 +03:00
* pointed to by context - > get_cached_srv_fn which
2008-02-28 19:23:20 +03:00
* was called by SMBC_find_server ( ) , will have issued a tree
* disconnect if the requested share is not the same as the
* one that was already connected .
*/
2009-10-28 22:48:36 +03:00
/*
* Use srv - > cli - > desthost and srv - > cli - > share instead of
* server and share below to connect to the actual share ,
* i . e . , a normal share or a referred share from
* ' msdfs proxy ' share .
*/
2011-07-19 18:25:52 +04:00
if ( ! cli_state_has_tcon ( srv - > cli ) ) {
2008-02-28 19:23:20 +03:00
/* Ensure we have accurate auth info */
2009-10-28 22:48:36 +03:00
SMBC_call_auth_fn ( ctx , context ,
2012-05-19 19:31:50 +04:00
smbXcli_conn_remote_name ( srv - > cli - > conn ) ,
2009-10-28 22:48:36 +03:00
srv - > cli - > share ,
2008-03-02 04:44:21 +03:00
pp_workgroup ,
pp_username ,
pp_password ) ;
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
if ( ! * pp_workgroup | | ! * pp_username | | ! * pp_password ) {
errno = ENOMEM ;
cli_shutdown ( srv - > cli ) ;
srv - > cli = NULL ;
2008-03-04 02:13:33 +03:00
smbc_getFunctionRemoveCachedServer ( context ) ( context ,
srv ) ;
2008-02-28 19:23:20 +03:00
return NULL ;
}
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
/*
* We don ' t need to renegotiate encryption
* here as the encryption context is not per
* tid .
*/
2008-09-11 20:45:26 +04:00
2011-10-31 20:51:11 +04:00
status = cli_tree_connect ( srv - > cli ,
srv - > cli - > share ,
" ????? " ,
2016-12-08 09:13:57 +03:00
* pp_password ) ;
2009-01-26 10:37:13 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-02-28 19:23:20 +03:00
cli_shutdown ( srv - > cli ) ;
2017-11-02 17:25:11 +03:00
errno = map_errno_from_nt_status ( status ) ;
2008-02-28 19:23:20 +03:00
srv - > cli = NULL ;
2008-03-04 02:13:33 +03:00
smbc_getFunctionRemoveCachedServer ( context ) ( context ,
srv ) ;
2008-02-28 19:23:20 +03:00
srv = NULL ;
}
2008-09-11 20:45:26 +04:00
2009-01-17 21:33:25 +03:00
/* Determine if this share supports case sensitivity */
if ( is_ipc ) {
DEBUG ( 4 ,
( " IPC$ so ignore case sensitivity \n " ) ) ;
2011-07-07 19:18:40 +04:00
status = NT_STATUS_OK ;
} else {
status = cli_get_fs_attr_info ( c , & fs_attrs ) ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-01-17 21:33:25 +03:00
DEBUG ( 4 , ( " Could not retrieve "
" case sensitivity flag: %s. \n " ,
2011-07-07 19:18:40 +04:00
nt_errstr ( status ) ) ) ;
2009-01-17 21:33:25 +03:00
/*
* We can ' t determine the case sensitivity of
* the share . We have no choice but to use the
* user - specified case sensitivity setting .
*/
if ( smbc_getOptionCaseSensitive ( context ) ) {
cli_set_case_sensitive ( c , True ) ;
} else {
cli_set_case_sensitive ( c , False ) ;
}
2011-07-07 19:18:40 +04:00
} else if ( ! is_ipc ) {
2009-01-17 21:33:25 +03:00
DEBUG ( 4 ,
( " Case sensitive: %s \n " ,
( fs_attrs & FILE_CASE_SENSITIVE_SEARCH
? " True "
: " False " ) ) ) ;
cli_set_case_sensitive (
c ,
( fs_attrs & FILE_CASE_SENSITIVE_SEARCH
? True
: False ) ) ;
}
2008-02-28 19:23:20 +03:00
/*
* Regenerate the dev value since it ' s based on both
* server and share
*/
if ( srv ) {
2011-07-22 18:34:29 +04:00
const char * remote_name =
2012-05-19 19:31:50 +04:00
smbXcli_conn_remote_name ( srv - > cli - > conn ) ;
2011-07-22 18:34:29 +04:00
srv - > dev = ( dev_t ) ( str_checksum ( remote_name ) ^
2009-10-28 22:48:36 +03:00
str_checksum ( srv - > cli - > share ) ) ;
2008-02-28 19:23:20 +03:00
}
}
}
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
/* If we have a connection... */
if ( srv ) {
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
/* ... then we're done here. Give 'em what they came for. */
2009-10-28 22:48:36 +03:00
* in_cache = true ;
2009-02-20 07:00:46 +03:00
goto done ;
2008-02-28 19:23:20 +03:00
}
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
/* If we're not asked to connect when a connection doesn't exist... */
if ( ! connect_if_not_found ) {
/* ... then we're done here. */
return NULL ;
}
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
if ( ! * pp_workgroup | | ! * pp_username | | ! * pp_password ) {
errno = ENOMEM ;
return NULL ;
}
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
DEBUG ( 4 , ( " SMBC_server: server_n=[%s] server=[%s] \n " , server_n , server ) ) ;
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
DEBUG ( 4 , ( " -> server_n=[%s] server=[%s] \n " , server_n , server ) ) ;
2008-09-11 20:45:26 +04:00
2011-05-29 22:22:38 +04:00
status = NT_STATUS_UNSUCCESSFUL ;
2008-09-11 20:45:26 +04:00
2011-09-07 22:35:51 +04:00
if ( smbc_getOptionUseKerberos ( context ) ) {
flags | = CLI_FULL_CONNECTION_USE_KERBEROS ;
2016-10-30 18:42:45 +03:00
use_kerberos = true ;
2011-09-07 22:35:51 +04:00
}
if ( smbc_getOptionFallbackAfterKerberos ( context ) ) {
flags | = CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS ;
2016-10-30 18:42:45 +03:00
fallback_after_kerberos = true ;
2011-09-07 22:35:51 +04:00
}
if ( smbc_getOptionUseCCache ( context ) ) {
flags | = CLI_FULL_CONNECTION_USE_CCACHE ;
2016-10-30 18:42:45 +03:00
use_ccache = true ;
2011-09-07 22:35:51 +04:00
}
2012-06-11 15:29:10 +04:00
if ( smbc_getOptionUseNTHash ( context ) ) {
flags | = CLI_FULL_CONNECTION_USE_NT_HASH ;
2016-10-30 18:42:45 +03:00
pw_nt_hash = true ;
2012-06-11 15:29:10 +04:00
}
2015-09-30 22:17:02 +03:00
if ( context - > internal - > smb_encryption_level ! = SMBC_ENCRYPTLEVEL_NONE ) {
signing_state = SMB_SIGNING_REQUIRED ;
}
2013-04-17 01:13:57 +04:00
if ( port = = 0 ) {
if ( share = = NULL | | * share = = ' \0 ' | | is_ipc ) {
/*
* Try 139 first for IPC $
*/
status = cli_connect_nb ( server_n , NULL , NBT_SMB_PORT , 0x20 ,
2011-05-29 22:22:38 +04:00
smbc_getNetbiosName ( context ) ,
2015-09-30 22:17:02 +03:00
signing_state , flags , & c ) ;
2013-04-17 01:13:57 +04:00
}
2011-05-29 22:22:38 +04:00
}
2008-09-11 20:45:26 +04:00
2011-05-29 22:22:38 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
/*
* No IPC $ or 139 did not work
*/
2013-04-17 01:13:57 +04:00
status = cli_connect_nb ( server_n , NULL , port , 0x20 ,
2011-05-29 22:22:38 +04:00
smbc_getNetbiosName ( context ) ,
2015-09-30 22:17:02 +03:00
signing_state , flags , & c ) ;
2011-05-29 22:22:38 +04:00
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
errno = map_errno_from_nt_status ( status ) ;
2008-02-28 19:23:20 +03:00
return NULL ;
}
2008-09-11 20:45:26 +04:00
2011-08-02 06:16:01 +04:00
cli_set_timeout ( c , smbc_getTimeout ( context ) ) ;
2008-09-11 20:45:26 +04:00
2013-08-11 16:01:36 +04:00
status = smbXcli_negprot ( c - > conn , c - > timeout ,
2014-02-04 06:09:08 +04:00
lp_client_min_protocol ( ) ,
2014-02-04 06:09:08 +04:00
lp_client_max_protocol ( ) ) ;
2008-09-11 20:57:49 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-02-28 19:23:20 +03:00
cli_shutdown ( c ) ;
2018-05-02 21:19:31 +03:00
errno = map_errno_from_nt_status ( status ) ;
2008-02-28 19:23:20 +03:00
return NULL ;
}
2008-09-11 20:45:26 +04:00
2014-08-21 10:32:36 +04:00
if ( smbXcli_conn_protocol ( c - > conn ) > = PROTOCOL_SMB2_02 ) {
/* Ensure we ask for some initial credits. */
smb2cli_conn_set_max_credits ( c - > conn , DEFAULT_SMB2_MAX_CREDITS ) ;
}
2016-10-25 12:31:07 +03:00
username_used = * pp_username ;
password_used = * pp_password ;
2008-09-11 20:45:26 +04:00
2016-10-30 18:42:45 +03:00
creds = cli_session_creds_init ( c ,
username_used ,
* pp_workgroup ,
NULL , /* realm */
password_used ,
use_kerberos ,
fallback_after_kerberos ,
use_ccache ,
pw_nt_hash ) ;
if ( creds = = NULL ) {
cli_shutdown ( c ) ;
errno = ENOMEM ;
return NULL ;
}
status = cli_session_setup_creds ( c , creds ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
/* Failed. Try an anonymous login, if allowed by flags. */
2016-10-25 12:31:07 +03:00
username_used = " " ;
password_used = " " ;
2008-09-11 20:45:26 +04:00
2008-03-04 02:13:33 +03:00
if ( smbc_getOptionNoAutoAnonymousLogin ( context ) | |
2016-10-30 18:42:45 +03:00
! NT_STATUS_IS_OK ( cli_session_setup_anon ( c ) ) ) {
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
cli_shutdown ( c ) ;
errno = EPERM ;
return NULL ;
}
2009-10-23 02:06:38 +04:00
}
2008-02-28 19:23:20 +03:00
DEBUG ( 4 , ( " session setup ok \n " ) ) ;
2008-09-11 20:45:26 +04:00
2009-10-28 22:48:36 +03:00
/* here's the fun part....to support 'msdfs proxy' shares
( on Samba or windows ) we have to issues a TRANS_GET_DFS_REFERRAL
here before trying to connect to the original share .
cli_check_msdfs_proxy ( ) will fail if it is a normal share . */
2013-05-17 22:46:24 +04:00
if ( smbXcli_conn_dfs_supported ( c - > conn ) & &
2009-10-28 22:48:36 +03:00
cli_check_msdfs_proxy ( ctx , c , share ,
& newserver , & newshare ,
/* FIXME: cli_check_msdfs_proxy() does
not support smbc_smb_encrypt_level type */
context - > internal - > smb_encryption_level ?
true : false ,
2016-11-04 14:25:34 +03:00
creds ) ) {
2009-10-28 22:48:36 +03:00
cli_shutdown ( c ) ;
srv = SMBC_server_internal ( ctx , context , connect_if_not_found ,
2013-04-17 01:13:57 +04:00
newserver , port , newshare , pp_workgroup ,
2009-10-28 22:48:36 +03:00
pp_username , pp_password , in_cache ) ;
TALLOC_FREE ( newserver ) ;
TALLOC_FREE ( newshare ) ;
return srv ;
}
/* must be a normal share */
2016-12-12 08:00:32 +03:00
status = cli_tree_connect_creds ( c , share , " ????? " , creds ) ;
2009-01-26 10:37:13 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-02-28 19:23:20 +03:00
cli_shutdown ( c ) ;
2017-11-02 17:25:11 +03:00
errno = map_errno_from_nt_status ( status ) ;
2008-02-28 19:23:20 +03:00
return NULL ;
}
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
DEBUG ( 4 , ( " tconx ok \n " ) ) ;
2008-09-11 20:45:26 +04:00
2013-09-27 08:06:32 +04:00
if ( smbXcli_conn_protocol ( c - > conn ) > = PROTOCOL_SMB2_02 ) {
tcon = c - > smb2 . tcon ;
} else {
tcon = c - > smb1 . tcon ;
}
2009-01-17 21:33:25 +03:00
/* Determine if this share supports case sensitivity */
if ( is_ipc ) {
DEBUG ( 4 , ( " IPC$ so ignore case sensitivity \n " ) ) ;
2011-07-08 03:55:26 +04:00
status = NT_STATUS_OK ;
} else {
status = cli_get_fs_attr_info ( c , & fs_attrs ) ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-01-17 21:33:25 +03:00
DEBUG ( 4 , ( " Could not retrieve case sensitivity flag: %s. \n " ,
2011-07-08 03:55:26 +04:00
nt_errstr ( status ) ) ) ;
2009-01-17 21:33:25 +03:00
/*
* We can ' t determine the case sensitivity of the share . We
* have no choice but to use the user - specified case
* sensitivity setting .
*/
if ( smbc_getOptionCaseSensitive ( context ) ) {
cli_set_case_sensitive ( c , True ) ;
} else {
cli_set_case_sensitive ( c , False ) ;
}
2011-07-08 03:55:26 +04:00
} else if ( ! is_ipc ) {
2009-01-17 21:33:25 +03:00
DEBUG ( 4 , ( " Case sensitive: %s \n " ,
( fs_attrs & FILE_CASE_SENSITIVE_SEARCH
? " True "
: " False " ) ) ) ;
2013-09-27 08:06:32 +04:00
smbXcli_tcon_set_fs_attributes ( tcon , fs_attrs ) ;
2009-01-17 21:33:25 +03:00
}
2008-02-29 21:34:35 +03:00
if ( context - > internal - > smb_encryption_level ) {
2016-11-03 17:11:29 +03:00
/* Attempt encryption. */
2016-11-03 19:27:49 +03:00
status = cli_cm_force_encryption_creds ( c ,
creds ,
share ) ;
2016-11-03 17:11:29 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
/*
* context - > smb_encryption_level = = 1
* means don ' t fail if encryption can ' t be negotiated ,
* = = 2 means fail if encryption can ' t be negotiated .
*/
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
DEBUG ( 4 , ( " SMB encrypt failed \n " ) ) ;
2008-09-11 20:45:26 +04:00
2008-02-29 21:34:35 +03:00
if ( context - > internal - > smb_encryption_level = = 2 ) {
2008-02-28 19:23:20 +03:00
cli_shutdown ( c ) ;
errno = EPERM ;
return NULL ;
}
}
DEBUG ( 4 , ( " SMB encrypt ok \n " ) ) ;
}
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
/*
* Ok , we have got a nice connection
* Let ' s allocate a server structure .
*/
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
srv = SMB_MALLOC_P ( SMBCSRV ) ;
if ( ! srv ) {
2009-10-28 22:48:36 +03:00
cli_shutdown ( c ) ;
2008-02-28 19:23:20 +03:00
errno = ENOMEM ;
2009-10-28 22:48:36 +03:00
return NULL ;
2008-02-28 19:23:20 +03:00
}
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
ZERO_STRUCTP ( srv ) ;
2015-12-16 22:04:20 +03:00
DLIST_ADD ( srv - > cli , c ) ;
2008-02-28 19:23:20 +03:00
srv - > dev = ( dev_t ) ( str_checksum ( server ) ^ str_checksum ( share ) ) ;
srv - > no_pathinfo = False ;
srv - > no_pathinfo2 = False ;
2013-10-11 13:02:24 +04:00
srv - > no_pathinfo3 = False ;
2008-02-28 19:23:20 +03:00
srv - > no_nt_session = False ;
2008-09-11 20:45:26 +04:00
2009-02-20 07:00:46 +03:00
done :
if ( ! pp_workgroup | | ! * pp_workgroup | | ! * * pp_workgroup ) {
workgroup = talloc_strdup ( ctx , smbc_getWorkgroup ( context ) ) ;
} else {
workgroup = * pp_workgroup ;
}
if ( ! workgroup ) {
2011-06-19 21:23:47 +04:00
if ( c ! = NULL ) {
cli_shutdown ( c ) ;
}
SAFE_FREE ( srv ) ;
2009-02-20 07:00:46 +03:00
return NULL ;
}
2009-10-28 22:48:36 +03:00
2009-02-20 07:00:46 +03:00
/* set the credentials to make DFS work */
smbc_set_credentials_with_fallback ( context ,
workgroup ,
* pp_username ,
* pp_password ) ;
2009-10-28 22:48:36 +03:00
2008-02-28 19:23:20 +03:00
return srv ;
2009-10-28 22:48:36 +03:00
}
SMBCSRV *
SMBC_server ( TALLOC_CTX * ctx ,
SMBCCTX * context ,
bool connect_if_not_found ,
const char * server ,
2013-04-17 01:11:08 +04:00
uint16_t port ,
2009-10-28 22:48:36 +03:00
const char * share ,
char * * pp_workgroup ,
char * * pp_username ,
char * * pp_password )
{
SMBCSRV * srv = NULL ;
bool in_cache = false ;
srv = SMBC_server_internal ( ctx , context , connect_if_not_found ,
2013-04-17 01:13:57 +04:00
server , port , share , pp_workgroup ,
2009-10-28 22:48:36 +03:00
pp_username , pp_password , & in_cache ) ;
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
if ( ! srv ) {
return NULL ;
}
2009-10-28 22:48:36 +03:00
if ( in_cache ) {
return srv ;
}
/* Now add it to the cache (internal or external) */
/* Let the cache function set errno if it wants to */
errno = 0 ;
if ( smbc_getFunctionAddCachedServer ( context ) ( context , srv ,
server , share ,
* pp_workgroup ,
* pp_username ) ) {
int saved_errno = errno ;
DEBUG ( 3 , ( " Failed to add server to cache \n " ) ) ;
errno = saved_errno ;
if ( errno = = 0 ) {
errno = ENOMEM ;
}
SAFE_FREE ( srv ) ;
return NULL ;
}
2008-09-11 20:45:26 +04:00
2009-10-28 22:48:36 +03:00
DEBUG ( 2 , ( " Server connect ok: //%s/%s: %p \n " ,
server , share , srv ) ) ;
DLIST_ADD ( context - > internal - > servers , srv ) ;
return srv ;
2008-02-28 19:23:20 +03:00
}
/*
* Connect to a server for getting / setting attributes , possibly on an existing
* connection . This works similarly to SMBC_server ( ) .
*/
SMBCSRV *
SMBC_attr_server ( TALLOC_CTX * ctx ,
SMBCCTX * context ,
const char * server ,
2013-04-16 23:22:11 +04:00
uint16_t port ,
2008-02-28 19:23:20 +03:00
const char * share ,
char * * pp_workgroup ,
char * * pp_username ,
char * * pp_password )
{
int flags ;
2009-11-13 00:56:33 +03:00
struct cli_state * ipc_cli = NULL ;
struct rpc_pipe_client * pipe_hnd = NULL ;
2008-02-28 19:23:20 +03:00
NTSTATUS nt_status ;
2009-10-28 22:48:36 +03:00
SMBCSRV * srv = NULL ;
2008-02-28 19:23:20 +03:00
SMBCSRV * ipc_srv = NULL ;
2008-09-11 20:45:26 +04:00
2009-10-28 22:48:36 +03:00
/*
* Use srv - > cli - > desthost and srv - > cli - > share instead of
* server and share below to connect to the actual share ,
* i . e . , a normal share or a referred share from
* ' msdfs proxy ' share .
*/
2013-04-17 01:11:08 +04:00
srv = SMBC_server ( ctx , context , true , server , port , share ,
2009-10-28 22:48:36 +03:00
pp_workgroup , pp_username , pp_password ) ;
if ( ! srv ) {
return NULL ;
}
2012-05-19 19:31:50 +04:00
server = smbXcli_conn_remote_name ( srv - > cli - > conn ) ;
2009-10-28 22:48:36 +03:00
share = srv - > cli - > share ;
2008-02-28 19:23:20 +03:00
/*
* See if we ' ve already created this special connection . Reference
* our " special " share name ' * IPC $ ' , which is an impossible real share
* name due to the leading asterisk .
*/
ipc_srv = SMBC_find_server ( ctx , context , server , " *IPC$ " ,
2008-03-02 04:44:21 +03:00
pp_workgroup , pp_username , pp_password ) ;
2008-02-28 19:23:20 +03:00
if ( ! ipc_srv ) {
2015-09-30 22:17:02 +03:00
int signing_state = SMB_SIGNING_DEFAULT ;
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
/* We didn't find a cached connection. Get the password */
if ( ! * pp_password | | ( * pp_password ) [ 0 ] = = ' \0 ' ) {
/* ... then retrieve it now. */
SMBC_call_auth_fn ( ctx , context , server , share ,
2008-03-02 04:44:21 +03:00
pp_workgroup ,
pp_username ,
pp_password ) ;
2008-02-28 19:23:20 +03:00
if ( ! * pp_workgroup | | ! * pp_username | | ! * pp_password ) {
errno = ENOMEM ;
return NULL ;
}
}
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
flags = 0 ;
2008-03-04 02:13:33 +03:00
if ( smbc_getOptionUseKerberos ( context ) ) {
2008-02-28 19:23:20 +03:00
flags | = CLI_FULL_CONNECTION_USE_KERBEROS ;
}
2010-01-24 21:24:10 +03:00
if ( smbc_getOptionUseCCache ( context ) ) {
flags | = CLI_FULL_CONNECTION_USE_CCACHE ;
}
2015-09-30 22:17:02 +03:00
if ( context - > internal - > smb_encryption_level ! = SMBC_ENCRYPTLEVEL_NONE ) {
signing_state = SMB_SIGNING_REQUIRED ;
}
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
nt_status = cli_full_connection ( & ipc_cli ,
2011-06-09 09:31:03 +04:00
lp_netbios_name ( ) , server ,
2011-07-22 14:25:44 +04:00
NULL , 0 , " IPC$ " , " ????? " ,
2008-02-28 19:23:20 +03:00
* pp_username ,
* pp_workgroup ,
* pp_password ,
flags ,
2015-09-30 22:17:02 +03:00
signing_state ) ;
2008-02-28 19:23:20 +03:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
DEBUG ( 1 , ( " cli_full_connection failed! (%s) \n " ,
nt_errstr ( nt_status ) ) ) ;
errno = ENOTSUP ;
return NULL ;
}
2008-09-11 20:45:26 +04:00
2008-02-29 21:34:35 +03:00
if ( context - > internal - > smb_encryption_level ) {
2016-11-03 17:11:29 +03:00
/* Attempt encryption. */
nt_status = cli_cm_force_encryption ( ipc_cli ,
* pp_username ,
* pp_password ,
* pp_workgroup ,
" IPC$ " ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
/*
* context - > smb_encryption_level = =
* 1 means don ' t fail if encryption can ' t be
* negotiated , = = 2 means fail if encryption
* can ' t be negotiated .
*/
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
DEBUG ( 4 , ( " SMB encrypt failed on IPC$ \n " ) ) ;
2008-09-11 20:45:26 +04:00
2008-02-29 21:34:35 +03:00
if ( context - > internal - > smb_encryption_level = = 2 ) {
2008-02-28 19:23:20 +03:00
cli_shutdown ( ipc_cli ) ;
errno = EPERM ;
return NULL ;
}
}
DEBUG ( 4 , ( " SMB encrypt ok on IPC$ \n " ) ) ;
}
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
ipc_srv = SMB_MALLOC_P ( SMBCSRV ) ;
if ( ! ipc_srv ) {
errno = ENOMEM ;
cli_shutdown ( ipc_cli ) ;
return NULL ;
}
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
ZERO_STRUCTP ( ipc_srv ) ;
2015-12-16 22:04:20 +03:00
DLIST_ADD ( ipc_srv - > cli , ipc_cli ) ;
2008-09-11 20:45:26 +04:00
2008-07-20 13:04:31 +04:00
nt_status = cli_rpc_pipe_open_noauth (
2013-05-24 15:29:28 +04:00
ipc_srv - > cli , & ndr_table_lsarpc , & pipe_hnd ) ;
2008-07-20 13:04:31 +04:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
2008-03-02 04:44:21 +03:00
DEBUG ( 1 , ( " cli_nt_session_open fail! \n " ) ) ;
errno = ENOTSUP ;
cli_shutdown ( ipc_srv - > cli ) ;
free ( ipc_srv ) ;
return NULL ;
2008-02-28 19:23:20 +03:00
}
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
/*
* Some systems don ' t support
2009-04-15 03:12:13 +04:00
* SEC_FLAG_MAXIMUM_ALLOWED , but NT sends 0x2000000
2008-02-28 19:23:20 +03:00
* so we might as well do it too .
*/
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
nt_status = rpccli_lsa_open_policy (
2008-03-02 04:44:21 +03:00
pipe_hnd ,
talloc_tos ( ) ,
True ,
GENERIC_EXECUTE_ACCESS ,
& ipc_srv - > pol ) ;
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
2008-03-02 04:44:21 +03:00
errno = SMBC_errno ( context , ipc_srv - > cli ) ;
cli_shutdown ( ipc_srv - > cli ) ;
2013-02-20 13:38:13 +04:00
free ( ipc_srv ) ;
2008-03-02 04:44:21 +03:00
return NULL ;
2008-02-28 19:23:20 +03:00
}
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
/* now add it to the cache (internal or external) */
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
errno = 0 ; /* let cache function set errno if it likes */
2008-03-04 02:13:33 +03:00
if ( smbc_getFunctionAddCachedServer ( context ) ( context , ipc_srv ,
server ,
" *IPC$ " ,
* pp_workgroup ,
* pp_username ) ) {
2008-02-28 19:23:20 +03:00
DEBUG ( 3 , ( " Failed to add server to cache \n " ) ) ;
if ( errno = = 0 ) {
errno = ENOMEM ;
}
cli_shutdown ( ipc_srv - > cli ) ;
free ( ipc_srv ) ;
return NULL ;
}
2008-09-11 20:45:26 +04:00
2008-02-29 21:34:35 +03:00
DLIST_ADD ( context - > internal - > servers , ipc_srv ) ;
2008-02-28 19:23:20 +03:00
}
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
return ipc_srv ;
}