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
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 .
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 .
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"
# include "libsmbclient.h"
# include "libsmb_internal.h"
/*
* 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-03-02 04:44:21 +03: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-03-02 04:44:21 +03: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-03-02 04:44:21 +03: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-03-02 04:44:21 +03:00
2008-02-29 21:34:35 +03:00
DLIST_REMOVE ( context - > internal - > servers , srv ) ;
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
cli_shutdown ( srv - > cli ) ;
srv - > cli = NULL ;
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
DEBUG ( 3 , ( " smbc_remove_usused_server: %p removed. \n " , srv ) ) ;
2008-03-02 04:44:21 +03:00
2008-03-04 02:13:33 +03:00
smbc_getFunctionRemoveCachedServer ( context ) ( context , srv ) ;
2008-03-02 04:44:21 +03: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-02 04:44:21 +03: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-03-02 04:44:21 +03:00
2008-03-04 02:13:33 +03:00
smbc_getFunctionAuthData ( context ) ( server , share ,
workgroup , sizeof ( workgroup ) ,
username , sizeof ( username ) ,
password , sizeof ( password ) ) ;
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( * pp_workgroup ) ;
TALLOC_FREE ( * pp_username ) ;
TALLOC_FREE ( * pp_password ) ;
2008-03-02 04:44:21 +03: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-03-02 04:44:21 +03:00
check_server_cache :
2008-03-04 02:13:33 +03:00
srv = smbc_getFunctionGetCachedServer ( context ) ( context ,
server , share ,
* pp_workgroup ,
* pp_username ) ;
2008-03-02 04:44:21 +03: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-02-28 19:23:20 +03:00
if ( ! pp_workgroup | | ! pp_username | | ! pp_password ) {
return NULL ;
}
2008-03-02 04:44:21 +03: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-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-02 04:44:21 +03: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-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
/*
* Maybe there are more cached connections to this
* server
*/
goto check_server_cache ;
}
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
return srv ;
}
2008-03-02 04:44:21 +03: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 .
*/
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 ;
struct cli_state * c ;
struct nmb_name called , calling ;
const char * server_n = server ;
struct sockaddr_storage ss ;
int tried_reverse = 0 ;
int port_try_first ;
int port_try_next ;
const char * username_used ;
NTSTATUS status ;
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
zero_addr ( & ss ) ;
ZERO_STRUCT ( c ) ;
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
if ( server [ 0 ] = = 0 ) {
errno = EPERM ;
return NULL ;
}
2008-03-02 04:44:21 +03: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-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-03-02 04:44:21 +03: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 .
*/
if ( srv - > cli - > cnum = = ( uint16 ) - 1 ) {
/* Ensure we have accurate auth info */
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 ;
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-03-02 04:44:21 +03: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-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
if ( ! cli_send_tconX ( srv - > cli , share , " ????? " ,
2008-03-02 04:44:21 +03:00
* pp_password ,
strlen ( * pp_password ) + 1 ) ) {
2008-02-28 19:23:20 +03:00
errno = SMBC_errno ( context , srv - > cli ) ;
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-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
/*
* Regenerate the dev value since it ' s based on both
* server and share
*/
if ( srv ) {
srv - > dev = ( dev_t ) ( str_checksum ( server ) ^
str_checksum ( share ) ) ;
}
}
}
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
/* If we have a connection... */
if ( srv ) {
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
/* ... then we're done here. Give 'em what they came for. */
return srv ;
}
2008-03-02 04:44:21 +03: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-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
if ( ! * pp_workgroup | | ! * pp_username | | ! * pp_password ) {
errno = ENOMEM ;
return NULL ;
}
2008-03-02 04:44:21 +03:00
2008-03-04 02:13:33 +03:00
make_nmb_name ( & calling , smbc_getNetbiosName ( context ) , 0x0 ) ;
2008-02-28 19:23:20 +03:00
make_nmb_name ( & called , server , 0x20 ) ;
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
DEBUG ( 4 , ( " SMBC_server: server_n=[%s] server=[%s] \n " , server_n , server ) ) ;
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
DEBUG ( 4 , ( " -> server_n=[%s] server=[%s] \n " , server_n , server ) ) ;
2008-03-02 04:44:21 +03:00
again :
2008-02-28 19:23:20 +03:00
zero_addr ( & ss ) ;
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
/* have to open a new connection */
if ( ( c = cli_initialise ( ) ) = = NULL ) {
errno = ENOMEM ;
return NULL ;
}
2008-03-02 04:44:21 +03: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-03-02 04:44:21 +03:00
2008-03-04 02:13:33 +03:00
c - > timeout = smbc_getTimeout ( context ) ;
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
/*
* Force use of port 139 for first try if share is $ IPC , empty , or
* null , so browse lists can work
*/
if ( share = = NULL | | * share = = ' \0 ' | | strcmp ( share , " IPC$ " ) = = 0 ) {
port_try_first = 139 ;
port_try_next = 445 ;
} else {
port_try_first = 445 ;
port_try_next = 139 ;
}
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
c - > port = port_try_first ;
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
status = cli_connect ( c , server_n , & ss ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
/* First connection attempt failed. Try alternate port. */
c - > port = port_try_next ;
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
status = cli_connect ( c , server_n , & ss ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
cli_shutdown ( c ) ;
errno = ETIMEDOUT ;
return NULL ;
}
}
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
if ( ! cli_session_request ( c , & calling , & called ) ) {
cli_shutdown ( c ) ;
if ( strcmp ( called . name , " *SMBSERVER " ) ) {
make_nmb_name ( & called , " *SMBSERVER " , 0x20 ) ;
goto again ;
} else { /* Try one more time, but ensure we don't loop */
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
/* Only try this if server is an IP address ... */
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
if ( is_ipaddress ( server ) & & ! tried_reverse ) {
fstring remote_name ;
struct sockaddr_storage rem_ss ;
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
if ( ! interpret_string_addr ( & rem_ss , server ,
2008-03-02 04:44:21 +03:00
NI_NUMERICHOST ) ) {
2008-02-28 19:23:20 +03:00
DEBUG ( 4 , ( " Could not convert IP address "
2008-03-02 04:44:21 +03:00
" %s to struct sockaddr_storage \n " ,
server ) ) ;
2008-02-28 19:23:20 +03:00
errno = ETIMEDOUT ;
return NULL ;
}
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
tried_reverse + + ; /* Yuck */
2008-03-02 04:44:21 +03:00
if ( name_status_find ( " * " , 0 , 0 ,
& rem_ss , remote_name ) ) {
make_nmb_name ( & called ,
remote_name ,
0x20 ) ;
2008-02-28 19:23:20 +03:00
goto again ;
}
}
}
errno = ETIMEDOUT ;
return NULL ;
}
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
DEBUG ( 4 , ( " session request ok \n " ) ) ;
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
if ( ! cli_negprot ( c ) ) {
cli_shutdown ( c ) ;
errno = ETIMEDOUT ;
return NULL ;
}
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
username_used = * pp_username ;
2008-03-02 04:44:21 +03: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-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
/* Failed. Try an anonymous login, if allowed by flags. */
username_used = " " ;
2008-03-02 04:44:21 +03: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-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
cli_shutdown ( c ) ;
errno = EPERM ;
return NULL ;
}
}
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
DEBUG ( 4 , ( " session setup ok \n " ) ) ;
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
if ( ! cli_send_tconX ( c , share , " ????? " ,
* pp_password , strlen ( * pp_password ) + 1 ) ) {
errno = SMBC_errno ( context , c ) ;
cli_shutdown ( c ) ;
return NULL ;
}
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
DEBUG ( 4 , ( " tconx ok \n " ) ) ;
2008-03-02 04:44:21 +03: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 ( c ,
2008-03-02 04:44:21 +03:00
username_used ,
* pp_password ,
* pp_workgroup ) ) ) {
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-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
DEBUG ( 4 , ( " SMB encrypt failed \n " ) ) ;
2008-03-02 04:44:21 +03: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-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
/*
* Ok , we have got a nice connection
* Let ' s allocate a server structure .
*/
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
srv = SMB_MALLOC_P ( SMBCSRV ) ;
if ( ! srv ) {
errno = ENOMEM ;
goto failed ;
}
2008-03-02 04:44:21 +03: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-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
/* now add it to the cache (internal or external) */
/* Let the cache function set errno if it wants to */
errno = 0 ;
2008-03-04 02:13:33 +03:00
if ( smbc_getFunctionAddCachedServer ( context ) ( context , srv ,
server , share ,
* pp_workgroup ,
* pp_username ) ) {
2008-02-28 19:23:20 +03:00
int saved_errno = errno ;
DEBUG ( 3 , ( " Failed to add server to cache \n " ) ) ;
errno = saved_errno ;
if ( errno = = 0 ) {
errno = ENOMEM ;
}
goto failed ;
}
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
DEBUG ( 2 , ( " Server connect ok: //%s/%s: %p \n " ,
server , share , srv ) ) ;
2008-03-02 04:44:21 +03:00
2008-02-29 21:34:35 +03:00
DLIST_ADD ( context - > internal - > servers , srv ) ;
2008-02-28 19:23:20 +03:00
return srv ;
2008-03-02 04:44:21 +03:00
failed :
2008-02-28 19:23:20 +03:00
cli_shutdown ( c ) ;
if ( ! srv ) {
return NULL ;
}
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
SAFE_FREE ( srv ) ;
return NULL ;
}
/*
* 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 ;
struct cli_state * ipc_cli ;
struct rpc_pipe_client * pipe_hnd ;
NTSTATUS nt_status ;
SMBCSRV * ipc_srv = NULL ;
2008-03-02 04:44:21 +03:00
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-03-02 04:44:21 +03: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-03-02 04:44:21 +03: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 ;
}
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
zero_addr ( & ss ) ;
nt_status = cli_full_connection ( & ipc_cli ,
global_myname ( ) , server ,
& ss , 0 , " IPC$ " , " ????? " ,
* pp_username ,
* pp_workgroup ,
* pp_password ,
flags ,
Undefined , NULL ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
DEBUG ( 1 , ( " cli_full_connection failed! (%s) \n " ,
nt_errstr ( nt_status ) ) ) ;
errno = ENOTSUP ;
return NULL ;
}
2008-03-02 04:44:21 +03: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-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-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
DEBUG ( 4 , ( " SMB encrypt failed on IPC$ \n " ) ) ;
2008-03-02 04:44:21 +03: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-03-02 04:44:21 +03: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-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
ZERO_STRUCTP ( ipc_srv ) ;
ipc_srv - > cli = ipc_cli ;
2008-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
pipe_hnd = cli_rpc_pipe_open_noauth ( ipc_srv - > cli ,
PI_LSARPC ,
& nt_status ) ;
if ( ! pipe_hnd ) {
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-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
/*
* Some systems don ' t support
* SEC_RIGHTS_MAXIMUM_ALLOWED , but NT sends 0x2000000
* so we might as well do it too .
*/
2008-03-02 04:44:21 +03: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-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-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
/* now add it to the cache (internal or external) */
2008-03-02 04:44:21 +03: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-03-02 04:44:21 +03: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-03-02 04:44:21 +03:00
2008-02-28 19:23:20 +03:00
return ipc_srv ;
}