Commit | Line | Data |
---|---|---|
2dc7e1c0 PS |
1 | /* |
2 | * fs/cifs/smb2transport.c | |
3 | * | |
4 | * Copyright (C) International Business Machines Corp., 2002, 2011 | |
5 | * Etersoft, 2012 | |
6 | * Author(s): Steve French (sfrench@us.ibm.com) | |
7 | * Jeremy Allison (jra@samba.org) 2006 | |
8 | * Pavel Shilovsky (pshilovsky@samba.org) 2012 | |
9 | * | |
10 | * This library is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU Lesser General Public License as published | |
12 | * by the Free Software Foundation; either version 2.1 of the License, or | |
13 | * (at your option) any later version. | |
14 | * | |
15 | * This library is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | |
18 | * the GNU Lesser General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU Lesser General Public License | |
21 | * along with this library; if not, write to the Free Software | |
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
23 | */ | |
24 | ||
25 | #include <linux/fs.h> | |
26 | #include <linux/list.h> | |
27 | #include <linux/wait.h> | |
28 | #include <linux/net.h> | |
29 | #include <linux/delay.h> | |
30 | #include <linux/uaccess.h> | |
31 | #include <asm/processor.h> | |
32 | #include <linux/mempool.h> | |
fb308a6f | 33 | #include <linux/highmem.h> |
026e93dc | 34 | #include <crypto/aead.h> |
2dc7e1c0 PS |
35 | #include "smb2pdu.h" |
36 | #include "cifsglob.h" | |
37 | #include "cifsproto.h" | |
38 | #include "smb2proto.h" | |
39 | #include "cifs_debug.h" | |
40 | #include "smb2status.h" | |
3c1bf7e4 PS |
41 | #include "smb2glob.h" |
42 | ||
95dc8dd1 SF |
43 | static int |
44 | smb2_crypto_shash_allocate(struct TCP_Server_Info *server) | |
45 | { | |
82fb82be AA |
46 | return cifs_alloc_hash("hmac(sha256)", |
47 | &server->secmech.hmacsha256, | |
48 | &server->secmech.sdeschmacsha256); | |
95dc8dd1 SF |
49 | } |
50 | ||
51 | static int | |
52 | smb3_crypto_shash_allocate(struct TCP_Server_Info *server) | |
53 | { | |
82fb82be | 54 | struct cifs_secmech *p = &server->secmech; |
95dc8dd1 SF |
55 | int rc; |
56 | ||
82fb82be AA |
57 | rc = cifs_alloc_hash("hmac(sha256)", |
58 | &p->hmacsha256, | |
59 | &p->sdeschmacsha256); | |
95dc8dd1 | 60 | if (rc) |
82fb82be | 61 | goto err; |
95dc8dd1 | 62 | |
82fb82be AA |
63 | rc = cifs_alloc_hash("cmac(aes)", &p->cmacaes, &p->sdesccmacaes); |
64 | if (rc) | |
65 | goto err; | |
95dc8dd1 SF |
66 | |
67 | return 0; | |
82fb82be AA |
68 | err: |
69 | cifs_free_hash(&p->hmacsha256, &p->sdeschmacsha256); | |
70 | return rc; | |
95dc8dd1 SF |
71 | } |
72 | ||
5fcd7f3f AA |
73 | int |
74 | smb311_crypto_shash_allocate(struct TCP_Server_Info *server) | |
75 | { | |
76 | struct cifs_secmech *p = &server->secmech; | |
77 | int rc = 0; | |
78 | ||
79 | rc = cifs_alloc_hash("hmac(sha256)", | |
80 | &p->hmacsha256, | |
81 | &p->sdeschmacsha256); | |
82 | if (rc) | |
83 | return rc; | |
84 | ||
85 | rc = cifs_alloc_hash("cmac(aes)", &p->cmacaes, &p->sdesccmacaes); | |
86 | if (rc) | |
87 | goto err; | |
88 | ||
89 | rc = cifs_alloc_hash("sha512", &p->sha512, &p->sdescsha512); | |
90 | if (rc) | |
91 | goto err; | |
92 | ||
93 | return 0; | |
94 | ||
95 | err: | |
96 | cifs_free_hash(&p->cmacaes, &p->sdesccmacaes); | |
97 | cifs_free_hash(&p->hmacsha256, &p->sdeschmacsha256); | |
98 | return rc; | |
99 | } | |
5fcd7f3f | 100 | |
38bd4906 SP |
101 | static struct cifs_ses * |
102 | smb2_find_smb_ses_unlocked(struct TCP_Server_Info *server, __u64 ses_id) | |
32811d24 SP |
103 | { |
104 | struct cifs_ses *ses; | |
105 | ||
32811d24 | 106 | list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { |
026e93dc | 107 | if (ses->Suid != ses_id) |
32811d24 | 108 | continue; |
32811d24 SP |
109 | return ses; |
110 | } | |
38bd4906 SP |
111 | |
112 | return NULL; | |
113 | } | |
114 | ||
115 | struct cifs_ses * | |
116 | smb2_find_smb_ses(struct TCP_Server_Info *server, __u64 ses_id) | |
117 | { | |
118 | struct cifs_ses *ses; | |
119 | ||
120 | spin_lock(&cifs_tcp_ses_lock); | |
121 | ses = smb2_find_smb_ses_unlocked(server, ses_id); | |
32811d24 SP |
122 | spin_unlock(&cifs_tcp_ses_lock); |
123 | ||
38bd4906 SP |
124 | return ses; |
125 | } | |
126 | ||
127 | static struct cifs_tcon * | |
128 | smb2_find_smb_sess_tcon_unlocked(struct cifs_ses *ses, __u32 tid) | |
129 | { | |
130 | struct cifs_tcon *tcon; | |
131 | ||
132 | list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { | |
133 | if (tcon->tid != tid) | |
134 | continue; | |
135 | ++tcon->tc_count; | |
136 | return tcon; | |
137 | } | |
138 | ||
32811d24 SP |
139 | return NULL; |
140 | } | |
141 | ||
38bd4906 SP |
142 | /* |
143 | * Obtain tcon corresponding to the tid in the given | |
144 | * cifs_ses | |
145 | */ | |
146 | ||
147 | struct cifs_tcon * | |
148 | smb2_find_smb_tcon(struct TCP_Server_Info *server, __u64 ses_id, __u32 tid) | |
149 | { | |
150 | struct cifs_ses *ses; | |
151 | struct cifs_tcon *tcon; | |
152 | ||
153 | spin_lock(&cifs_tcp_ses_lock); | |
154 | ses = smb2_find_smb_ses_unlocked(server, ses_id); | |
155 | if (!ses) { | |
156 | spin_unlock(&cifs_tcp_ses_lock); | |
157 | return NULL; | |
158 | } | |
159 | tcon = smb2_find_smb_sess_tcon_unlocked(ses, tid); | |
160 | spin_unlock(&cifs_tcp_ses_lock); | |
161 | ||
162 | return tcon; | |
163 | } | |
164 | ||
38107d45 | 165 | int |
0b688cfc | 166 | smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) |
3c1bf7e4 | 167 | { |
16c568ef | 168 | int rc; |
3c1bf7e4 PS |
169 | unsigned char smb2_signature[SMB2_HMACSHA256_SIZE]; |
170 | unsigned char *sigptr = smb2_signature; | |
0b688cfc | 171 | struct kvec *iov = rqst->rq_iov; |
c713c877 | 172 | struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[0].iov_base; |
32811d24 | 173 | struct cifs_ses *ses; |
a5c62f48 | 174 | struct shash_desc *shash; |
8de8c460 | 175 | struct smb_rqst drqst; |
32811d24 | 176 | |
026e93dc | 177 | ses = smb2_find_smb_ses(server, shdr->SessionId); |
32811d24 | 178 | if (!ses) { |
afe6f653 | 179 | cifs_server_dbg(VFS, "%s: Could not find session\n", __func__); |
32811d24 SP |
180 | return 0; |
181 | } | |
3c1bf7e4 PS |
182 | |
183 | memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE); | |
31473fc4 | 184 | memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE); |
3c1bf7e4 | 185 | |
95dc8dd1 SF |
186 | rc = smb2_crypto_shash_allocate(server); |
187 | if (rc) { | |
afe6f653 | 188 | cifs_server_dbg(VFS, "%s: sha256 alloc failed\n", __func__); |
95dc8dd1 SF |
189 | return rc; |
190 | } | |
191 | ||
3c1bf7e4 | 192 | rc = crypto_shash_setkey(server->secmech.hmacsha256, |
8de8c460 | 193 | ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE); |
3c1bf7e4 | 194 | if (rc) { |
afe6f653 | 195 | cifs_server_dbg(VFS, "%s: Could not update with response\n", __func__); |
3c1bf7e4 PS |
196 | return rc; |
197 | } | |
198 | ||
a5c62f48 | 199 | shash = &server->secmech.sdeschmacsha256->shash; |
8de8c460 | 200 | rc = crypto_shash_init(shash); |
3c1bf7e4 | 201 | if (rc) { |
afe6f653 | 202 | cifs_server_dbg(VFS, "%s: Could not init sha256", __func__); |
3c1bf7e4 PS |
203 | return rc; |
204 | } | |
205 | ||
8de8c460 PA |
206 | /* |
207 | * For SMB2+, __cifs_calc_signature() expects to sign only the actual | |
208 | * data, that is, iov[0] should not contain a rfc1002 length. | |
209 | * | |
210 | * Sign the rfc1002 length prior to passing the data (iov[1-N]) down to | |
211 | * __cifs_calc_signature(). | |
212 | */ | |
213 | drqst = *rqst; | |
214 | if (drqst.rq_nvec >= 2 && iov[0].iov_len == 4) { | |
215 | rc = crypto_shash_update(shash, iov[0].iov_base, | |
216 | iov[0].iov_len); | |
217 | if (rc) { | |
afe6f653 | 218 | cifs_server_dbg(VFS, "%s: Could not update with payload\n", |
8de8c460 PA |
219 | __func__); |
220 | return rc; | |
221 | } | |
222 | drqst.rq_iov++; | |
223 | drqst.rq_nvec--; | |
224 | } | |
3c1bf7e4 | 225 | |
8de8c460 | 226 | rc = __cifs_calc_signature(&drqst, server, sigptr, shash); |
16c568ef | 227 | if (!rc) |
31473fc4 | 228 | memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE); |
3c1bf7e4 PS |
229 | |
230 | return rc; | |
231 | } | |
232 | ||
373512ec SF |
233 | static int generate_key(struct cifs_ses *ses, struct kvec label, |
234 | struct kvec context, __u8 *key, unsigned int key_size) | |
429b46f4 SF |
235 | { |
236 | unsigned char zero = 0x0; | |
237 | __u8 i[4] = {0, 0, 0, 1}; | |
238 | __u8 L[4] = {0, 0, 0, 128}; | |
239 | int rc = 0; | |
240 | unsigned char prfhash[SMB2_HMACSHA256_SIZE]; | |
241 | unsigned char *hashptr = prfhash; | |
afe6f653 | 242 | struct TCP_Server_Info *server = ses->server; |
429b46f4 SF |
243 | |
244 | memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE); | |
373512ec | 245 | memset(key, 0x0, key_size); |
429b46f4 | 246 | |
afe6f653 | 247 | rc = smb3_crypto_shash_allocate(server); |
95dc8dd1 | 248 | if (rc) { |
afe6f653 | 249 | cifs_server_dbg(VFS, "%s: crypto alloc failed\n", __func__); |
95dc8dd1 SF |
250 | goto smb3signkey_ret; |
251 | } | |
252 | ||
afe6f653 | 253 | rc = crypto_shash_setkey(server->secmech.hmacsha256, |
32811d24 | 254 | ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE); |
429b46f4 | 255 | if (rc) { |
afe6f653 | 256 | cifs_server_dbg(VFS, "%s: Could not set with session key\n", __func__); |
429b46f4 SF |
257 | goto smb3signkey_ret; |
258 | } | |
259 | ||
afe6f653 | 260 | rc = crypto_shash_init(&server->secmech.sdeschmacsha256->shash); |
429b46f4 | 261 | if (rc) { |
afe6f653 | 262 | cifs_server_dbg(VFS, "%s: Could not init sign hmac\n", __func__); |
429b46f4 SF |
263 | goto smb3signkey_ret; |
264 | } | |
265 | ||
afe6f653 | 266 | rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash, |
429b46f4 SF |
267 | i, 4); |
268 | if (rc) { | |
afe6f653 | 269 | cifs_server_dbg(VFS, "%s: Could not update with n\n", __func__); |
429b46f4 SF |
270 | goto smb3signkey_ret; |
271 | } | |
272 | ||
afe6f653 | 273 | rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash, |
373512ec | 274 | label.iov_base, label.iov_len); |
429b46f4 | 275 | if (rc) { |
afe6f653 | 276 | cifs_server_dbg(VFS, "%s: Could not update with label\n", __func__); |
429b46f4 SF |
277 | goto smb3signkey_ret; |
278 | } | |
279 | ||
afe6f653 | 280 | rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash, |
429b46f4 SF |
281 | &zero, 1); |
282 | if (rc) { | |
afe6f653 | 283 | cifs_server_dbg(VFS, "%s: Could not update with zero\n", __func__); |
429b46f4 SF |
284 | goto smb3signkey_ret; |
285 | } | |
286 | ||
afe6f653 | 287 | rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash, |
373512ec | 288 | context.iov_base, context.iov_len); |
429b46f4 | 289 | if (rc) { |
afe6f653 | 290 | cifs_server_dbg(VFS, "%s: Could not update with context\n", __func__); |
429b46f4 SF |
291 | goto smb3signkey_ret; |
292 | } | |
293 | ||
afe6f653 | 294 | rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash, |
429b46f4 SF |
295 | L, 4); |
296 | if (rc) { | |
afe6f653 | 297 | cifs_server_dbg(VFS, "%s: Could not update with L\n", __func__); |
429b46f4 SF |
298 | goto smb3signkey_ret; |
299 | } | |
300 | ||
afe6f653 | 301 | rc = crypto_shash_final(&server->secmech.sdeschmacsha256->shash, |
429b46f4 SF |
302 | hashptr); |
303 | if (rc) { | |
afe6f653 | 304 | cifs_server_dbg(VFS, "%s: Could not generate sha256 hash\n", __func__); |
429b46f4 SF |
305 | goto smb3signkey_ret; |
306 | } | |
307 | ||
373512ec | 308 | memcpy(key, hashptr, key_size); |
429b46f4 SF |
309 | |
310 | smb3signkey_ret: | |
32811d24 | 311 | return rc; |
429b46f4 SF |
312 | } |
313 | ||
373512ec SF |
314 | struct derivation { |
315 | struct kvec label; | |
316 | struct kvec context; | |
317 | }; | |
318 | ||
319 | struct derivation_triplet { | |
320 | struct derivation signing; | |
321 | struct derivation encryption; | |
322 | struct derivation decryption; | |
323 | }; | |
324 | ||
325 | static int | |
326 | generate_smb3signingkey(struct cifs_ses *ses, | |
327 | const struct derivation_triplet *ptriplet) | |
328 | { | |
329 | int rc; | |
330 | ||
331 | rc = generate_key(ses, ptriplet->signing.label, | |
332 | ptriplet->signing.context, ses->smb3signingkey, | |
333 | SMB3_SIGN_KEY_SIZE); | |
334 | if (rc) | |
335 | return rc; | |
336 | ||
337 | rc = generate_key(ses, ptriplet->encryption.label, | |
338 | ptriplet->encryption.context, ses->smb3encryptionkey, | |
339 | SMB3_SIGN_KEY_SIZE); | |
340 | if (rc) | |
341 | return rc; | |
342 | ||
d38de3c6 AA |
343 | rc = generate_key(ses, ptriplet->decryption.label, |
344 | ptriplet->decryption.context, | |
345 | ses->smb3decryptionkey, SMB3_SIGN_KEY_SIZE); | |
346 | ||
347 | if (rc) | |
348 | return rc; | |
349 | ||
350 | #ifdef CONFIG_CIFS_DEBUG_DUMP_KEYS | |
351 | cifs_dbg(VFS, "%s: dumping generated AES session keys\n", __func__); | |
352 | /* | |
353 | * The session id is opaque in terms of endianness, so we can't | |
354 | * print it as a long long. we dump it as we got it on the wire | |
355 | */ | |
356 | cifs_dbg(VFS, "Session Id %*ph\n", (int)sizeof(ses->Suid), | |
357 | &ses->Suid); | |
358 | cifs_dbg(VFS, "Session Key %*ph\n", | |
359 | SMB2_NTLMV2_SESSKEY_SIZE, ses->auth_key.response); | |
360 | cifs_dbg(VFS, "Signing Key %*ph\n", | |
361 | SMB3_SIGN_KEY_SIZE, ses->smb3signingkey); | |
362 | cifs_dbg(VFS, "ServerIn Key %*ph\n", | |
363 | SMB3_SIGN_KEY_SIZE, ses->smb3encryptionkey); | |
364 | cifs_dbg(VFS, "ServerOut Key %*ph\n", | |
365 | SMB3_SIGN_KEY_SIZE, ses->smb3decryptionkey); | |
366 | #endif | |
367 | return rc; | |
373512ec SF |
368 | } |
369 | ||
370 | int | |
371 | generate_smb30signingkey(struct cifs_ses *ses) | |
372 | ||
373 | { | |
374 | struct derivation_triplet triplet; | |
375 | struct derivation *d; | |
376 | ||
377 | d = &triplet.signing; | |
378 | d->label.iov_base = "SMB2AESCMAC"; | |
379 | d->label.iov_len = 12; | |
380 | d->context.iov_base = "SmbSign"; | |
381 | d->context.iov_len = 8; | |
382 | ||
383 | d = &triplet.encryption; | |
384 | d->label.iov_base = "SMB2AESCCM"; | |
385 | d->label.iov_len = 11; | |
386 | d->context.iov_base = "ServerIn "; | |
387 | d->context.iov_len = 10; | |
388 | ||
389 | d = &triplet.decryption; | |
390 | d->label.iov_base = "SMB2AESCCM"; | |
391 | d->label.iov_len = 11; | |
392 | d->context.iov_base = "ServerOut"; | |
393 | d->context.iov_len = 10; | |
394 | ||
395 | return generate_smb3signingkey(ses, &triplet); | |
396 | } | |
397 | ||
398 | int | |
399 | generate_smb311signingkey(struct cifs_ses *ses) | |
400 | ||
401 | { | |
402 | struct derivation_triplet triplet; | |
403 | struct derivation *d; | |
404 | ||
405 | d = &triplet.signing; | |
06e22908 SF |
406 | d->label.iov_base = "SMBSigningKey"; |
407 | d->label.iov_len = 14; | |
408 | d->context.iov_base = ses->preauth_sha_hash; | |
409 | d->context.iov_len = 64; | |
373512ec SF |
410 | |
411 | d = &triplet.encryption; | |
06e22908 SF |
412 | d->label.iov_base = "SMBC2SCipherKey"; |
413 | d->label.iov_len = 16; | |
414 | d->context.iov_base = ses->preauth_sha_hash; | |
415 | d->context.iov_len = 64; | |
373512ec SF |
416 | |
417 | d = &triplet.decryption; | |
06e22908 SF |
418 | d->label.iov_base = "SMBS2CCipherKey"; |
419 | d->label.iov_len = 16; | |
420 | d->context.iov_base = ses->preauth_sha_hash; | |
421 | d->context.iov_len = 64; | |
373512ec SF |
422 | |
423 | return generate_smb3signingkey(ses, &triplet); | |
424 | } | |
425 | ||
38107d45 SF |
426 | int |
427 | smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) | |
428 | { | |
27c32b49 | 429 | int rc; |
429b46f4 SF |
430 | unsigned char smb3_signature[SMB2_CMACAES_SIZE]; |
431 | unsigned char *sigptr = smb3_signature; | |
432 | struct kvec *iov = rqst->rq_iov; | |
c713c877 | 433 | struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[0].iov_base; |
32811d24 | 434 | struct cifs_ses *ses; |
27c32b49 PA |
435 | struct shash_desc *shash = &server->secmech.sdesccmacaes->shash; |
436 | struct smb_rqst drqst; | |
32811d24 | 437 | |
026e93dc | 438 | ses = smb2_find_smb_ses(server, shdr->SessionId); |
32811d24 | 439 | if (!ses) { |
afe6f653 | 440 | cifs_server_dbg(VFS, "%s: Could not find session\n", __func__); |
32811d24 SP |
441 | return 0; |
442 | } | |
429b46f4 SF |
443 | |
444 | memset(smb3_signature, 0x0, SMB2_CMACAES_SIZE); | |
31473fc4 | 445 | memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE); |
429b46f4 SF |
446 | |
447 | rc = crypto_shash_setkey(server->secmech.cmacaes, | |
27c32b49 | 448 | ses->smb3signingkey, SMB2_CMACAES_SIZE); |
429b46f4 | 449 | if (rc) { |
afe6f653 | 450 | cifs_server_dbg(VFS, "%s: Could not set key for cmac aes\n", __func__); |
429b46f4 SF |
451 | return rc; |
452 | } | |
453 | ||
95dc8dd1 SF |
454 | /* |
455 | * we already allocate sdesccmacaes when we init smb3 signing key, | |
456 | * so unlike smb2 case we do not have to check here if secmech are | |
457 | * initialized | |
458 | */ | |
27c32b49 | 459 | rc = crypto_shash_init(shash); |
429b46f4 | 460 | if (rc) { |
afe6f653 | 461 | cifs_server_dbg(VFS, "%s: Could not init cmac aes\n", __func__); |
429b46f4 SF |
462 | return rc; |
463 | } | |
82fb82be | 464 | |
27c32b49 PA |
465 | /* |
466 | * For SMB2+, __cifs_calc_signature() expects to sign only the actual | |
467 | * data, that is, iov[0] should not contain a rfc1002 length. | |
468 | * | |
469 | * Sign the rfc1002 length prior to passing the data (iov[1-N]) down to | |
470 | * __cifs_calc_signature(). | |
471 | */ | |
472 | drqst = *rqst; | |
473 | if (drqst.rq_nvec >= 2 && iov[0].iov_len == 4) { | |
474 | rc = crypto_shash_update(shash, iov[0].iov_base, | |
475 | iov[0].iov_len); | |
476 | if (rc) { | |
afe6f653 | 477 | cifs_server_dbg(VFS, "%s: Could not update with payload\n", |
27c32b49 PA |
478 | __func__); |
479 | return rc; | |
480 | } | |
481 | drqst.rq_iov++; | |
482 | drqst.rq_nvec--; | |
483 | } | |
429b46f4 | 484 | |
27c32b49 | 485 | rc = __cifs_calc_signature(&drqst, server, sigptr, shash); |
16c568ef | 486 | if (!rc) |
31473fc4 | 487 | memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE); |
429b46f4 SF |
488 | |
489 | return rc; | |
38107d45 SF |
490 | } |
491 | ||
3c1bf7e4 PS |
492 | /* must be called with server->srv_mutex held */ |
493 | static int | |
0b688cfc | 494 | smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server) |
3c1bf7e4 PS |
495 | { |
496 | int rc = 0; | |
738f9de5 | 497 | struct smb2_sync_hdr *shdr = |
c713c877 | 498 | (struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base; |
3c1bf7e4 | 499 | |
31473fc4 | 500 | if (!(shdr->Flags & SMB2_FLAGS_SIGNED) || |
3c1bf7e4 PS |
501 | server->tcpStatus == CifsNeedNegotiate) |
502 | return rc; | |
503 | ||
504 | if (!server->session_estab) { | |
31473fc4 | 505 | strncpy(shdr->Signature, "BSRSPYL", 8); |
3c1bf7e4 PS |
506 | return rc; |
507 | } | |
508 | ||
38107d45 | 509 | rc = server->ops->calc_signature(rqst, server); |
3c1bf7e4 PS |
510 | |
511 | return rc; | |
512 | } | |
513 | ||
514 | int | |
0b688cfc | 515 | smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) |
3c1bf7e4 PS |
516 | { |
517 | unsigned int rc; | |
518 | char server_response_sig[16]; | |
738f9de5 | 519 | struct smb2_sync_hdr *shdr = |
977b6170 | 520 | (struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base; |
3c1bf7e4 | 521 | |
31473fc4 PS |
522 | if ((shdr->Command == SMB2_NEGOTIATE) || |
523 | (shdr->Command == SMB2_SESSION_SETUP) || | |
524 | (shdr->Command == SMB2_OPLOCK_BREAK) || | |
4f5c10f1 | 525 | server->ignore_signature || |
3c1bf7e4 PS |
526 | (!server->session_estab)) |
527 | return 0; | |
528 | ||
529 | /* | |
530 | * BB what if signatures are supposed to be on for session but | |
531 | * server does not send one? BB | |
532 | */ | |
533 | ||
534 | /* Do not need to verify session setups with signature "BSRSPYL " */ | |
31473fc4 | 535 | if (memcmp(shdr->Signature, "BSRSPYL ", 8) == 0) |
f96637be | 536 | cifs_dbg(FYI, "dummy signature received for smb command 0x%x\n", |
31473fc4 | 537 | shdr->Command); |
3c1bf7e4 PS |
538 | |
539 | /* | |
540 | * Save off the origiginal signature so we can modify the smb and check | |
541 | * our calculated signature against what the server sent. | |
542 | */ | |
31473fc4 | 543 | memcpy(server_response_sig, shdr->Signature, SMB2_SIGNATURE_SIZE); |
3c1bf7e4 | 544 | |
31473fc4 | 545 | memset(shdr->Signature, 0, SMB2_SIGNATURE_SIZE); |
3c1bf7e4 PS |
546 | |
547 | mutex_lock(&server->srv_mutex); | |
38107d45 | 548 | rc = server->ops->calc_signature(rqst, server); |
3c1bf7e4 PS |
549 | mutex_unlock(&server->srv_mutex); |
550 | ||
551 | if (rc) | |
552 | return rc; | |
553 | ||
31473fc4 | 554 | if (memcmp(server_response_sig, shdr->Signature, SMB2_SIGNATURE_SIZE)) |
3c1bf7e4 PS |
555 | return -EACCES; |
556 | else | |
557 | return 0; | |
558 | } | |
559 | ||
2dc7e1c0 PS |
560 | /* |
561 | * Set message id for the request. Should be called after wait_for_free_request | |
562 | * and when srv_mutex is held. | |
563 | */ | |
564 | static inline void | |
31473fc4 PS |
565 | smb2_seq_num_into_buf(struct TCP_Server_Info *server, |
566 | struct smb2_sync_hdr *shdr) | |
2dc7e1c0 | 567 | { |
31473fc4 | 568 | unsigned int i, num = le16_to_cpu(shdr->CreditCharge); |
cb7e9eab | 569 | |
31473fc4 | 570 | shdr->MessageId = get_next_mid64(server); |
cb7e9eab PS |
571 | /* skip message numbers according to CreditCharge field */ |
572 | for (i = 1; i < num; i++) | |
573 | get_next_mid(server); | |
2dc7e1c0 PS |
574 | } |
575 | ||
576 | static struct mid_q_entry * | |
31473fc4 | 577 | smb2_mid_entry_alloc(const struct smb2_sync_hdr *shdr, |
2dc7e1c0 PS |
578 | struct TCP_Server_Info *server) |
579 | { | |
580 | struct mid_q_entry *temp; | |
c781af7e | 581 | unsigned int credits = le16_to_cpu(shdr->CreditCharge); |
2dc7e1c0 PS |
582 | |
583 | if (server == NULL) { | |
f96637be | 584 | cifs_dbg(VFS, "Null TCP session in smb2_mid_entry_alloc\n"); |
2dc7e1c0 PS |
585 | return NULL; |
586 | } | |
587 | ||
588 | temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS); | |
a6f74e80 | 589 | memset(temp, 0, sizeof(struct mid_q_entry)); |
696e420b | 590 | kref_init(&temp->refcount); |
a6f74e80 | 591 | temp->mid = le64_to_cpu(shdr->MessageId); |
c781af7e | 592 | temp->credits = credits > 0 ? credits : 1; |
a6f74e80 N |
593 | temp->pid = current->pid; |
594 | temp->command = shdr->Command; /* Always LE */ | |
595 | temp->when_alloc = jiffies; | |
596 | temp->server = server; | |
597 | ||
598 | /* | |
599 | * The default is for the mid to be synchronous, so the | |
600 | * default callback just wakes up the current task. | |
601 | */ | |
602 | temp->callback = cifs_wake_up_task; | |
603 | temp->callback_data = current; | |
2dc7e1c0 PS |
604 | |
605 | atomic_inc(&midCount); | |
606 | temp->mid_state = MID_REQUEST_ALLOCATED; | |
53a3e0d9 SF |
607 | trace_smb3_cmd_enter(shdr->TreeId, shdr->SessionId, |
608 | le16_to_cpu(shdr->Command), temp->mid); | |
2dc7e1c0 PS |
609 | return temp; |
610 | } | |
611 | ||
612 | static int | |
31473fc4 | 613 | smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_sync_hdr *shdr, |
2dc7e1c0 PS |
614 | struct mid_q_entry **mid) |
615 | { | |
616 | if (ses->server->tcpStatus == CifsExiting) | |
617 | return -ENOENT; | |
618 | ||
619 | if (ses->server->tcpStatus == CifsNeedReconnect) { | |
f96637be | 620 | cifs_dbg(FYI, "tcp session dead - return to caller to retry\n"); |
2dc7e1c0 PS |
621 | return -EAGAIN; |
622 | } | |
623 | ||
2084ed57 PS |
624 | if (ses->server->tcpStatus == CifsNeedNegotiate && |
625 | shdr->Command != SMB2_NEGOTIATE) | |
626 | return -EAGAIN; | |
627 | ||
7f48558e | 628 | if (ses->status == CifsNew) { |
31473fc4 PS |
629 | if ((shdr->Command != SMB2_SESSION_SETUP) && |
630 | (shdr->Command != SMB2_NEGOTIATE)) | |
2dc7e1c0 PS |
631 | return -EAGAIN; |
632 | /* else ok - we are setting up session */ | |
633 | } | |
7f48558e SP |
634 | |
635 | if (ses->status == CifsExiting) { | |
31473fc4 | 636 | if (shdr->Command != SMB2_LOGOFF) |
7f48558e SP |
637 | return -EAGAIN; |
638 | /* else ok - we are shutting down the session */ | |
639 | } | |
640 | ||
31473fc4 | 641 | *mid = smb2_mid_entry_alloc(shdr, ses->server); |
2dc7e1c0 PS |
642 | if (*mid == NULL) |
643 | return -ENOMEM; | |
644 | spin_lock(&GlobalMid_Lock); | |
645 | list_add_tail(&(*mid)->qhead, &ses->server->pending_mid_q); | |
646 | spin_unlock(&GlobalMid_Lock); | |
53a3e0d9 | 647 | |
2dc7e1c0 PS |
648 | return 0; |
649 | } | |
650 | ||
651 | int | |
652 | smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server, | |
653 | bool log_error) | |
654 | { | |
e19b2bc0 | 655 | unsigned int len = mid->resp_buf_size; |
977b6170 | 656 | struct kvec iov[1]; |
738f9de5 | 657 | struct smb_rqst rqst = { .rq_iov = iov, |
977b6170 | 658 | .rq_nvec = 1 }; |
0b688cfc | 659 | |
738f9de5 | 660 | iov[0].iov_base = (char *)mid->resp_buf; |
977b6170 | 661 | iov[0].iov_len = len; |
2dc7e1c0 PS |
662 | |
663 | dump_smb(mid->resp_buf, min_t(u32, 80, len)); | |
664 | /* convert the length into a more usable form */ | |
4326ed2f | 665 | if (len > 24 && server->sign && !mid->decrypted) { |
3c1bf7e4 PS |
666 | int rc; |
667 | ||
0b688cfc | 668 | rc = smb2_verify_signature(&rqst, server); |
3c1bf7e4 | 669 | if (rc) |
afe6f653 | 670 | cifs_server_dbg(VFS, "SMB signature verification returned error = %d\n", |
f96637be | 671 | rc); |
3c1bf7e4 | 672 | } |
2dc7e1c0 PS |
673 | |
674 | return map_smb2_to_linux_error(mid->resp_buf, log_error); | |
675 | } | |
676 | ||
fec344e3 JL |
677 | struct mid_q_entry * |
678 | smb2_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst) | |
2dc7e1c0 PS |
679 | { |
680 | int rc; | |
738f9de5 | 681 | struct smb2_sync_hdr *shdr = |
c713c877 | 682 | (struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base; |
2dc7e1c0 PS |
683 | struct mid_q_entry *mid; |
684 | ||
31473fc4 | 685 | smb2_seq_num_into_buf(ses->server, shdr); |
2dc7e1c0 | 686 | |
31473fc4 | 687 | rc = smb2_get_mid_entry(ses, shdr, &mid); |
c781af7e PS |
688 | if (rc) { |
689 | revert_current_mid_from_hdr(ses->server, shdr); | |
fec344e3 | 690 | return ERR_PTR(rc); |
c781af7e PS |
691 | } |
692 | ||
fec344e3 JL |
693 | rc = smb2_sign_rqst(rqst, ses->server); |
694 | if (rc) { | |
c781af7e | 695 | revert_current_mid_from_hdr(ses->server, shdr); |
3c1bf7e4 | 696 | cifs_delete_mid(mid); |
fec344e3 JL |
697 | return ERR_PTR(rc); |
698 | } | |
c781af7e | 699 | |
fec344e3 | 700 | return mid; |
2dc7e1c0 PS |
701 | } |
702 | ||
fec344e3 JL |
703 | struct mid_q_entry * |
704 | smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst) | |
c95b8eed | 705 | { |
fec344e3 | 706 | int rc; |
738f9de5 | 707 | struct smb2_sync_hdr *shdr = |
c713c877 | 708 | (struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base; |
c95b8eed PS |
709 | struct mid_q_entry *mid; |
710 | ||
2084ed57 PS |
711 | if (server->tcpStatus == CifsNeedNegotiate && |
712 | shdr->Command != SMB2_NEGOTIATE) | |
713 | return ERR_PTR(-EAGAIN); | |
714 | ||
31473fc4 | 715 | smb2_seq_num_into_buf(server, shdr); |
c95b8eed | 716 | |
31473fc4 | 717 | mid = smb2_mid_entry_alloc(shdr, server); |
c781af7e PS |
718 | if (mid == NULL) { |
719 | revert_current_mid_from_hdr(server, shdr); | |
fec344e3 | 720 | return ERR_PTR(-ENOMEM); |
c781af7e | 721 | } |
c95b8eed | 722 | |
fec344e3 | 723 | rc = smb2_sign_rqst(rqst, server); |
c95b8eed | 724 | if (rc) { |
c781af7e | 725 | revert_current_mid_from_hdr(server, shdr); |
c95b8eed | 726 | DeleteMidQEntry(mid); |
fec344e3 | 727 | return ERR_PTR(rc); |
3c1bf7e4 PS |
728 | } |
729 | ||
fec344e3 | 730 | return mid; |
c95b8eed | 731 | } |
026e93dc PS |
732 | |
733 | int | |
734 | smb3_crypto_aead_allocate(struct TCP_Server_Info *server) | |
735 | { | |
736 | struct crypto_aead *tfm; | |
737 | ||
738 | if (!server->secmech.ccmaesencrypt) { | |
2b2f7548 SF |
739 | if (server->cipher_type == SMB2_ENCRYPTION_AES128_GCM) |
740 | tfm = crypto_alloc_aead("gcm(aes)", 0, 0); | |
741 | else | |
742 | tfm = crypto_alloc_aead("ccm(aes)", 0, 0); | |
026e93dc | 743 | if (IS_ERR(tfm)) { |
afe6f653 | 744 | cifs_server_dbg(VFS, "%s: Failed to alloc encrypt aead\n", |
026e93dc PS |
745 | __func__); |
746 | return PTR_ERR(tfm); | |
747 | } | |
748 | server->secmech.ccmaesencrypt = tfm; | |
749 | } | |
750 | ||
751 | if (!server->secmech.ccmaesdecrypt) { | |
2b2f7548 SF |
752 | if (server->cipher_type == SMB2_ENCRYPTION_AES128_GCM) |
753 | tfm = crypto_alloc_aead("gcm(aes)", 0, 0); | |
754 | else | |
755 | tfm = crypto_alloc_aead("ccm(aes)", 0, 0); | |
026e93dc PS |
756 | if (IS_ERR(tfm)) { |
757 | crypto_free_aead(server->secmech.ccmaesencrypt); | |
758 | server->secmech.ccmaesencrypt = NULL; | |
afe6f653 | 759 | cifs_server_dbg(VFS, "%s: Failed to alloc decrypt aead\n", |
026e93dc PS |
760 | __func__); |
761 | return PTR_ERR(tfm); | |
762 | } | |
763 | server->secmech.ccmaesdecrypt = tfm; | |
764 | } | |
765 | ||
766 | return 0; | |
767 | } |