2
Unix SMB/CIFS implementation.
3
client connect/disconnect routines
4
Copyright (C) Andrew Tridgell 1994-1998
5
Copyright (C) Gerald (Jerry) Carter 2004
6
Copyright (C) Jeremy Allison 2007-2009
8
This program is free software; you can redistribute it and/or modify
9
it under the terms of the GNU General Public License as published by
10
the Free Software Foundation; either version 3 of the License, or
11
(at your option) any later version.
13
This program is distributed in the hope that it will be useful,
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
GNU General Public License for more details.
18
You should have received a copy of the GNU General Public License
19
along with this program. If not, see <http://www.gnu.org/licenses/>.
24
/********************************************************************
27
DFS paths are *always* of the form \server\share\<pathname> (the \ characters
28
are not C escaped here).
30
- but if we're using POSIX paths then <pathname> may contain
31
'/' separators, not '\\' separators. So cope with '\\' or '/'
32
as a separator when looking at the pathname part.... JRA.
33
********************************************************************/
35
static bool cli_check_msdfs_proxy(TALLOC_CTX *ctx,
36
struct cli_state *cli,
37
const char *sharename,
45
/********************************************************************
46
Ensure a connection is encrypted.
47
********************************************************************/
49
NTSTATUS cli_cm_force_encryption(struct cli_state *c,
53
const char *sharename)
55
NTSTATUS status = cli_force_encryption(c,
60
if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_SUPPORTED)) {
61
d_printf("Encryption required and "
62
"server that doesn't support "
63
"UNIX extensions - failing connect\n");
64
} else if (NT_STATUS_EQUAL(status,NT_STATUS_UNKNOWN_REVISION)) {
65
d_printf("Encryption required and "
66
"can't get UNIX CIFS extensions "
67
"version from server.\n");
68
} else if (NT_STATUS_EQUAL(status,NT_STATUS_UNSUPPORTED_COMPRESSION)) {
69
d_printf("Encryption required and "
70
"share %s doesn't support "
71
"encryption.\n", sharename);
72
} else if (!NT_STATUS_IS_OK(status)) {
73
d_printf("Encryption required and "
74
"setup failed with error %s.\n",
81
/********************************************************************
82
Return a connection to a server.
83
********************************************************************/
85
static struct cli_state *do_connect(TALLOC_CTX *ctx,
88
const struct user_auth_info *auth_info,
95
struct cli_state *c = NULL;
96
struct nmb_name called, calling;
97
const char *called_str;
99
struct sockaddr_storage ss;
102
char *newserver, *newshare;
103
const char *username;
104
const char *password;
107
/* make a copy so we don't modify the global string 'service' */
108
servicename = talloc_strdup(ctx,share);
112
sharename = servicename;
113
if (*sharename == '\\') {
115
called_str = sharename;
116
if (server == NULL) {
119
sharename = strchr_m(sharename,'\\');
133
make_nmb_name(&calling, global_myname(), 0x0);
134
make_nmb_name(&called , called_str, name_type);
139
/* have to open a new connection */
140
if (!(c=cli_initialise_ex(get_cmdline_auth_info_signing_state(auth_info)))) {
141
d_printf("Connection to %s failed\n", server_n);
148
cli_set_port(c, port);
151
status = cli_connect(c, server_n, &ss);
152
if (!NT_STATUS_IS_OK(status)) {
153
d_printf("Connection to %s failed (Error %s)\n",
160
if (max_protocol == 0) {
161
max_protocol = PROTOCOL_NT1;
163
c->protocol = max_protocol;
164
c->use_kerberos = get_cmdline_auth_info_use_kerberos(auth_info);
165
c->fallback_after_kerberos =
166
get_cmdline_auth_info_fallback_after_kerberos(auth_info);
168
if (!cli_session_request(c, &calling, &called)) {
170
d_printf("session request to %s failed (%s)\n",
171
called.name, cli_errstr(c));
174
if ((p=strchr_m(called.name, '.'))) {
178
if (strcmp(called.name, "*SMBSERVER")) {
179
make_nmb_name(&called , "*SMBSERVER", 0x20);
185
DEBUG(4,(" session request ok\n"));
187
status = cli_negprot(c);
189
if (!NT_STATUS_IS_OK(status)) {
190
d_printf("protocol negotiation failed: %s\n",
196
username = get_cmdline_auth_info_username(auth_info);
197
password = get_cmdline_auth_info_password(auth_info);
199
if (!NT_STATUS_IS_OK(cli_session_setup(c, username,
200
password, strlen(password),
201
password, strlen(password),
203
/* If a password was not supplied then
204
* try again with a null username. */
205
if (password[0] || !username[0] ||
206
get_cmdline_auth_info_use_kerberos(auth_info) ||
207
!NT_STATUS_IS_OK(cli_session_setup(c, "",
211
d_printf("session setup failed: %s\n", cli_errstr(c));
212
if (NT_STATUS_V(cli_nt_error(c)) ==
213
NT_STATUS_V(NT_STATUS_MORE_PROCESSING_REQUIRED))
214
d_printf("did you forget to run kinit?\n");
218
d_printf("Anonymous login successful\n");
219
status = cli_init_creds(c, "", lp_workgroup(), "");
221
status = cli_init_creds(c, username, lp_workgroup(), password);
224
if (!NT_STATUS_IS_OK(status)) {
225
DEBUG(10,("cli_init_creds() failed: %s\n", nt_errstr(status)));
230
if ( show_sessetup ) {
231
if (*c->server_domain) {
232
DEBUG(0,("Domain=[%s] OS=[%s] Server=[%s]\n",
233
c->server_domain,c->server_os,c->server_type));
234
} else if (*c->server_os || *c->server_type) {
235
DEBUG(0,("OS=[%s] Server=[%s]\n",
236
c->server_os,c->server_type));
239
DEBUG(4,(" session setup ok\n"));
241
/* here's the fun part....to support 'msdfs proxy' shares
242
(on Samba or windows) we have to issues a TRANS_GET_DFS_REFERRAL
243
here before trying to connect to the original share.
244
check_dfs_proxy() will fail if it is a normal share. */
246
if ((c->capabilities & CAP_DFS) &&
247
cli_check_msdfs_proxy(ctx, c, sharename,
248
&newserver, &newshare,
254
return do_connect(ctx, newserver,
255
newshare, auth_info, false,
256
force_encrypt, max_protocol,
260
/* must be a normal share */
262
status = cli_tcon_andx(c, sharename, "?????",
263
password, strlen(password)+1);
264
if (!NT_STATUS_IS_OK(status)) {
265
d_printf("tree connect failed: %s\n", nt_errstr(status));
271
status = cli_cm_force_encryption(c,
276
if (!NT_STATUS_IS_OK(status)) {
282
DEBUG(4,(" tconx ok\n"));
286
/****************************************************************************
287
****************************************************************************/
289
static void cli_set_mntpoint(struct cli_state *cli, const char *mnt)
291
char *name = clean_name(NULL, mnt);
295
TALLOC_FREE(cli->dfs_mountpoint);
296
cli->dfs_mountpoint = talloc_strdup(cli, name);
300
/********************************************************************
301
Add a new connection to the list.
302
referring_cli == NULL means a new initial connection.
303
********************************************************************/
305
static struct cli_state *cli_cm_connect(TALLOC_CTX *ctx,
306
struct cli_state *referring_cli,
309
const struct user_auth_info *auth_info,
316
struct cli_state *cli;
318
cli = do_connect(ctx, server, share,
320
show_hdr, force_encrypt, max_protocol,
327
/* Enter into the list. */
329
DLIST_ADD_END(referring_cli, cli, struct cli_state *);
332
if (referring_cli && referring_cli->posix_capabilities) {
334
uint32 caplow, caphigh;
335
if (cli_unix_extensions_version(cli, &major,
336
&minor, &caplow, &caphigh)) {
337
cli_set_unix_extensions_capabilities(cli,
346
/********************************************************************
347
Return a connection to a server on a particular share.
348
********************************************************************/
350
static struct cli_state *cli_cm_find(struct cli_state *cli,
360
/* Search to the start of the list. */
361
for (p = cli; p; p = p->prev) {
362
if (strequal(server, p->desthost) &&
363
strequal(share,p->share)) {
368
/* Search to the end of the list. */
369
for (p = cli->next; p; p = p->next) {
370
if (strequal(server, p->desthost) &&
371
strequal(share,p->share)) {
379
/****************************************************************************
380
Open a client connection to a \\server\share.
381
****************************************************************************/
383
struct cli_state *cli_cm_open(TALLOC_CTX *ctx,
384
struct cli_state *referring_cli,
387
const struct user_auth_info *auth_info,
394
/* Try to reuse an existing connection in this list. */
395
struct cli_state *c = cli_cm_find(referring_cli, server, share);
401
if (auth_info == NULL) {
402
/* Can't do a new connection
403
* without auth info. */
404
d_printf("cli_cm_open() Unable to open connection [\\%s\\%s] "
405
"without auth info\n",
410
return cli_cm_connect(ctx,
422
/****************************************************************************
423
****************************************************************************/
425
void cli_cm_display(const struct cli_state *cli)
429
for (i=0; cli; cli = cli->next,i++ ) {
430
d_printf("%d:\tserver=%s, share=%s\n",
431
i, cli->desthost, cli->share );
435
/****************************************************************************
436
****************************************************************************/
438
/****************************************************************************
439
****************************************************************************/
442
void cli_cm_set_credentials(struct user_auth_info *auth_info)
444
SAFE_FREE(cm_creds.username);
445
cm_creds.username = SMB_STRDUP(get_cmdline_auth_info_username(
448
if (get_cmdline_auth_info_got_pass(auth_info)) {
449
cm_set_password(get_cmdline_auth_info_password(auth_info));
452
cm_creds.use_kerberos = get_cmdline_auth_info_use_kerberos(auth_info);
453
cm_creds.fallback_after_kerberos = false;
454
cm_creds.signing_state = get_cmdline_auth_info_signing_state(auth_info);
458
/**********************************************************************
459
split a dfs path into the server, share name, and extrapath components
460
**********************************************************************/
462
static void split_dfs_path(TALLOC_CTX *ctx,
463
const char *nodepath,
473
*pp_extrapath = NULL;
475
path = talloc_strdup(ctx, nodepath);
480
if ( path[0] != '\\' ) {
484
p = strchr_m( path + 1, '\\' );
492
/* Look for any extra/deep path */
493
q = strchr_m(p, '\\');
497
*pp_extrapath = talloc_strdup(ctx, q);
499
*pp_extrapath = talloc_strdup(ctx, "");
502
*pp_share = talloc_strdup(ctx, p);
503
*pp_server = talloc_strdup(ctx, &path[1]);
506
/****************************************************************************
507
Return the original path truncated at the directory component before
508
the first wildcard character. Trust the caller to provide a NULL
510
****************************************************************************/
512
static char *clean_path(TALLOC_CTX *ctx, const char *path)
518
/* No absolute paths. */
519
while (IS_DIRECTORY_SEP(*path)) {
523
path_out = talloc_strdup(ctx, path);
528
p1 = strchr_m(path_out, '*');
529
p2 = strchr_m(path_out, '?');
541
/* Now go back to the start of this component. */
542
p1 = strrchr_m(path_out, '/');
543
p2 = strrchr_m(path_out, '\\');
550
/* Strip any trailing separator */
552
len = strlen(path_out);
553
if ( (len > 0) && IS_DIRECTORY_SEP(path_out[len-1])) {
554
path_out[len-1] = '\0';
560
/****************************************************************************
561
****************************************************************************/
563
static char *cli_dfs_make_full_path(TALLOC_CTX *ctx,
564
struct cli_state *cli,
567
char path_sep = '\\';
569
/* Ensure the extrapath doesn't start with a separator. */
570
while (IS_DIRECTORY_SEP(*dir)) {
574
if (cli->posix_capabilities & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
577
return talloc_asprintf(ctx, "%c%s%c%s%c%s",
586
/********************************************************************
587
check for dfs referral
588
********************************************************************/
590
static bool cli_dfs_check_error( struct cli_state *cli, NTSTATUS status )
592
uint32 flgs2 = SVAL(cli->inbuf,smb_flg2);
594
/* only deal with DS when we negotiated NT_STATUS codes and UNICODE */
596
if (!((flgs2&FLAGS2_32_BIT_ERROR_CODES) &&
597
(flgs2&FLAGS2_UNICODE_STRINGS)))
600
if (NT_STATUS_EQUAL(status, NT_STATUS(IVAL(cli->inbuf,smb_rcls))))
606
/********************************************************************
607
Get the dfs referral link.
608
********************************************************************/
610
bool cli_dfs_get_referral(TALLOC_CTX *ctx,
611
struct cli_state *cli,
613
CLIENT_DFS_REFERRAL**refs,
617
unsigned int data_len = 0;
618
unsigned int param_len = 0;
619
uint16 setup = TRANSACT2_GET_DFS_REFERRAL;
621
char *rparam=NULL, *rdata=NULL;
624
size_t pathlen = 2*(strlen(path)+1);
625
smb_ucs2_t *path_ucs;
626
char *consumed_path = NULL;
627
uint16_t consumed_ucs;
628
uint16 num_referrals;
629
CLIENT_DFS_REFERRAL *referrals = NULL;
635
param = SMB_MALLOC_ARRAY(char, 2+pathlen+2);
639
SSVAL(param, 0, 0x03); /* max referral level */
642
path_ucs = (smb_ucs2_t *)p;
643
p += clistr_push(cli, p, path, pathlen, STR_TERMINATE);
644
param_len = PTR_DIFF(p, param);
646
if (!cli_send_trans(cli, SMBtrans2,
648
-1, 0, /* fid, flags */
649
&setup, 1, 0, /* setup, length, max */
650
param, param_len, 2, /* param, length, max */
651
NULL, 0, cli->max_xmit /* data, length, max */
656
if (!cli_receive_trans(cli, SMBtrans2,
658
&rdata, &data_len)) {
666
endp = rdata + data_len;
668
consumed_ucs = SVAL(rdata, 0);
669
num_referrals = SVAL(rdata, 2);
671
/* consumed_ucs is the number of bytes
672
* of the UCS2 path consumed not counting any
673
* terminating null. We need to convert
674
* back to unix charset and count again
675
* to get the number of bytes consumed from
676
* the incoming path. */
678
if (pull_string_talloc(talloc_tos(),
687
if (consumed_path == NULL) {
690
*consumed = strlen(consumed_path);
692
if (num_referrals != 0) {
698
referrals = TALLOC_ARRAY(ctx, CLIENT_DFS_REFERRAL,
704
/* start at the referrals array */
707
for (i=0; i<num_referrals && p < endp; i++) {
711
ref_version = SVAL(p, 0);
712
ref_size = SVAL(p, 2);
713
node_offset = SVAL(p, 16);
715
if (ref_version != 3) {
720
referrals[i].proximity = SVAL(p, 8);
721
referrals[i].ttl = SVAL(p, 10);
723
if (p + node_offset > endp) {
726
clistr_pull_talloc(ctx, cli->inbuf,
727
&referrals[i].dfspath,
729
STR_TERMINATE|STR_UNICODE);
731
if (!referrals[i].dfspath) {
736
if (i < num_referrals) {
743
*num_refs = num_referrals;
748
TALLOC_FREE(consumed_path);
755
/********************************************************************
756
********************************************************************/
758
bool cli_resolve_path(TALLOC_CTX *ctx,
760
const struct user_auth_info *dfs_auth_info,
761
struct cli_state *rootcli,
763
struct cli_state **targetcli,
764
char **pp_targetpath)
766
CLIENT_DFS_REFERRAL *refs = NULL;
769
struct cli_state *cli_ipc = NULL;
770
char *dfs_path = NULL;
771
char *cleanpath = NULL;
772
char *extrapath = NULL;
776
struct cli_state *newcli = NULL;
777
char *newpath = NULL;
778
char *newmount = NULL;
780
SMB_STRUCT_STAT sbuf;
783
if ( !rootcli || !path || !targetcli ) {
787
/* Don't do anything if this is not a DFS root. */
789
if ( !rootcli->dfsroot) {
790
*targetcli = rootcli;
791
*pp_targetpath = talloc_strdup(ctx, path);
792
if (!*pp_targetpath) {
800
/* Send a trans2_query_path_info to check for a referral. */
802
cleanpath = clean_path(ctx, path);
807
dfs_path = cli_dfs_make_full_path(ctx, rootcli, cleanpath);
812
if (cli_qpathinfo_basic( rootcli, dfs_path, &sbuf, &attributes)) {
813
/* This is an ordinary path, just return it. */
814
*targetcli = rootcli;
815
*pp_targetpath = talloc_strdup(ctx, path);
816
if (!*pp_targetpath) {
822
/* Special case where client asked for a path that does not exist */
824
if (cli_dfs_check_error(rootcli, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
825
*targetcli = rootcli;
826
*pp_targetpath = talloc_strdup(ctx, path);
827
if (!*pp_targetpath) {
833
/* We got an error, check for DFS referral. */
835
if (!cli_dfs_check_error(rootcli, NT_STATUS_PATH_NOT_COVERED)) {
839
/* Check for the referral. */
841
if (!(cli_ipc = cli_cm_open(ctx,
847
(rootcli->trans_enc_state != NULL),
854
if (!cli_dfs_get_referral(ctx, cli_ipc, dfs_path, &refs,
855
&num_refs, &consumed) || !num_refs) {
859
/* Just store the first referral for now. */
861
if (!refs[0].dfspath) {
864
split_dfs_path(ctx, refs[0].dfspath, &server, &share, &extrapath );
866
if (!server || !share) {
870
/* Make sure to recreate the original string including any wildcards. */
872
dfs_path = cli_dfs_make_full_path(ctx, rootcli, path);
876
pathlen = strlen(dfs_path);
877
consumed = MIN(pathlen, consumed);
878
*pp_targetpath = talloc_strdup(ctx, &dfs_path[consumed]);
879
if (!*pp_targetpath) {
882
dfs_path[consumed] = '\0';
885
* *pp_targetpath is now the unconsumed part of the path.
886
* dfs_path is now the consumed part of the path
887
* (in \server\share\path format).
890
/* Open the connection to the target server & share */
891
if ((*targetcli = cli_cm_open(ctx, rootcli,
896
(rootcli->trans_enc_state != NULL),
900
d_printf("Unable to follow dfs referral [\\%s\\%s]\n",
905
if (extrapath && strlen(extrapath) > 0) {
906
*pp_targetpath = talloc_asprintf(ctx,
910
if (!*pp_targetpath) {
915
/* parse out the consumed mount path */
916
/* trim off the \server\share\ */
920
if (*ppath != '\\') {
921
d_printf("cli_resolve_path: "
922
"dfs_path (%s) not in correct format.\n",
927
ppath++; /* Now pointing at start of server name. */
929
if ((ppath = strchr_m( dfs_path, '\\' )) == NULL) {
933
ppath++; /* Now pointing at start of share name. */
935
if ((ppath = strchr_m( ppath+1, '\\' )) == NULL) {
939
ppath++; /* Now pointing at path component. */
941
newmount = talloc_asprintf(ctx, "%s\\%s", mountpt, ppath );
946
cli_set_mntpoint(*targetcli, newmount);
948
/* Check for another dfs referral, note that we are not
949
checking for loops here. */
951
if (!strequal(*pp_targetpath, "\\") && !strequal(*pp_targetpath, "/")) {
952
if (cli_resolve_path(ctx,
960
* When cli_resolve_path returns true here it's always
961
* returning the complete path in newpath, so we're done
965
*pp_targetpath = newpath;
972
/* If returning true ensure we return a dfs root full path. */
973
if ((*targetcli)->dfsroot) {
974
dfs_path = talloc_strdup(ctx, *pp_targetpath);
978
*pp_targetpath = cli_dfs_make_full_path(ctx, *targetcli, dfs_path);
984
/********************************************************************
985
********************************************************************/
987
static bool cli_check_msdfs_proxy(TALLOC_CTX *ctx,
988
struct cli_state *cli,
989
const char *sharename,
993
const char *username,
994
const char *password,
997
CLIENT_DFS_REFERRAL *refs = NULL;
1000
char *fullpath = NULL;
1003
char *newextrapath = NULL;
1005
if (!cli || !sharename) {
1011
/* special case. never check for a referral on the IPC$ share */
1013
if (strequal(sharename, "IPC$")) {
1017
/* send a trans2_query_path_info to check for a referral */
1019
fullpath = talloc_asprintf(ctx, "\\%s\\%s", cli->desthost, sharename );
1024
/* check for the referral */
1026
if (!NT_STATUS_IS_OK(cli_tcon_andx(cli, "IPC$", "IPC", NULL, 0))) {
1030
if (force_encrypt) {
1031
NTSTATUS status = cli_cm_force_encryption(cli,
1036
if (!NT_STATUS_IS_OK(status)) {
1041
res = cli_dfs_get_referral(ctx, cli, fullpath, &refs, &num_refs, &consumed);
1043
if (!cli_tdis(cli)) {
1049
if (!res || !num_refs) {
1053
if (!refs[0].dfspath) {
1057
split_dfs_path(ctx, refs[0].dfspath, pp_newserver,
1058
pp_newshare, &newextrapath );
1060
if ((*pp_newserver == NULL) || (*pp_newshare == NULL)) {
1064
/* check that this is not a self-referral */
1066
if (strequal(cli->desthost, *pp_newserver) &&
1067
strequal(sharename, *pp_newshare)) {