Skip to content

Commit 0a040b2

Browse files
committed
Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6
Pull SMB3 fixes from Steve French: "Some small bug fixes as well as SMB2.1/SMB3 enablement for DFS (global namespace) which previously was only enabled for CIFS" * 'for-next' of git://git.samba.org/sfrench/cifs-2.6: smb2: Enforce sec= mount option CIFS: Fix sparse warnings CIFS: implement get_dfs_refer for SMB2+ CIFS: use DFS pathnames in SMB2+ Create requests CIFS: set signing flag in SMB2+ TreeConnect if needed CIFS: let ses->ipc_tid hold smb2 TreeIds CIFS: add use_ipc flag to SMB2_ioctl() CIFS: add build_path_from_dentry_optional_prefix() CIFS: move DFS response parsing out of SMB1 code CIFS: Fix possible use after free in demultiplex thread
2 parents 4e66c42 + ef65aae commit 0a040b2

File tree

16 files changed

+447
-168
lines changed

16 files changed

+447
-168
lines changed

fs/cifs/cifs_dfs_ref.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,9 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
303303
* gives us the latter, so we must adjust the result.
304304
*/
305305
mnt = ERR_PTR(-ENOMEM);
306-
full_path = build_path_from_dentry(mntpt);
306+
307+
/* always use tree name prefix */
308+
full_path = build_path_from_dentry_optional_prefix(mntpt, true);
307309
if (full_path == NULL)
308310
goto cdda_exit;
309311

fs/cifs/cifs_unicode.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,10 @@ wchar_t cifs_toupper(wchar_t in);
130130
* Returns:
131131
* Address of the first string
132132
*/
133-
static inline wchar_t *
134-
UniStrcat(wchar_t *ucs1, const wchar_t *ucs2)
133+
static inline __le16 *
134+
UniStrcat(__le16 *ucs1, const __le16 *ucs2)
135135
{
136-
wchar_t *anchor = ucs1; /* save a pointer to start of ucs1 */
136+
__le16 *anchor = ucs1; /* save a pointer to start of ucs1 */
137137

138138
while (*ucs1++) ; /* To end of first string */
139139
ucs1--; /* Return to the null */

fs/cifs/cifsglob.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,9 @@ struct smb_version_operations {
443443
int (*is_transform_hdr)(void *buf);
444444
int (*receive_transform)(struct TCP_Server_Info *,
445445
struct mid_q_entry **);
446+
enum securityEnum (*select_sectype)(struct TCP_Server_Info *,
447+
enum securityEnum);
448+
446449
};
447450

448451
struct smb_version_values {
@@ -822,7 +825,7 @@ struct cifs_ses {
822825
int ses_count; /* reference counter */
823826
enum statusEnum status;
824827
unsigned overrideSecFlg; /* if non-zero override global sec flags */
825-
__u16 ipc_tid; /* special tid for connection to IPC share */
828+
__u32 ipc_tid; /* special tid for connection to IPC share */
826829
char *serverOS; /* name of operating system underlying server */
827830
char *serverNOS; /* name of network operating system of server */
828831
char *serverDomain; /* security realm of server */

fs/cifs/cifspdu.h

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2086,17 +2086,21 @@ typedef struct dfs_referral_level_3 { /* version 4 is same, + one flag bit */
20862086
__u8 ServiceSiteGuid[16]; /* MBZ, ignored */
20872087
} __attribute__((packed)) REFERRAL3;
20882088

2089-
typedef struct smb_com_transaction_get_dfs_refer_rsp {
2090-
struct smb_hdr hdr; /* wct = 10 */
2091-
struct trans2_resp t2;
2092-
__u16 ByteCount;
2093-
__u8 Pad;
2089+
struct get_dfs_referral_rsp {
20942090
__le16 PathConsumed;
20952091
__le16 NumberOfReferrals;
20962092
__le32 DFSFlags;
20972093
REFERRAL3 referrals[1]; /* array of level 3 dfs_referral structures */
20982094
/* followed by the strings pointed to by the referral structures */
2099-
} __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_RSP;
2095+
} __packed;
2096+
2097+
typedef struct smb_com_transaction_get_dfs_refer_rsp {
2098+
struct smb_hdr hdr; /* wct = 10 */
2099+
struct trans2_resp t2;
2100+
__u16 ByteCount;
2101+
__u8 Pad;
2102+
struct get_dfs_referral_rsp dfs_data;
2103+
} __packed TRANSACTION2_GET_DFS_REFER_RSP;
21002104

21012105
/* DFS Flags */
21022106
#define DFSREF_REFERRAL_SERVER 0x00000001 /* all targets are DFS roots */

fs/cifs/cifsproto.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ extern void exit_cifs_idmap(void);
6161
extern int init_cifs_spnego(void);
6262
extern void exit_cifs_spnego(void);
6363
extern char *build_path_from_dentry(struct dentry *);
64+
extern char *build_path_from_dentry_optional_prefix(struct dentry *direntry,
65+
bool prefix);
6466
extern char *cifs_build_path_to_root(struct smb_vol *vol,
6567
struct cifs_sb_info *cifs_sb,
6668
struct cifs_tcon *tcon,
@@ -284,6 +286,11 @@ extern int get_dfs_path(const unsigned int xid, struct cifs_ses *ses,
284286
const struct nls_table *nls_codepage,
285287
unsigned int *num_referrals,
286288
struct dfs_info3_param **referrals, int remap);
289+
extern int parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
290+
unsigned int *num_of_nodes,
291+
struct dfs_info3_param **target_nodes,
292+
const struct nls_table *nls_codepage, int remap,
293+
const char *searchName, bool is_unicode);
287294
extern void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon,
288295
struct cifs_sb_info *cifs_sb,
289296
struct smb_vol *vol);
@@ -526,4 +533,6 @@ int cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
526533
int __cifs_calc_signature(struct smb_rqst *rqst,
527534
struct TCP_Server_Info *server, char *signature,
528535
struct shash_desc *shash);
536+
enum securityEnum cifs_select_sectype(struct TCP_Server_Info *,
537+
enum securityEnum);
529538
#endif /* _CIFSPROTO_H */

fs/cifs/cifssmb.c

Lines changed: 5 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -4786,117 +4786,6 @@ CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
47864786
return rc;
47874787
}
47884788

4789-
/* parses DFS refferal V3 structure
4790-
* caller is responsible for freeing target_nodes
4791-
* returns:
4792-
* on success - 0
4793-
* on failure - errno
4794-
*/
4795-
static int
4796-
parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
4797-
unsigned int *num_of_nodes,
4798-
struct dfs_info3_param **target_nodes,
4799-
const struct nls_table *nls_codepage, int remap,
4800-
const char *searchName)
4801-
{
4802-
int i, rc = 0;
4803-
char *data_end;
4804-
bool is_unicode;
4805-
struct dfs_referral_level_3 *ref;
4806-
4807-
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4808-
is_unicode = true;
4809-
else
4810-
is_unicode = false;
4811-
*num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4812-
4813-
if (*num_of_nodes < 1) {
4814-
cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n",
4815-
*num_of_nodes);
4816-
rc = -EINVAL;
4817-
goto parse_DFS_referrals_exit;
4818-
}
4819-
4820-
ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
4821-
if (ref->VersionNumber != cpu_to_le16(3)) {
4822-
cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n",
4823-
le16_to_cpu(ref->VersionNumber));
4824-
rc = -EINVAL;
4825-
goto parse_DFS_referrals_exit;
4826-
}
4827-
4828-
/* get the upper boundary of the resp buffer */
4829-
data_end = (char *)(&(pSMBr->PathConsumed)) +
4830-
le16_to_cpu(pSMBr->t2.DataCount);
4831-
4832-
cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n",
4833-
*num_of_nodes, le32_to_cpu(pSMBr->DFSFlags));
4834-
4835-
*target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param),
4836-
GFP_KERNEL);
4837-
if (*target_nodes == NULL) {
4838-
rc = -ENOMEM;
4839-
goto parse_DFS_referrals_exit;
4840-
}
4841-
4842-
/* collect necessary data from referrals */
4843-
for (i = 0; i < *num_of_nodes; i++) {
4844-
char *temp;
4845-
int max_len;
4846-
struct dfs_info3_param *node = (*target_nodes)+i;
4847-
4848-
node->flags = le32_to_cpu(pSMBr->DFSFlags);
4849-
if (is_unicode) {
4850-
__le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4851-
GFP_KERNEL);
4852-
if (tmp == NULL) {
4853-
rc = -ENOMEM;
4854-
goto parse_DFS_referrals_exit;
4855-
}
4856-
cifsConvertToUTF16((__le16 *) tmp, searchName,
4857-
PATH_MAX, nls_codepage, remap);
4858-
node->path_consumed = cifs_utf16_bytes(tmp,
4859-
le16_to_cpu(pSMBr->PathConsumed),
4860-
nls_codepage);
4861-
kfree(tmp);
4862-
} else
4863-
node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4864-
4865-
node->server_type = le16_to_cpu(ref->ServerType);
4866-
node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4867-
4868-
/* copy DfsPath */
4869-
temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4870-
max_len = data_end - temp;
4871-
node->path_name = cifs_strndup_from_utf16(temp, max_len,
4872-
is_unicode, nls_codepage);
4873-
if (!node->path_name) {
4874-
rc = -ENOMEM;
4875-
goto parse_DFS_referrals_exit;
4876-
}
4877-
4878-
/* copy link target UNC */
4879-
temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4880-
max_len = data_end - temp;
4881-
node->node_name = cifs_strndup_from_utf16(temp, max_len,
4882-
is_unicode, nls_codepage);
4883-
if (!node->node_name) {
4884-
rc = -ENOMEM;
4885-
goto parse_DFS_referrals_exit;
4886-
}
4887-
4888-
ref++;
4889-
}
4890-
4891-
parse_DFS_referrals_exit:
4892-
if (rc) {
4893-
free_dfs_info_array(*target_nodes, *num_of_nodes);
4894-
*target_nodes = NULL;
4895-
*num_of_nodes = 0;
4896-
}
4897-
return rc;
4898-
}
4899-
49004789
int
49014790
CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
49024791
const char *search_name, struct dfs_info3_param **target_nodes,
@@ -4993,9 +4882,11 @@ CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
49934882
get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
49944883

49954884
/* parse returned result into more usable form */
4996-
rc = parse_DFS_referrals(pSMBr, num_of_nodes,
4997-
target_nodes, nls_codepage, remap,
4998-
search_name);
4885+
rc = parse_dfs_referrals(&pSMBr->dfs_data,
4886+
le16_to_cpu(pSMBr->t2.DataCount),
4887+
num_of_nodes, target_nodes, nls_codepage,
4888+
remap, search_name,
4889+
(pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) != 0);
49994890

50004891
GetDFSRefExit:
50014892
cifs_buf_release(pSMB);

fs/cifs/connect.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2074,7 +2074,8 @@ match_security(struct TCP_Server_Info *server, struct smb_vol *vol)
20742074
* that was specified, or "Unspecified" if that sectype was not
20752075
* compatible with the given NEGOTIATE request.
20762076
*/
2077-
if (select_sectype(server, vol->sectype) == Unspecified)
2077+
if (server->ops->select_sectype(server, vol->sectype)
2078+
== Unspecified)
20782079
return false;
20792080

20802081
/*

fs/cifs/dir.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,17 @@ cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
8080
/* Note: caller must free return buffer */
8181
char *
8282
build_path_from_dentry(struct dentry *direntry)
83+
{
84+
struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
85+
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
86+
bool prefix = tcon->Flags & SMB_SHARE_IS_IN_DFS;
87+
88+
return build_path_from_dentry_optional_prefix(direntry,
89+
prefix);
90+
}
91+
92+
char *
93+
build_path_from_dentry_optional_prefix(struct dentry *direntry, bool prefix)
8394
{
8495
struct dentry *temp;
8596
int namelen;
@@ -92,7 +103,7 @@ build_path_from_dentry(struct dentry *direntry)
92103
unsigned seq;
93104

94105
dirsep = CIFS_DIR_SEP(cifs_sb);
95-
if (tcon->Flags & SMB_SHARE_IS_IN_DFS)
106+
if (prefix)
96107
dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
97108
else
98109
dfsplen = 0;

fs/cifs/misc.c

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,3 +640,108 @@ cifs_add_pending_open(struct cifs_fid *fid, struct tcon_link *tlink,
640640
cifs_add_pending_open_locked(fid, tlink, open);
641641
spin_unlock(&tlink_tcon(open->tlink)->open_file_lock);
642642
}
643+
644+
/* parses DFS refferal V3 structure
645+
* caller is responsible for freeing target_nodes
646+
* returns:
647+
* - on success - 0
648+
* - on failure - errno
649+
*/
650+
int
651+
parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
652+
unsigned int *num_of_nodes,
653+
struct dfs_info3_param **target_nodes,
654+
const struct nls_table *nls_codepage, int remap,
655+
const char *searchName, bool is_unicode)
656+
{
657+
int i, rc = 0;
658+
char *data_end;
659+
struct dfs_referral_level_3 *ref;
660+
661+
*num_of_nodes = le16_to_cpu(rsp->NumberOfReferrals);
662+
663+
if (*num_of_nodes < 1) {
664+
cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n",
665+
*num_of_nodes);
666+
rc = -EINVAL;
667+
goto parse_DFS_referrals_exit;
668+
}
669+
670+
ref = (struct dfs_referral_level_3 *) &(rsp->referrals);
671+
if (ref->VersionNumber != cpu_to_le16(3)) {
672+
cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n",
673+
le16_to_cpu(ref->VersionNumber));
674+
rc = -EINVAL;
675+
goto parse_DFS_referrals_exit;
676+
}
677+
678+
/* get the upper boundary of the resp buffer */
679+
data_end = (char *)rsp + rsp_size;
680+
681+
cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n",
682+
*num_of_nodes, le32_to_cpu(rsp->DFSFlags));
683+
684+
*target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param),
685+
GFP_KERNEL);
686+
if (*target_nodes == NULL) {
687+
rc = -ENOMEM;
688+
goto parse_DFS_referrals_exit;
689+
}
690+
691+
/* collect necessary data from referrals */
692+
for (i = 0; i < *num_of_nodes; i++) {
693+
char *temp;
694+
int max_len;
695+
struct dfs_info3_param *node = (*target_nodes)+i;
696+
697+
node->flags = le32_to_cpu(rsp->DFSFlags);
698+
if (is_unicode) {
699+
__le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
700+
GFP_KERNEL);
701+
if (tmp == NULL) {
702+
rc = -ENOMEM;
703+
goto parse_DFS_referrals_exit;
704+
}
705+
cifsConvertToUTF16((__le16 *) tmp, searchName,
706+
PATH_MAX, nls_codepage, remap);
707+
node->path_consumed = cifs_utf16_bytes(tmp,
708+
le16_to_cpu(rsp->PathConsumed),
709+
nls_codepage);
710+
kfree(tmp);
711+
} else
712+
node->path_consumed = le16_to_cpu(rsp->PathConsumed);
713+
714+
node->server_type = le16_to_cpu(ref->ServerType);
715+
node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
716+
717+
/* copy DfsPath */
718+
temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
719+
max_len = data_end - temp;
720+
node->path_name = cifs_strndup_from_utf16(temp, max_len,
721+
is_unicode, nls_codepage);
722+
if (!node->path_name) {
723+
rc = -ENOMEM;
724+
goto parse_DFS_referrals_exit;
725+
}
726+
727+
/* copy link target UNC */
728+
temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
729+
max_len = data_end - temp;
730+
node->node_name = cifs_strndup_from_utf16(temp, max_len,
731+
is_unicode, nls_codepage);
732+
if (!node->node_name) {
733+
rc = -ENOMEM;
734+
goto parse_DFS_referrals_exit;
735+
}
736+
737+
ref++;
738+
}
739+
740+
parse_DFS_referrals_exit:
741+
if (rc) {
742+
free_dfs_info_array(*target_nodes, *num_of_nodes);
743+
*target_nodes = NULL;
744+
*num_of_nodes = 0;
745+
}
746+
return rc;
747+
}

fs/cifs/sess.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@ int build_ntlmssp_auth_blob(unsigned char **pbuffer,
498498
}
499499

500500
enum securityEnum
501-
select_sectype(struct TCP_Server_Info *server, enum securityEnum requested)
501+
cifs_select_sectype(struct TCP_Server_Info *server, enum securityEnum requested)
502502
{
503503
switch (server->negflavor) {
504504
case CIFS_NEGFLAVOR_EXTENDED:
@@ -1391,7 +1391,7 @@ static int select_sec(struct cifs_ses *ses, struct sess_data *sess_data)
13911391
{
13921392
int type;
13931393

1394-
type = select_sectype(ses->server, ses->sectype);
1394+
type = cifs_select_sectype(ses->server, ses->sectype);
13951395
cifs_dbg(FYI, "sess setup type %d\n", type);
13961396
if (type == Unspecified) {
13971397
cifs_dbg(VFS,

0 commit comments

Comments
 (0)