summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
authorDavid Disseldorp <ddiss@samba.org>2015-01-16 16:21:22 +0100
committerKarolin Seeger <kseeger@samba.org>2015-01-29 21:15:10 +0100
commit2856b641f321ecfd430fef24cd1158c0e2a1dd01 (patch)
treeab940e4a6b3933a667f89d478a3d228be718f0f6 /source3
parentf9693a1766b88ce068bb04c88f1a41ce3330e2cc (diff)
downloadsamba-2856b641f321ecfd430fef24cd1158c0e2a1dd01.tar.gz
libsmb: reuse connections derived from DFS referrals
[MS-DFSC] 3.2.1.1 and 3.2.1.2 states that DFS targets with the same site location or relative cost are placed in random order in a DFS referral response. libsmbclient currently resolves DFS referrals on every API call, always using the first entry in the referral response. With random ordering, libsmbclient may open a new server connection, rather than reuse an existing (cached) connection established in a previous DFS referred API call. This change sees libsmbclient check the connection cache for any of the DFS referral response entries before creating a new connection. This change is based on a patch by Har Gagan Sahai <SHarGagan@novell.com>. Bug: https://bugzilla.samba.org/show_bug.cgi?id=10123 Signed-off-by: David Disseldorp <ddiss@samba.org> Reviewed-by: Jeremy Allison <jra@samba.org> (cherry picked from commit 7b7d4f740fe5017107d3100041cc8c7982f0eac7) [ddiss@samba.org: 4.0 rebase without smbXcli_tcon context]
Diffstat (limited to 'source3')
-rw-r--r--source3/libsmb/clidfs.c103
1 files changed, 79 insertions, 24 deletions
diff --git a/source3/libsmb/clidfs.c b/source3/libsmb/clidfs.c
index b2e2e9ec2b0..93c964a4d02 100644
--- a/source3/libsmb/clidfs.c
+++ b/source3/libsmb/clidfs.c
@@ -776,6 +776,11 @@ NTSTATUS cli_dfs_get_referral(TALLOC_CTX *ctx,
/********************************************************************
********************************************************************/
+struct cli_dfs_path_split {
+ char *server;
+ char *share;
+ char *extrapath;
+};
NTSTATUS cli_resolve_path(TALLOC_CTX *ctx,
const char *mountpt,
@@ -793,15 +798,16 @@ NTSTATUS cli_resolve_path(TALLOC_CTX *ctx,
char *cleanpath = NULL;
char *extrapath = NULL;
int pathlen;
- char *server = NULL;
- char *share = NULL;
struct cli_state *newcli = NULL;
+ struct cli_state *ccli = NULL;
+ int count = 0;
char *newpath = NULL;
char *newmount = NULL;
char *ppath = NULL;
SMB_STRUCT_STAT sbuf;
uint32 attributes;
NTSTATUS status;
+ struct cli_dfs_path_split *dfs_refs = NULL;
if ( !rootcli || !path || !targetcli ) {
return NT_STATUS_INVALID_PARAMETER;
@@ -885,26 +891,83 @@ NTSTATUS cli_resolve_path(TALLOC_CTX *ctx,
return status;
}
- /* Just store the first referral for now. */
-
if (!refs[0].dfspath) {
return NT_STATUS_NOT_FOUND;
}
- if (!split_dfs_path(ctx, refs[0].dfspath, &server, &share,
- &extrapath)) {
- return NT_STATUS_NOT_FOUND;
+
+ /*
+ * Bug#10123 - DFS referal entries can be provided in a random order,
+ * so check the connection cache for each item to avoid unnecessary
+ * reconnections.
+ */
+ dfs_refs = talloc_array(ctx, struct cli_dfs_path_split, num_refs);
+ if (dfs_refs == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (count = 0; count < num_refs; count++) {
+ if (!split_dfs_path(dfs_refs, refs[count].dfspath,
+ &dfs_refs[count].server,
+ &dfs_refs[count].share,
+ &dfs_refs[count].extrapath)) {
+ TALLOC_FREE(dfs_refs);
+ return NT_STATUS_NOT_FOUND;
+ }
+
+ ccli = cli_cm_find(rootcli, dfs_refs[count].server,
+ dfs_refs[count].share);
+ if (ccli != NULL) {
+ extrapath = dfs_refs[count].extrapath;
+ *targetcli = ccli;
+ break;
+ }
+ }
+
+ /*
+ * If no cached connection was found, then connect to the first live
+ * referral server in the list.
+ */
+ for (count = 0; (ccli == NULL) && (count < num_refs); count++) {
+ /* Connect to the target server & share */
+ status = cli_cm_connect(ctx, rootcli,
+ dfs_refs[count].server,
+ dfs_refs[count].share,
+ dfs_auth_info,
+ false,
+ smb1cli_conn_encryption_on(rootcli->conn),
+ smbXcli_conn_protocol(rootcli->conn),
+ 0,
+ 0x20,
+ targetcli);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("Unable to follow dfs referral [\\%s\\%s]\n",
+ dfs_refs[count].server,
+ dfs_refs[count].share);
+ continue;
+ } else {
+ extrapath = dfs_refs[count].extrapath;
+ break;
+ }
+ }
+
+ /* No available referral server for the connection */
+ if (*targetcli == NULL) {
+ TALLOC_FREE(dfs_refs);
+ return status;
}
/* Make sure to recreate the original string including any wildcards. */
dfs_path = cli_dfs_make_full_path(ctx, rootcli, path);
if (!dfs_path) {
+ TALLOC_FREE(dfs_refs);
return NT_STATUS_NO_MEMORY;
}
pathlen = strlen(dfs_path);
consumed = MIN(pathlen, consumed);
*pp_targetpath = talloc_strdup(ctx, &dfs_path[consumed]);
if (!*pp_targetpath) {
+ TALLOC_FREE(dfs_refs);
return NT_STATUS_NO_MEMORY;
}
dfs_path[consumed] = '\0';
@@ -915,23 +978,6 @@ NTSTATUS cli_resolve_path(TALLOC_CTX *ctx,
* (in \server\share\path format).
*/
- /* Open the connection to the target server & share */
- status = cli_cm_open(ctx, rootcli,
- server,
- share,
- dfs_auth_info,
- false,
- smb1cli_conn_encryption_on(rootcli->conn),
- smbXcli_conn_protocol(rootcli->conn),
- 0,
- 0x20,
- targetcli);
- if (!NT_STATUS_IS_OK(status)) {
- d_printf("Unable to follow dfs referral [\\%s\\%s]\n",
- server, share );
- return status;
- }
-
if (extrapath && strlen(extrapath) > 0) {
/* EMC Celerra NAS version 5.6.50 (at least) doesn't appear to */
/* put the trailing \ on the path, so to be save we put one in if needed */
@@ -947,6 +993,7 @@ NTSTATUS cli_resolve_path(TALLOC_CTX *ctx,
*pp_targetpath);
}
if (!*pp_targetpath) {
+ TALLOC_FREE(dfs_refs);
return NT_STATUS_NO_MEMORY;
}
}
@@ -960,18 +1007,21 @@ NTSTATUS cli_resolve_path(TALLOC_CTX *ctx,
d_printf("cli_resolve_path: "
"dfs_path (%s) not in correct format.\n",
dfs_path );
+ TALLOC_FREE(dfs_refs);
return NT_STATUS_NOT_FOUND;
}
ppath++; /* Now pointing at start of server name. */
if ((ppath = strchr_m( dfs_path, '\\' )) == NULL) {
+ TALLOC_FREE(dfs_refs);
return NT_STATUS_NOT_FOUND;
}
ppath++; /* Now pointing at start of share name. */
if ((ppath = strchr_m( ppath+1, '\\' )) == NULL) {
+ TALLOC_FREE(dfs_refs);
return NT_STATUS_NOT_FOUND;
}
@@ -979,6 +1029,7 @@ NTSTATUS cli_resolve_path(TALLOC_CTX *ctx,
newmount = talloc_asprintf(ctx, "%s\\%s", mountpt, ppath );
if (!newmount) {
+ TALLOC_FREE(dfs_refs);
return NT_STATUS_NOT_FOUND;
}
@@ -1003,6 +1054,7 @@ NTSTATUS cli_resolve_path(TALLOC_CTX *ctx,
*/
*targetcli = newcli;
*pp_targetpath = newpath;
+ TALLOC_FREE(dfs_refs);
return status;
}
}
@@ -1013,14 +1065,17 @@ NTSTATUS cli_resolve_path(TALLOC_CTX *ctx,
if ((*targetcli)->dfsroot) {
dfs_path = talloc_strdup(ctx, *pp_targetpath);
if (!dfs_path) {
+ TALLOC_FREE(dfs_refs);
return NT_STATUS_NO_MEMORY;
}
*pp_targetpath = cli_dfs_make_full_path(ctx, *targetcli, dfs_path);
if (*pp_targetpath == NULL) {
+ TALLOC_FREE(dfs_refs);
return NT_STATUS_NO_MEMORY;
}
}
+ TALLOC_FREE(dfs_refs);
return NT_STATUS_OK;
}