Skip to content

Commit 9d49640

Browse files
aaptelsmfrench
authored andcommitted
CIFS: implement get_dfs_refer for SMB2+
in SMB2+ the get_dfs_refer operation uses a FSCTL. The request can be made on any Tree Connection according to the specs. Since Samba only accepted it on an IPC connection until recently, try that first. https://lists.samba.org/archive/samba-technical/2017-February/118859.html 3.2.4.20.3 Application Requests DFS Referral Information: > The client MUST search for an existing Session and TreeConnect to any > share on the server identified by ServerName for the user identified by > UserCredentials. If no Session and TreeConnect are found, the client > MUST establish a new Session and TreeConnect to IPC$ on the target > server as described in section 3.2.4.2 using the supplied ServerName and > UserCredentials. Signed-off-by: Aurelien Aptel <aaptel@suse.com> Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com> Signed-off-by: Steve French <smfrench@gmail.com>
1 parent f071292 commit 9d49640

File tree

2 files changed

+109
-0
lines changed

2 files changed

+109
-0
lines changed

fs/cifs/smb2ops.c

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,6 +1104,103 @@ smb2_new_lease_key(struct cifs_fid *fid)
11041104
generate_random_uuid(fid->lease_key);
11051105
}
11061106

1107+
static int
1108+
smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
1109+
const char *search_name,
1110+
struct dfs_info3_param **target_nodes,
1111+
unsigned int *num_of_nodes,
1112+
const struct nls_table *nls_codepage, int remap)
1113+
{
1114+
int rc;
1115+
__le16 *utf16_path = NULL;
1116+
int utf16_path_len = 0;
1117+
struct cifs_tcon *tcon;
1118+
struct fsctl_get_dfs_referral_req *dfs_req = NULL;
1119+
struct get_dfs_referral_rsp *dfs_rsp = NULL;
1120+
u32 dfs_req_size = 0, dfs_rsp_size = 0;
1121+
1122+
cifs_dbg(FYI, "smb2_get_dfs_refer path <%s>\n", search_name);
1123+
1124+
/*
1125+
* Use any tcon from the current session. Here, the first one.
1126+
*/
1127+
spin_lock(&cifs_tcp_ses_lock);
1128+
tcon = list_first_entry_or_null(&ses->tcon_list, struct cifs_tcon,
1129+
tcon_list);
1130+
if (tcon)
1131+
tcon->tc_count++;
1132+
spin_unlock(&cifs_tcp_ses_lock);
1133+
1134+
if (!tcon) {
1135+
cifs_dbg(VFS, "session %p has no tcon available for a dfs referral request\n",
1136+
ses);
1137+
rc = -ENOTCONN;
1138+
goto out;
1139+
}
1140+
1141+
utf16_path = cifs_strndup_to_utf16(search_name, PATH_MAX,
1142+
&utf16_path_len,
1143+
nls_codepage, remap);
1144+
if (!utf16_path) {
1145+
rc = -ENOMEM;
1146+
goto out;
1147+
}
1148+
1149+
dfs_req_size = sizeof(*dfs_req) + utf16_path_len;
1150+
dfs_req = kzalloc(dfs_req_size, GFP_KERNEL);
1151+
if (!dfs_req) {
1152+
rc = -ENOMEM;
1153+
goto out;
1154+
}
1155+
1156+
/* Highest DFS referral version understood */
1157+
dfs_req->MaxReferralLevel = DFS_VERSION;
1158+
1159+
/* Path to resolve in an UTF-16 null-terminated string */
1160+
memcpy(dfs_req->RequestFileName, utf16_path, utf16_path_len);
1161+
1162+
do {
1163+
/* try first with IPC */
1164+
rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
1165+
FSCTL_DFS_GET_REFERRALS,
1166+
true /* is_fsctl */, true /* use_ipc */,
1167+
(char *)dfs_req, dfs_req_size,
1168+
(char **)&dfs_rsp, &dfs_rsp_size);
1169+
if (rc == -ENOTCONN) {
1170+
/* try with normal tcon */
1171+
rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
1172+
FSCTL_DFS_GET_REFERRALS,
1173+
true /* is_fsctl */, false /*use_ipc*/,
1174+
(char *)dfs_req, dfs_req_size,
1175+
(char **)&dfs_rsp, &dfs_rsp_size);
1176+
}
1177+
} while (rc == -EAGAIN);
1178+
1179+
if (rc) {
1180+
cifs_dbg(VFS, "ioctl error in smb2_get_dfs_refer rc=%d\n", rc);
1181+
goto out;
1182+
}
1183+
1184+
rc = parse_dfs_referrals(dfs_rsp, dfs_rsp_size,
1185+
num_of_nodes, target_nodes,
1186+
nls_codepage, remap, search_name,
1187+
true /* is_unicode */);
1188+
if (rc) {
1189+
cifs_dbg(VFS, "parse error in smb2_get_dfs_refer rc=%d\n", rc);
1190+
goto out;
1191+
}
1192+
1193+
out:
1194+
if (tcon) {
1195+
spin_lock(&cifs_tcp_ses_lock);
1196+
tcon->tc_count--;
1197+
spin_unlock(&cifs_tcp_ses_lock);
1198+
}
1199+
kfree(utf16_path);
1200+
kfree(dfs_req);
1201+
kfree(dfs_rsp);
1202+
return rc;
1203+
}
11071204
#define SMB2_SYMLINK_STRUCT_SIZE \
11081205
(sizeof(struct smb2_err_rsp) - 1 + sizeof(struct smb2_symlink_err_rsp))
11091206

@@ -2283,6 +2380,7 @@ struct smb_version_operations smb20_operations = {
22832380
.clone_range = smb2_clone_range,
22842381
.wp_retry_size = smb2_wp_retry_size,
22852382
.dir_needs_close = smb2_dir_needs_close,
2383+
.get_dfs_refer = smb2_get_dfs_refer,
22862384
};
22872385

22882386
struct smb_version_operations smb21_operations = {
@@ -2364,6 +2462,7 @@ struct smb_version_operations smb21_operations = {
23642462
.wp_retry_size = smb2_wp_retry_size,
23652463
.dir_needs_close = smb2_dir_needs_close,
23662464
.enum_snapshots = smb3_enum_snapshots,
2465+
.get_dfs_refer = smb2_get_dfs_refer,
23672466
};
23682467

23692468
struct smb_version_operations smb30_operations = {
@@ -2455,6 +2554,7 @@ struct smb_version_operations smb30_operations = {
24552554
.free_transform_rq = smb3_free_transform_rq,
24562555
.is_transform_hdr = smb3_is_transform_hdr,
24572556
.receive_transform = smb3_receive_transform,
2557+
.get_dfs_refer = smb2_get_dfs_refer,
24582558
};
24592559

24602560
#ifdef CONFIG_CIFS_SMB311
@@ -2547,6 +2647,7 @@ struct smb_version_operations smb311_operations = {
25472647
.free_transform_rq = smb3_free_transform_rq,
25482648
.is_transform_hdr = smb3_is_transform_hdr,
25492649
.receive_transform = smb3_receive_transform,
2650+
.get_dfs_refer = smb2_get_dfs_refer,
25502651
};
25512652
#endif /* CIFS_SMB311 */
25522653

fs/cifs/smb2pdu.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,14 @@ struct fsctl_get_integrity_information_rsp {
695695
/* Integrity flags for above */
696696
#define FSCTL_INTEGRITY_FLAG_CHECKSUM_ENFORCEMENT_OFF 0x00000001
697697

698+
/* See MS-DFSC 2.2.2 */
699+
struct fsctl_get_dfs_referral_req {
700+
__le16 MaxReferralLevel;
701+
__u8 RequestFileName[];
702+
} __packed;
703+
704+
/* DFS response is struct get_dfs_refer_rsp */
705+
698706
/* See MS-SMB2 2.2.31.3 */
699707
struct network_resiliency_req {
700708
__le32 Timeout;

0 commit comments

Comments
 (0)