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
Copyright ( C ) Tom Jansen ( Ninja ISD ) 2002
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"
2008-02-28 19:23:20 +03:00
/*
* Check a server for being alive and well .
* returns 0 if the server is in shape . Returns 1 on error
*
* Also useable outside libsmbclient to enable external cache
* to do some checks too .
*/
int
SMBC_check_server ( SMBCCTX * context ,
SMBCSRV * server )
{
socklen_t size ;
struct sockaddr addr ;
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
size = sizeof ( addr ) ;
return ( getpeername ( server - > cli - > fd , & addr , & size ) = = - 1 ) ;
}
/*
* 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 .
*
* 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 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void
SMBC_call_auth_fn ( TALLOC_CTX * ctx ,
SMBCCTX * context ,
const char * server ,
const char * share ,
char * * pp_workgroup ,
char * * pp_username ,
char * * pp_password )
{
fstring workgroup ;
fstring username ;
fstring password ;
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
2008-02-28 19:23:20 +03:00
strlcpy ( workgroup , * pp_workgroup , sizeof ( workgroup ) ) ;
strlcpy ( username , * pp_username , sizeof ( username ) ) ;
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 ,
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 ,
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 ) ;
uint32 fs_attrs = 0 ;
2008-02-28 19:23:20 +03:00
const char * username_used ;
NTSTATUS status ;
2009-10-28 22:48:36 +03:00
char * newserver , * newshare ;
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 & &
* share ! = ' \0 ' & &
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 .
*/
2008-02-28 19:23:20 +03:00
if ( srv - > cli - > cnum = = ( uint16 ) - 1 ) {
/* Ensure we have accurate auth info */
2009-10-28 22:48:36 +03:00
SMBC_call_auth_fn ( ctx , context ,
srv - > cli - > desthost ,
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
2009-10-28 22:48:36 +03:00
status = cli_tcon_andx ( srv - > cli , srv - > cli - > share , " ????? " ,
2009-01-26 10:37:13 +03:00
* pp_password ,
strlen ( * pp_password ) + 1 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
errno = map_errno_from_nt_status ( status ) ;
2008-02-28 19:23:20 +03:00
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
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 ) {
2009-10-28 22:48:36 +03:00
srv - > dev = ( dev_t ) ( str_checksum ( srv - > cli - > desthost ) ^
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-05-29 22:22:38 +04:00
if ( share = = NULL | | * share = = ' \0 ' | | is_ipc ) {
/*
* Try 139 first for IPC $
*/
status = cli_connect_nb ( server_n , NULL , 139 , 0x20 ,
smbc_getNetbiosName ( context ) ,
Undefined , & c ) ;
}
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
*/
status = cli_connect_nb ( server_n , NULL , 0 , 0x20 ,
smbc_getNetbiosName ( context ) ,
Undefined , & c ) ;
}
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
2008-03-04 02:13:33 +03:00
if ( smbc_getOptionUseKerberos ( context ) ) {
2008-02-28 19:23:20 +03:00
c - > use_kerberos = True ;
}
2008-03-04 02:13:33 +03:00
if ( smbc_getOptionFallbackAfterKerberos ( context ) ) {
2008-02-28 19:23:20 +03:00
c - > fallback_after_kerberos = True ;
}
2008-09-11 20:45:26 +04:00
2010-01-24 21:24:10 +03:00
if ( smbc_getOptionUseCCache ( context ) ) {
c - > use_ccache = True ;
}
2008-03-04 02:13:33 +03:00
c - > timeout = smbc_getTimeout ( context ) ;
2008-09-11 20:45:26 +04:00
2008-09-11 20:57:49 +04:00
status = cli_negprot ( c ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-02-28 19:23:20 +03:00
cli_shutdown ( c ) ;
errno = ETIMEDOUT ;
return NULL ;
}
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
username_used = * pp_username ;
2008-09-11 20:45:26 +04:00
2008-02-28 19:23:20 +03:00
if ( ! NT_STATUS_IS_OK ( cli_session_setup ( c , username_used ,
2008-03-02 04:44:21 +03:00
* pp_password ,
strlen ( * pp_password ) ,
* pp_password ,
strlen ( * pp_password ) ,
2008-02-28 19:23:20 +03:00
* pp_workgroup ) ) ) {
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. */
username_used = " " ;
2008-09-11 20:45:26 +04:00
2008-03-04 02:13:33 +03:00
if ( smbc_getOptionNoAutoAnonymousLogin ( context ) | |
2008-02-28 19:23:20 +03:00
! NT_STATUS_IS_OK ( cli_session_setup ( c , username_used ,
* pp_password , 1 ,
* pp_password , 0 ,
* pp_workgroup ) ) ) {
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
}
2009-10-23 02:26:22 +04:00
status = cli_init_creds ( c , username_used ,
* pp_workgroup , * pp_password ) ;
2009-10-23 02:06:38 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
errno = map_errno_from_nt_status ( status ) ;
cli_shutdown ( c ) ;
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
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 . */
if ( ( c - > capabilities & CAP_DFS ) & &
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 ,
* pp_username ,
* pp_password ,
* pp_workgroup ) ) {
cli_shutdown ( c ) ;
srv = SMBC_server_internal ( ctx , context , connect_if_not_found ,
newserver , newshare , pp_workgroup ,
pp_username , pp_password , in_cache ) ;
TALLOC_FREE ( newserver ) ;
TALLOC_FREE ( newshare ) ;
return srv ;
}
/* must be a normal share */
2009-01-26 10:37:13 +03:00
status = cli_tcon_andx ( c , share , " ????? " , * pp_password ,
strlen ( * pp_password ) + 1 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
errno = map_errno_from_nt_status ( status ) ;
2008-02-28 19:23:20 +03:00
cli_shutdown ( c ) ;
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
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 " ) ) ;
2009-11-21 15:46:52 +03:00
} else if ( ! NT_STATUS_IS_OK ( cli_get_fs_attr_info ( c , & fs_attrs ) ) ) {
2009-01-17 21:33:25 +03:00
DEBUG ( 4 , ( " Could not retrieve case sensitivity flag: %s. \n " ,
cli_errstr ( c ) ) ) ;
/*
* 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 ) ;
}
} else {
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-29 21:34:35 +03:00
if ( context - > internal - > smb_encryption_level ) {
2008-02-28 19:23:20 +03:00
/* Attempt UNIX smb encryption. */
if ( ! NT_STATUS_IS_OK ( cli_force_encryption ( c ,
2008-03-02 04:44:21 +03:00
username_used ,
* pp_password ,
* pp_workgroup ) ) ) {
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 ) ;
srv - > cli = c ;
srv - > dev = ( dev_t ) ( str_checksum ( server ) ^ str_checksum ( share ) ) ;
srv - > no_pathinfo = False ;
srv - > no_pathinfo2 = False ;
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 ,
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 ,
server , share , pp_workgroup ,
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 ,
const char * share ,
char * * pp_workgroup ,
char * * pp_username ,
char * * pp_password )
{
int flags ;
struct sockaddr_storage ss ;
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 .
*/
srv = SMBC_server ( ctx , context , true , server , share ,
pp_workgroup , pp_username , pp_password ) ;
if ( ! srv ) {
return NULL ;
}
server = srv - > cli - > desthost ;
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 ) {
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 ;
}
2008-09-11 20:45:26 +04:00
2008-12-03 10:29:57 +03:00
zero_sockaddr ( & ss ) ;
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 ,
2008-02-28 19:23:20 +03:00
& ss , 0 , " IPC$ " , " ????? " ,
* pp_username ,
* pp_workgroup ,
* pp_password ,
flags ,
2010-12-20 18:37:23 +03:00
Undefined ) ;
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 ) {
2008-02-28 19:23:20 +03:00
/* Attempt UNIX smb encryption. */
if ( ! NT_STATUS_IS_OK ( cli_force_encryption ( ipc_cli ,
2008-03-02 04:44:21 +03:00
* pp_username ,
* pp_password ,
* pp_workgroup ) ) ) {
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 ) ;
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 (
ipc_srv - > cli , & ndr_table_lsarpc . syntax_id , & pipe_hnd ) ;
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 ) ;
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 ;
}