2
Unix SMB/CIFS implementation.
3
client connect/disconnect routines
4
Copyright (C) Andrew Tridgell 1994-1998
5
Copyright (C) Gerald (Jerry) Carter 2004
7
This program is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2 of the License, or
10
(at your option) any later version.
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with this program; if not, write to the Free Software
19
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27
struct client_connection {
28
struct client_connection *prev, *next;
29
struct cli_state *cli;
33
/* global state....globals reek! */
35
static pstring username;
36
static pstring password;
37
static BOOL use_kerberos;
39
static int signing_state;
40
int max_protocol = PROTOCOL_NT1;
43
static int name_type = 0x20;
45
static struct in_addr dest_ip;
47
static struct client_connection *connections;
49
/********************************************************************
50
Return a connection to a server.
51
********************************************************************/
53
static struct cli_state *do_connect( const char *server, const char *share,
57
struct nmb_name called, calling;
63
/* make a copy so we don't modify the global string 'service' */
64
pstrcpy(servicename, share);
65
sharename = servicename;
66
if (*sharename == '\\') {
68
sharename = strchr_m(server,'\\');
69
if (!sharename) return NULL;
78
make_nmb_name(&calling, global_myname(), 0x0);
79
make_nmb_name(&called , server, name_type);
86
/* have to open a new connection */
87
if (!(c=cli_initialise(NULL)) || (cli_set_port(c, port) != port) ||
88
!cli_connect(c, server_n, &ip)) {
89
d_printf("Connection to %s failed\n", server_n);
93
c->protocol = max_protocol;
94
c->use_kerberos = use_kerberos;
95
cli_setup_signing_state(c, signing_state);
98
if (!cli_session_request(c, &calling, &called)) {
100
d_printf("session request to %s failed (%s)\n",
101
called.name, cli_errstr(c));
103
if ((p=strchr_m(called.name, '.'))) {
107
if (strcmp(called.name, "*SMBSERVER")) {
108
make_nmb_name(&called , "*SMBSERVER", 0x20);
114
DEBUG(4,(" session request ok\n"));
116
if (!cli_negprot(c)) {
117
d_printf("protocol negotiation failed\n");
123
char *pass = getpass("Password: ");
125
pstrcpy(password, pass);
130
if (!cli_session_setup(c, username,
131
password, strlen(password),
132
password, strlen(password),
134
/* if a password was not supplied then try again with a null username */
135
if (password[0] || !username[0] || use_kerberos ||
136
!cli_session_setup(c, "", "", 0, "", 0, lp_workgroup())) {
137
d_printf("session setup failed: %s\n", cli_errstr(c));
138
if (NT_STATUS_V(cli_nt_error(c)) ==
139
NT_STATUS_V(NT_STATUS_MORE_PROCESSING_REQUIRED))
140
d_printf("did you forget to run kinit?\n");
144
d_printf("Anonymous login successful\n");
147
if ( show_sessetup ) {
148
if (*c->server_domain) {
149
DEBUG(0,("Domain=[%s] OS=[%s] Server=[%s]\n",
150
c->server_domain,c->server_os,c->server_type));
151
} else if (*c->server_os || *c->server_type){
152
DEBUG(0,("OS=[%s] Server=[%s]\n",
153
c->server_os,c->server_type));
156
DEBUG(4,(" session setup ok\n"));
158
if (!cli_send_tconX(c, sharename, "?????",
159
password, strlen(password)+1)) {
160
d_printf("tree connect failed: %s\n", cli_errstr(c));
165
DEBUG(4,(" tconx ok\n"));
170
/****************************************************************************
171
****************************************************************************/
173
static void cli_cm_set_mntpoint( struct cli_state *c, const char *mnt )
175
struct client_connection *p;
178
for ( p=connections,i=0; p; p=p->next,i++ ) {
179
if ( strequal(p->cli->desthost, c->desthost) && strequal(p->cli->share, c->share) )
184
pstrcpy( p->mount, mnt );
185
dos_clean_name( p->mount );
189
/****************************************************************************
190
****************************************************************************/
192
const char * cli_cm_get_mntpoint( struct cli_state *c )
194
struct client_connection *p;
197
for ( p=connections,i=0; p; p=p->next,i++ ) {
198
if ( strequal(p->cli->desthost, c->desthost) && strequal(p->cli->share, c->share) )
208
/********************************************************************
209
Add a new connection to the list
210
********************************************************************/
212
static struct cli_state* cli_cm_connect( const char *server, const char *share,
215
struct client_connection *node;
217
node = SMB_XMALLOC_P( struct client_connection );
219
node->cli = do_connect( server, share, show_hdr );
226
DLIST_ADD( connections, node );
228
cli_cm_set_mntpoint( node->cli, "" );
234
/********************************************************************
235
Return a connection to a server.
236
********************************************************************/
238
static struct cli_state* cli_cm_find( const char *server, const char *share )
240
struct client_connection *p;
242
for ( p=connections; p; p=p->next ) {
243
if ( strequal(server, p->cli->desthost) && strequal(share,p->cli->share) )
250
/****************************************************************************
251
open a client connection to a \\server\share. Set's the current *cli
252
global variable as a side-effect (but only if the connection is successful).
253
****************************************************************************/
255
struct cli_state* cli_cm_open( const char *server, const char *share, BOOL show_hdr )
259
/* try to reuse an existing connection */
261
c = cli_cm_find( server, share );
264
c = cli_cm_connect( server, share, show_hdr );
269
/****************************************************************************
270
****************************************************************************/
272
void cli_cm_shutdown( void )
275
struct client_connection *p, *x;
277
for ( p=connections; p; ) {
278
cli_shutdown( p->cli );
290
/****************************************************************************
291
****************************************************************************/
293
void cli_cm_display(void)
295
struct client_connection *p;
298
for ( p=connections,i=0; p; p=p->next,i++ ) {
299
d_printf("%d:\tserver=%s, share=%s\n",
300
i, p->cli->desthost, p->cli->share );
304
/****************************************************************************
305
****************************************************************************/
307
void cli_cm_set_credentials( struct user_auth_info *user )
309
pstrcpy( username, user->username );
311
if ( user->got_pass ) {
312
pstrcpy( password, user->password );
316
use_kerberos = user->use_kerberos;
317
signing_state = user->signing_state;
320
/****************************************************************************
321
****************************************************************************/
323
void cli_cm_set_port( int port_number )
328
/****************************************************************************
329
****************************************************************************/
331
void cli_cm_set_dest_name_type( int type )
336
/****************************************************************************
337
****************************************************************************/
339
void cli_cm_set_dest_ip(struct in_addr ip )
345
/********************************************************************
346
split a dfs path into the server and share name components
347
********************************************************************/
349
static void split_dfs_path( const char *nodepath, fstring server, fstring share )
354
pstrcpy( path, nodepath );
356
if ( path[0] != '\\' )
359
p = strrchr_m( path, '\\' );
368
fstrcpy( server, &path[1] );
371
/****************************************************************************
372
return the original path truncated at the first wildcard character
373
(also strips trailing \'s). Trust the caller to provide a NULL
375
****************************************************************************/
377
static void clean_path( pstring clean, const char *path )
383
pstrcpy( newpath, path );
387
/* first check for '*' */
389
p = strrchr_m( newpath, '*' );
396
/* first check for '?' */
398
p = strrchr_m( newpath, '?' );
405
/* strip a trailing backslash */
407
len = strlen( newpath );
408
if ( newpath[len-1] == '\\' )
409
newpath[len-1] = '\0';
411
pstrcpy( clean, newpath );
414
/****************************************************************************
415
****************************************************************************/
417
static BOOL make_full_path( pstring path, const char *server, const char *share,
422
const char *directory;
425
/* make a copy so we don't modify the global string 'service' */
427
pstrcpy(servicename, share);
428
sharename = servicename;
430
if (*sharename == '\\') {
432
server = sharename+2;
433
sharename = strchr_m(server,'\\');
443
if ( *directory == '\\' )
446
pstr_sprintf( path, "\\%s\\%s\\%s", server, sharename, directory );
451
/********************************************************************
452
check for dfs referral
453
********************************************************************/
455
static BOOL cli_dfs_check_error( struct cli_state *cli )
457
uint32 flgs2 = SVAL(cli->inbuf,smb_flg2);
459
/* only deal with DS when we negotiated NT_STATUS codes and UNICODE */
461
if ( !( (flgs2&FLAGS2_32_BIT_ERROR_CODES) && (flgs2&FLAGS2_UNICODE_STRINGS) ) )
464
if ( NT_STATUS_EQUAL( NT_STATUS_PATH_NOT_COVERED, NT_STATUS(IVAL(cli->inbuf,smb_rcls)) ) )
470
/********************************************************************
471
get the dfs referral link
472
********************************************************************/
474
BOOL cli_dfs_get_referral( struct cli_state *cli, const char *path,
475
CLIENT_DFS_REFERRAL**refs, size_t *num_refs,
478
unsigned int data_len = 0;
479
unsigned int param_len = 0;
480
uint16 setup = TRANSACT2_GET_DFS_REFERRAL;
481
char param[sizeof(pstring)+2];
483
char *rparam=NULL, *rdata=NULL;
485
size_t pathlen = 2*(strlen(path)+1);
486
uint16 num_referrals;
487
CLIENT_DFS_REFERRAL *referrals = NULL;
489
memset(param, 0, sizeof(param));
490
SSVAL(param, 0, 0x03); /* max referral level */
493
p += clistr_push(cli, p, path, MIN(pathlen, sizeof(param)-2), STR_TERMINATE);
494
param_len = PTR_DIFF(p, param);
496
if (!cli_send_trans(cli, SMBtrans2,
498
-1, 0, /* fid, flags */
499
&setup, 1, 0, /* setup, length, max */
500
param, param_len, 2, /* param, length, max */
501
(char *)&data, data_len, cli->max_xmit /* data, length, max */
506
if (!cli_receive_trans(cli, SMBtrans2,
508
&rdata, &data_len)) {
512
*consumed = SVAL( rdata, 0 );
513
num_referrals = SVAL( rdata, 2 );
515
if ( num_referrals != 0 ) {
522
referrals = SMB_XMALLOC_ARRAY( CLIENT_DFS_REFERRAL, num_referrals );
524
/* start at the referrals array */
527
for ( i=0; i<num_referrals; i++ ) {
528
ref_version = SVAL( p, 0 );
529
ref_size = SVAL( p, 2 );
530
node_offset = SVAL( p, 16 );
532
if ( ref_version != 3 ) {
537
referrals[i].proximity = SVAL( p, 8 );
538
referrals[i].ttl = SVAL( p, 10 );
540
clistr_pull( cli, referrals[i].dfspath, p+node_offset,
541
sizeof(referrals[i].dfspath), -1, STR_TERMINATE|STR_UNICODE );
548
*num_refs = num_referrals;
557
/********************************************************************
558
********************************************************************/
560
BOOL cli_resolve_path( const char *mountpt, struct cli_state *rootcli, const char *path,
561
struct cli_state **targetcli, pstring targetpath )
563
CLIENT_DFS_REFERRAL *refs = NULL;
566
struct cli_state *cli_ipc;
567
pstring fullpath, cleanpath;
569
fstring server, share;
570
struct cli_state *newcli;
575
SMB_STRUCT_STAT sbuf;
580
if ( !rootcli || !path || !targetcli )
583
/* send a trans2_query_path_info to check for a referral */
585
clean_path( cleanpath, path );
586
make_full_path( fullpath, rootcli->desthost, rootcli->share, cleanpath );
588
/* don't bother continuing if this is not a dfs root */
590
if ( !rootcli->dfsroot || cli_qpathinfo_basic( rootcli, cleanpath, &sbuf, &attributes ) ) {
591
*targetcli = rootcli;
592
pstrcpy( targetpath, path );
596
/* we got an error, check for DFS referral */
598
if ( !cli_dfs_check_error(rootcli) )
601
/* check for the referral */
603
if ( !(cli_ipc = cli_cm_open( rootcli->desthost, "IPC$", False )) )
606
if ( !cli_dfs_get_referral(cli_ipc, fullpath, &refs, &num_refs, &consumed)
612
/* just store the first referral for now
613
Make sure to recreate the original string including any wildcards */
615
make_full_path( fullpath, rootcli->desthost, rootcli->share, path );
616
pathlen = strlen( fullpath )*2;
617
consumed = MIN(pathlen, consumed );
618
pstrcpy( targetpath, &fullpath[consumed/2] );
620
split_dfs_path( refs[0].dfspath, server, share );
623
/* open the connection to the target path */
625
if ( (*targetcli = cli_cm_open(server, share, False)) == NULL ) {
626
d_printf("Unable to follow dfs referral [//%s/%s]\n",
632
/* parse out the consumed mount path */
633
/* trim off the \server\share\ */
635
fullpath[consumed/2] = '\0';
636
dos_clean_name( fullpath );
637
ppath = strchr_m( fullpath, '\\' );
638
ppath = strchr_m( ppath+1, '\\' );
639
ppath = strchr_m( ppath+1, '\\' );
642
pstr_sprintf( newmount, "%s\\%s", mountpt, ppath );
643
cli_cm_set_mntpoint( *targetcli, newmount );
645
/* check for another dfs referral, note that we are not
646
checking for loops here */
648
if ( !strequal( targetpath, "\\" ) ) {
649
if ( cli_resolve_path( newmount, *targetcli, targetpath, &newcli, newpath ) ) {
651
pstrcpy( targetpath, newpath );