diff options
-rw-r--r-- | fs/cifs/cifsglob.h | 8 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 5 | ||||
-rw-r--r-- | fs/cifs/connect.c | 2 | ||||
-rw-r--r-- | fs/cifs/misc.c | 2 | ||||
-rw-r--r-- | fs/cifs/smb2misc.c | 36 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 13 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 10 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.h | 8 | ||||
-rw-r--r-- | fs/cifs/smb2proto.h | 3 | ||||
-rw-r--r-- | fs/cifs/smb2transport.c | 102 |
10 files changed, 156 insertions, 33 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 9d14926531ba..a25b2513f146 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -227,7 +227,7 @@ struct smb_version_operations { | |||
227 | void (*print_stats)(struct seq_file *m, struct cifs_tcon *); | 227 | void (*print_stats)(struct seq_file *m, struct cifs_tcon *); |
228 | void (*dump_share_caps)(struct seq_file *, struct cifs_tcon *); | 228 | void (*dump_share_caps)(struct seq_file *, struct cifs_tcon *); |
229 | /* verify the message */ | 229 | /* verify the message */ |
230 | int (*check_message)(char *, unsigned int); | 230 | int (*check_message)(char *, unsigned int, struct TCP_Server_Info *); |
231 | bool (*is_oplock_break)(char *, struct TCP_Server_Info *); | 231 | bool (*is_oplock_break)(char *, struct TCP_Server_Info *); |
232 | void (*downgrade_oplock)(struct TCP_Server_Info *, | 232 | void (*downgrade_oplock)(struct TCP_Server_Info *, |
233 | struct cifsInodeInfo *, bool); | 233 | struct cifsInodeInfo *, bool); |
@@ -630,6 +630,7 @@ struct TCP_Server_Info { | |||
630 | #ifdef CONFIG_CIFS_SMB2 | 630 | #ifdef CONFIG_CIFS_SMB2 |
631 | unsigned int max_read; | 631 | unsigned int max_read; |
632 | unsigned int max_write; | 632 | unsigned int max_write; |
633 | __u8 preauth_hash[512]; | ||
633 | #endif /* CONFIG_CIFS_SMB2 */ | 634 | #endif /* CONFIG_CIFS_SMB2 */ |
634 | unsigned long echo_interval; | 635 | unsigned long echo_interval; |
635 | }; | 636 | }; |
@@ -813,7 +814,10 @@ struct cifs_ses { | |||
813 | bool need_reconnect:1; /* connection reset, uid now invalid */ | 814 | bool need_reconnect:1; /* connection reset, uid now invalid */ |
814 | #ifdef CONFIG_CIFS_SMB2 | 815 | #ifdef CONFIG_CIFS_SMB2 |
815 | __u16 session_flags; | 816 | __u16 session_flags; |
816 | char smb3signingkey[SMB3_SIGN_KEY_SIZE]; /* for signing smb3 packets */ | 817 | __u8 smb3signingkey[SMB3_SIGN_KEY_SIZE]; |
818 | __u8 smb3encryptionkey[SMB3_SIGN_KEY_SIZE]; | ||
819 | __u8 smb3decryptionkey[SMB3_SIGN_KEY_SIZE]; | ||
820 | __u8 preauth_hash[512]; | ||
817 | #endif /* CONFIG_CIFS_SMB2 */ | 821 | #endif /* CONFIG_CIFS_SMB2 */ |
818 | }; | 822 | }; |
819 | 823 | ||
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index c63fd1dde25b..eed7ff50faf0 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -102,7 +102,7 @@ extern int SendReceiveBlockingLock(const unsigned int xid, | |||
102 | struct smb_hdr *out_buf, | 102 | struct smb_hdr *out_buf, |
103 | int *bytes_returned); | 103 | int *bytes_returned); |
104 | extern int cifs_reconnect(struct TCP_Server_Info *server); | 104 | extern int cifs_reconnect(struct TCP_Server_Info *server); |
105 | extern int checkSMB(char *buf, unsigned int length); | 105 | extern int checkSMB(char *buf, unsigned int len, struct TCP_Server_Info *srvr); |
106 | extern bool is_valid_oplock_break(char *, struct TCP_Server_Info *); | 106 | extern bool is_valid_oplock_break(char *, struct TCP_Server_Info *); |
107 | extern bool backup_cred(struct cifs_sb_info *); | 107 | extern bool backup_cred(struct cifs_sb_info *); |
108 | extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof); | 108 | extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof); |
@@ -439,7 +439,8 @@ extern int setup_ntlm_response(struct cifs_ses *, const struct nls_table *); | |||
439 | extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *); | 439 | extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *); |
440 | extern void cifs_crypto_shash_release(struct TCP_Server_Info *); | 440 | extern void cifs_crypto_shash_release(struct TCP_Server_Info *); |
441 | extern int calc_seckey(struct cifs_ses *); | 441 | extern int calc_seckey(struct cifs_ses *); |
442 | extern int generate_smb3signingkey(struct cifs_ses *); | 442 | extern int generate_smb30signingkey(struct cifs_ses *); |
443 | extern int generate_smb311signingkey(struct cifs_ses *); | ||
443 | 444 | ||
444 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 445 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
445 | extern int calc_lanman_hash(const char *password, const char *cryptkey, | 446 | extern int calc_lanman_hash(const char *password, const char *cryptkey, |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index de53c5558fe3..6ab9e83b899e 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -831,7 +831,7 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
831 | * 48 bytes is enough to display the header and a little bit | 831 | * 48 bytes is enough to display the header and a little bit |
832 | * into the payload for debugging purposes. | 832 | * into the payload for debugging purposes. |
833 | */ | 833 | */ |
834 | length = server->ops->check_message(buf, server->total_read); | 834 | length = server->ops->check_message(buf, server->total_read, server); |
835 | if (length != 0) | 835 | if (length != 0) |
836 | cifs_dump_mem("Bad SMB: ", buf, | 836 | cifs_dump_mem("Bad SMB: ", buf, |
837 | min_t(unsigned int, server->total_read, 48)); | 837 | min_t(unsigned int, server->total_read, 48)); |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 8442b8b8e0be..813fe13c2ae1 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
@@ -310,7 +310,7 @@ check_smb_hdr(struct smb_hdr *smb) | |||
310 | } | 310 | } |
311 | 311 | ||
312 | int | 312 | int |
313 | checkSMB(char *buf, unsigned int total_read) | 313 | checkSMB(char *buf, unsigned int total_read, struct TCP_Server_Info *server) |
314 | { | 314 | { |
315 | struct smb_hdr *smb = (struct smb_hdr *)buf; | 315 | struct smb_hdr *smb = (struct smb_hdr *)buf; |
316 | __u32 rfclen = be32_to_cpu(smb->smb_buf_length); | 316 | __u32 rfclen = be32_to_cpu(smb->smb_buf_length); |
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index 1c5907019045..389fb9f8c84e 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c | |||
@@ -38,7 +38,7 @@ check_smb2_hdr(struct smb2_hdr *hdr, __u64 mid) | |||
38 | * Make sure that this really is an SMB, that it is a response, | 38 | * Make sure that this really is an SMB, that it is a response, |
39 | * and that the message ids match. | 39 | * and that the message ids match. |
40 | */ | 40 | */ |
41 | if ((*(__le32 *)hdr->ProtocolId == SMB2_PROTO_NUMBER) && | 41 | if ((hdr->ProtocolId == SMB2_PROTO_NUMBER) && |
42 | (mid == wire_mid)) { | 42 | (mid == wire_mid)) { |
43 | if (hdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR) | 43 | if (hdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR) |
44 | return 0; | 44 | return 0; |
@@ -50,9 +50,9 @@ check_smb2_hdr(struct smb2_hdr *hdr, __u64 mid) | |||
50 | cifs_dbg(VFS, "Received Request not response\n"); | 50 | cifs_dbg(VFS, "Received Request not response\n"); |
51 | } | 51 | } |
52 | } else { /* bad signature or mid */ | 52 | } else { /* bad signature or mid */ |
53 | if (*(__le32 *)hdr->ProtocolId != SMB2_PROTO_NUMBER) | 53 | if (hdr->ProtocolId != SMB2_PROTO_NUMBER) |
54 | cifs_dbg(VFS, "Bad protocol string signature header %x\n", | 54 | cifs_dbg(VFS, "Bad protocol string signature header %x\n", |
55 | *(unsigned int *) hdr->ProtocolId); | 55 | le32_to_cpu(hdr->ProtocolId)); |
56 | if (mid != wire_mid) | 56 | if (mid != wire_mid) |
57 | cifs_dbg(VFS, "Mids do not match: %llu and %llu\n", | 57 | cifs_dbg(VFS, "Mids do not match: %llu and %llu\n", |
58 | mid, wire_mid); | 58 | mid, wire_mid); |
@@ -93,11 +93,11 @@ static const __le16 smb2_rsp_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = { | |||
93 | }; | 93 | }; |
94 | 94 | ||
95 | int | 95 | int |
96 | smb2_check_message(char *buf, unsigned int length) | 96 | smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr) |
97 | { | 97 | { |
98 | struct smb2_hdr *hdr = (struct smb2_hdr *)buf; | 98 | struct smb2_hdr *hdr = (struct smb2_hdr *)buf; |
99 | struct smb2_pdu *pdu = (struct smb2_pdu *)hdr; | 99 | struct smb2_pdu *pdu = (struct smb2_pdu *)hdr; |
100 | __u64 mid = le64_to_cpu(hdr->MessageId); | 100 | __u64 mid; |
101 | __u32 len = get_rfc1002_length(buf); | 101 | __u32 len = get_rfc1002_length(buf); |
102 | __u32 clc_len; /* calculated length */ | 102 | __u32 clc_len; /* calculated length */ |
103 | int command; | 103 | int command; |
@@ -111,6 +111,30 @@ smb2_check_message(char *buf, unsigned int length) | |||
111 | * ie Validate the wct via smb2_struct_sizes table above | 111 | * ie Validate the wct via smb2_struct_sizes table above |
112 | */ | 112 | */ |
113 | 113 | ||
114 | if (hdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) { | ||
115 | struct smb2_transform_hdr *thdr = | ||
116 | (struct smb2_transform_hdr *)buf; | ||
117 | struct cifs_ses *ses = NULL; | ||
118 | struct list_head *tmp; | ||
119 | |||
120 | /* decrypt frame now that it is completely read in */ | ||
121 | spin_lock(&cifs_tcp_ses_lock); | ||
122 | list_for_each(tmp, &srvr->smb_ses_list) { | ||
123 | ses = list_entry(tmp, struct cifs_ses, smb_ses_list); | ||
124 | if (ses->Suid == thdr->SessionId) | ||
125 | break; | ||
126 | |||
127 | ses = NULL; | ||
128 | } | ||
129 | spin_unlock(&cifs_tcp_ses_lock); | ||
130 | if (ses == NULL) { | ||
131 | cifs_dbg(VFS, "no decryption - session id not found\n"); | ||
132 | return 1; | ||
133 | } | ||
134 | } | ||
135 | |||
136 | |||
137 | mid = le64_to_cpu(hdr->MessageId); | ||
114 | if (length < sizeof(struct smb2_pdu)) { | 138 | if (length < sizeof(struct smb2_pdu)) { |
115 | if ((length >= sizeof(struct smb2_hdr)) && (hdr->Status != 0)) { | 139 | if ((length >= sizeof(struct smb2_hdr)) && (hdr->Status != 0)) { |
116 | pdu->StructureSize2 = 0; | 140 | pdu->StructureSize2 = 0; |
@@ -322,7 +346,7 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr) | |||
322 | 346 | ||
323 | /* return pointer to beginning of data area, ie offset from SMB start */ | 347 | /* return pointer to beginning of data area, ie offset from SMB start */ |
324 | if ((*off != 0) && (*len != 0)) | 348 | if ((*off != 0) && (*len != 0)) |
325 | return (char *)(&hdr->ProtocolId[0]) + *off; | 349 | return (char *)(&hdr->ProtocolId) + *off; |
326 | else | 350 | else |
327 | return NULL; | 351 | return NULL; |
328 | } | 352 | } |
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 53ccdde6ff18..3525ed756173 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c | |||
@@ -182,6 +182,11 @@ smb2_find_mid(struct TCP_Server_Info *server, char *buf) | |||
182 | struct smb2_hdr *hdr = (struct smb2_hdr *)buf; | 182 | struct smb2_hdr *hdr = (struct smb2_hdr *)buf; |
183 | __u64 wire_mid = le64_to_cpu(hdr->MessageId); | 183 | __u64 wire_mid = le64_to_cpu(hdr->MessageId); |
184 | 184 | ||
185 | if (hdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) { | ||
186 | cifs_dbg(VFS, "encrypted frame parsing not supported yet"); | ||
187 | return NULL; | ||
188 | } | ||
189 | |||
185 | spin_lock(&GlobalMid_Lock); | 190 | spin_lock(&GlobalMid_Lock); |
186 | list_for_each_entry(mid, &server->pending_mid_q, qhead) { | 191 | list_for_each_entry(mid, &server->pending_mid_q, qhead) { |
187 | if ((mid->mid == wire_mid) && | 192 | if ((mid->mid == wire_mid) && |
@@ -1692,7 +1697,7 @@ struct smb_version_operations smb30_operations = { | |||
1692 | .get_lease_key = smb2_get_lease_key, | 1697 | .get_lease_key = smb2_get_lease_key, |
1693 | .set_lease_key = smb2_set_lease_key, | 1698 | .set_lease_key = smb2_set_lease_key, |
1694 | .new_lease_key = smb2_new_lease_key, | 1699 | .new_lease_key = smb2_new_lease_key, |
1695 | .generate_signingkey = generate_smb3signingkey, | 1700 | .generate_signingkey = generate_smb30signingkey, |
1696 | .calc_signature = smb3_calc_signature, | 1701 | .calc_signature = smb3_calc_signature, |
1697 | .set_integrity = smb3_set_integrity, | 1702 | .set_integrity = smb3_set_integrity, |
1698 | .is_read_op = smb21_is_read_op, | 1703 | .is_read_op = smb21_is_read_op, |
@@ -1779,7 +1784,7 @@ struct smb_version_operations smb311_operations = { | |||
1779 | .get_lease_key = smb2_get_lease_key, | 1784 | .get_lease_key = smb2_get_lease_key, |
1780 | .set_lease_key = smb2_set_lease_key, | 1785 | .set_lease_key = smb2_set_lease_key, |
1781 | .new_lease_key = smb2_new_lease_key, | 1786 | .new_lease_key = smb2_new_lease_key, |
1782 | .generate_signingkey = generate_smb3signingkey, | 1787 | .generate_signingkey = generate_smb311signingkey, |
1783 | .calc_signature = smb3_calc_signature, | 1788 | .calc_signature = smb3_calc_signature, |
1784 | .set_integrity = smb3_set_integrity, | 1789 | .set_integrity = smb3_set_integrity, |
1785 | .is_read_op = smb21_is_read_op, | 1790 | .is_read_op = smb21_is_read_op, |
@@ -1838,7 +1843,7 @@ struct smb_version_values smb21_values = { | |||
1838 | struct smb_version_values smb30_values = { | 1843 | struct smb_version_values smb30_values = { |
1839 | .version_string = SMB30_VERSION_STRING, | 1844 | .version_string = SMB30_VERSION_STRING, |
1840 | .protocol_id = SMB30_PROT_ID, | 1845 | .protocol_id = SMB30_PROT_ID, |
1841 | .req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU | SMB2_GLOBAL_CAP_PERSISTENT_HANDLES, | 1846 | .req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU | SMB2_GLOBAL_CAP_PERSISTENT_HANDLES | SMB2_GLOBAL_CAP_ENCRYPTION, |
1842 | .large_lock_type = 0, | 1847 | .large_lock_type = 0, |
1843 | .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, | 1848 | .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, |
1844 | .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, | 1849 | .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, |
@@ -1858,7 +1863,7 @@ struct smb_version_values smb30_values = { | |||
1858 | struct smb_version_values smb302_values = { | 1863 | struct smb_version_values smb302_values = { |
1859 | .version_string = SMB302_VERSION_STRING, | 1864 | .version_string = SMB302_VERSION_STRING, |
1860 | .protocol_id = SMB302_PROT_ID, | 1865 | .protocol_id = SMB302_PROT_ID, |
1861 | .req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU | SMB2_GLOBAL_CAP_PERSISTENT_HANDLES, | 1866 | .req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU | SMB2_GLOBAL_CAP_PERSISTENT_HANDLES | SMB2_GLOBAL_CAP_ENCRYPTION, |
1862 | .large_lock_type = 0, | 1867 | .large_lock_type = 0, |
1863 | .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, | 1868 | .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, |
1864 | .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, | 1869 | .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, |
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 767555518d40..10f8d5cf5681 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c | |||
@@ -97,10 +97,7 @@ smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ , | |||
97 | hdr->smb2_buf_length = cpu_to_be32(parmsize + sizeof(struct smb2_hdr) | 97 | hdr->smb2_buf_length = cpu_to_be32(parmsize + sizeof(struct smb2_hdr) |
98 | - 4 /* RFC 1001 length field itself not counted */); | 98 | - 4 /* RFC 1001 length field itself not counted */); |
99 | 99 | ||
100 | hdr->ProtocolId[0] = 0xFE; | 100 | hdr->ProtocolId = SMB2_PROTO_NUMBER; |
101 | hdr->ProtocolId[1] = 'S'; | ||
102 | hdr->ProtocolId[2] = 'M'; | ||
103 | hdr->ProtocolId[3] = 'B'; | ||
104 | hdr->StructureSize = cpu_to_le16(64); | 101 | hdr->StructureSize = cpu_to_le16(64); |
105 | hdr->Command = smb2_cmd; | 102 | hdr->Command = smb2_cmd; |
106 | hdr->CreditRequest = cpu_to_le16(2); /* BB make this dynamic */ | 103 | hdr->CreditRequest = cpu_to_le16(2); /* BB make this dynamic */ |
@@ -1573,7 +1570,8 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, | |||
1573 | goto ioctl_exit; | 1570 | goto ioctl_exit; |
1574 | } | 1571 | } |
1575 | 1572 | ||
1576 | memcpy(*out_data, rsp->hdr.ProtocolId + le32_to_cpu(rsp->OutputOffset), | 1573 | memcpy(*out_data, |
1574 | (char *)&rsp->hdr.ProtocolId + le32_to_cpu(rsp->OutputOffset), | ||
1577 | *plen); | 1575 | *plen); |
1578 | ioctl_exit: | 1576 | ioctl_exit: |
1579 | free_rsp_buf(resp_buftype, rsp); | 1577 | free_rsp_buf(resp_buftype, rsp); |
@@ -2093,7 +2091,7 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms, | |||
2093 | } | 2091 | } |
2094 | 2092 | ||
2095 | if (*buf) { | 2093 | if (*buf) { |
2096 | memcpy(*buf, (char *)rsp->hdr.ProtocolId + rsp->DataOffset, | 2094 | memcpy(*buf, (char *)&rsp->hdr.ProtocolId + rsp->DataOffset, |
2097 | *nbytes); | 2095 | *nbytes); |
2098 | free_rsp_buf(resp_buftype, iov[0].iov_base); | 2096 | free_rsp_buf(resp_buftype, iov[0].iov_base); |
2099 | } else if (resp_buftype != CIFS_NO_BUFFER) { | 2097 | } else if (resp_buftype != CIFS_NO_BUFFER) { |
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index 4af52780ec35..ff88d9feb01e 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h | |||
@@ -86,6 +86,7 @@ | |||
86 | #define MAX_SMB2_HDR_SIZE 0x78 /* 4 len + 64 hdr + (2*24 wct) + 2 bct + 2 pad */ | 86 | #define MAX_SMB2_HDR_SIZE 0x78 /* 4 len + 64 hdr + (2*24 wct) + 2 bct + 2 pad */ |
87 | 87 | ||
88 | #define SMB2_PROTO_NUMBER cpu_to_le32(0x424d53fe) | 88 | #define SMB2_PROTO_NUMBER cpu_to_le32(0x424d53fe) |
89 | #define SMB2_TRANSFORM_PROTO_NUM cpu_to_le32(0x424d53fd) | ||
89 | 90 | ||
90 | /* | 91 | /* |
91 | * SMB2 Header Definition | 92 | * SMB2 Header Definition |
@@ -102,7 +103,7 @@ struct smb2_hdr { | |||
102 | __be32 smb2_buf_length; /* big endian on wire */ | 103 | __be32 smb2_buf_length; /* big endian on wire */ |
103 | /* length is only two or three bytes - with | 104 | /* length is only two or three bytes - with |
104 | one or two byte type preceding it that MBZ */ | 105 | one or two byte type preceding it that MBZ */ |
105 | __u8 ProtocolId[4]; /* 0xFE 'S' 'M' 'B' */ | 106 | __le32 ProtocolId; /* 0xFE 'S' 'M' 'B' */ |
106 | __le16 StructureSize; /* 64 */ | 107 | __le16 StructureSize; /* 64 */ |
107 | __le16 CreditCharge; /* MBZ */ | 108 | __le16 CreditCharge; /* MBZ */ |
108 | __le32 Status; /* Error from server */ | 109 | __le32 Status; /* Error from server */ |
@@ -128,11 +129,10 @@ struct smb2_transform_hdr { | |||
128 | one or two byte type preceding it that MBZ */ | 129 | one or two byte type preceding it that MBZ */ |
129 | __u8 ProtocolId[4]; /* 0xFD 'S' 'M' 'B' */ | 130 | __u8 ProtocolId[4]; /* 0xFD 'S' 'M' 'B' */ |
130 | __u8 Signature[16]; | 131 | __u8 Signature[16]; |
131 | __u8 Nonce[11]; | 132 | __u8 Nonce[16]; |
132 | __u8 Reserved[5]; | ||
133 | __le32 OriginalMessageSize; | 133 | __le32 OriginalMessageSize; |
134 | __u16 Reserved1; | 134 | __u16 Reserved1; |
135 | __le16 EncryptionAlgorithm; | 135 | __le16 Flags; /* EncryptionAlgorithm */ |
136 | __u64 SessionId; | 136 | __u64 SessionId; |
137 | } __packed; | 137 | } __packed; |
138 | 138 | ||
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 79dc650c18b2..4f07dc93608d 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h | |||
@@ -34,7 +34,8 @@ struct smb_rqst; | |||
34 | ***************************************************************** | 34 | ***************************************************************** |
35 | */ | 35 | */ |
36 | extern int map_smb2_to_linux_error(char *buf, bool log_err); | 36 | extern int map_smb2_to_linux_error(char *buf, bool log_err); |
37 | extern int smb2_check_message(char *buf, unsigned int length); | 37 | extern int smb2_check_message(char *buf, unsigned int length, |
38 | struct TCP_Server_Info *server); | ||
38 | extern unsigned int smb2_calc_size(void *buf); | 39 | extern unsigned int smb2_calc_size(void *buf); |
39 | extern char *smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr); | 40 | extern char *smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr); |
40 | extern __le16 *cifs_convert_path_to_utf16(const char *from, | 41 | extern __le16 *cifs_convert_path_to_utf16(const char *from, |
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c index d4c5b6f109a7..8732a43b1008 100644 --- a/fs/cifs/smb2transport.c +++ b/fs/cifs/smb2transport.c | |||
@@ -222,8 +222,8 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) | |||
222 | return rc; | 222 | return rc; |
223 | } | 223 | } |
224 | 224 | ||
225 | int | 225 | static int generate_key(struct cifs_ses *ses, struct kvec label, |
226 | generate_smb3signingkey(struct cifs_ses *ses) | 226 | struct kvec context, __u8 *key, unsigned int key_size) |
227 | { | 227 | { |
228 | unsigned char zero = 0x0; | 228 | unsigned char zero = 0x0; |
229 | __u8 i[4] = {0, 0, 0, 1}; | 229 | __u8 i[4] = {0, 0, 0, 1}; |
@@ -233,7 +233,7 @@ generate_smb3signingkey(struct cifs_ses *ses) | |||
233 | unsigned char *hashptr = prfhash; | 233 | unsigned char *hashptr = prfhash; |
234 | 234 | ||
235 | memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE); | 235 | memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE); |
236 | memset(ses->smb3signingkey, 0x0, SMB3_SIGNKEY_SIZE); | 236 | memset(key, 0x0, key_size); |
237 | 237 | ||
238 | rc = smb3_crypto_shash_allocate(ses->server); | 238 | rc = smb3_crypto_shash_allocate(ses->server); |
239 | if (rc) { | 239 | if (rc) { |
@@ -262,7 +262,7 @@ generate_smb3signingkey(struct cifs_ses *ses) | |||
262 | } | 262 | } |
263 | 263 | ||
264 | rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash, | 264 | rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash, |
265 | "SMB2AESCMAC", 12); | 265 | label.iov_base, label.iov_len); |
266 | if (rc) { | 266 | if (rc) { |
267 | cifs_dbg(VFS, "%s: Could not update with label\n", __func__); | 267 | cifs_dbg(VFS, "%s: Could not update with label\n", __func__); |
268 | goto smb3signkey_ret; | 268 | goto smb3signkey_ret; |
@@ -276,7 +276,7 @@ generate_smb3signingkey(struct cifs_ses *ses) | |||
276 | } | 276 | } |
277 | 277 | ||
278 | rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash, | 278 | rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash, |
279 | "SmbSign", 8); | 279 | context.iov_base, context.iov_len); |
280 | if (rc) { | 280 | if (rc) { |
281 | cifs_dbg(VFS, "%s: Could not update with context\n", __func__); | 281 | cifs_dbg(VFS, "%s: Could not update with context\n", __func__); |
282 | goto smb3signkey_ret; | 282 | goto smb3signkey_ret; |
@@ -296,12 +296,102 @@ generate_smb3signingkey(struct cifs_ses *ses) | |||
296 | goto smb3signkey_ret; | 296 | goto smb3signkey_ret; |
297 | } | 297 | } |
298 | 298 | ||
299 | memcpy(ses->smb3signingkey, hashptr, SMB3_SIGNKEY_SIZE); | 299 | memcpy(key, hashptr, key_size); |
300 | 300 | ||
301 | smb3signkey_ret: | 301 | smb3signkey_ret: |
302 | return rc; | 302 | return rc; |
303 | } | 303 | } |
304 | 304 | ||
305 | struct derivation { | ||
306 | struct kvec label; | ||
307 | struct kvec context; | ||
308 | }; | ||
309 | |||
310 | struct derivation_triplet { | ||
311 | struct derivation signing; | ||
312 | struct derivation encryption; | ||
313 | struct derivation decryption; | ||
314 | }; | ||
315 | |||
316 | static int | ||
317 | generate_smb3signingkey(struct cifs_ses *ses, | ||
318 | const struct derivation_triplet *ptriplet) | ||
319 | { | ||
320 | int rc; | ||
321 | |||
322 | rc = generate_key(ses, ptriplet->signing.label, | ||
323 | ptriplet->signing.context, ses->smb3signingkey, | ||
324 | SMB3_SIGN_KEY_SIZE); | ||
325 | if (rc) | ||
326 | return rc; | ||
327 | |||
328 | rc = generate_key(ses, ptriplet->encryption.label, | ||
329 | ptriplet->encryption.context, ses->smb3encryptionkey, | ||
330 | SMB3_SIGN_KEY_SIZE); | ||
331 | if (rc) | ||
332 | return rc; | ||
333 | |||
334 | return generate_key(ses, ptriplet->decryption.label, | ||
335 | ptriplet->decryption.context, | ||
336 | ses->smb3decryptionkey, SMB3_SIGN_KEY_SIZE); | ||
337 | } | ||
338 | |||
339 | int | ||
340 | generate_smb30signingkey(struct cifs_ses *ses) | ||
341 | |||
342 | { | ||
343 | struct derivation_triplet triplet; | ||
344 | struct derivation *d; | ||
345 | |||
346 | d = &triplet.signing; | ||
347 | d->label.iov_base = "SMB2AESCMAC"; | ||
348 | d->label.iov_len = 12; | ||
349 | d->context.iov_base = "SmbSign"; | ||
350 | d->context.iov_len = 8; | ||
351 | |||
352 | d = &triplet.encryption; | ||
353 | d->label.iov_base = "SMB2AESCCM"; | ||
354 | d->label.iov_len = 11; | ||
355 | d->context.iov_base = "ServerIn "; | ||
356 | d->context.iov_len = 10; | ||
357 | |||
358 | d = &triplet.decryption; | ||
359 | d->label.iov_base = "SMB2AESCCM"; | ||
360 | d->label.iov_len = 11; | ||
361 | d->context.iov_base = "ServerOut"; | ||
362 | d->context.iov_len = 10; | ||
363 | |||
364 | return generate_smb3signingkey(ses, &triplet); | ||
365 | } | ||
366 | |||
367 | int | ||
368 | generate_smb311signingkey(struct cifs_ses *ses) | ||
369 | |||
370 | { | ||
371 | struct derivation_triplet triplet; | ||
372 | struct derivation *d; | ||
373 | |||
374 | d = &triplet.signing; | ||
375 | d->label.iov_base = "SMB2AESCMAC"; | ||
376 | d->label.iov_len = 12; | ||
377 | d->context.iov_base = "SmbSign"; | ||
378 | d->context.iov_len = 8; | ||
379 | |||
380 | d = &triplet.encryption; | ||
381 | d->label.iov_base = "SMB2AESCCM"; | ||
382 | d->label.iov_len = 11; | ||
383 | d->context.iov_base = "ServerIn "; | ||
384 | d->context.iov_len = 10; | ||
385 | |||
386 | d = &triplet.decryption; | ||
387 | d->label.iov_base = "SMB2AESCCM"; | ||
388 | d->label.iov_len = 11; | ||
389 | d->context.iov_base = "ServerOut"; | ||
390 | d->context.iov_len = 10; | ||
391 | |||
392 | return generate_smb3signingkey(ses, &triplet); | ||
393 | } | ||
394 | |||
305 | int | 395 | int |
306 | smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) | 396 | smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) |
307 | { | 397 | { |