]>
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 | #ifdef CONFIG_CIFS_SMB311 |
74 | int | |
75 | smb311_crypto_shash_allocate(struct TCP_Server_Info *server) | |
76 | { | |
77 | struct cifs_secmech *p = &server->secmech; | |
78 | int rc = 0; | |
79 | ||
80 | rc = cifs_alloc_hash("hmac(sha256)", | |
81 | &p->hmacsha256, | |
82 | &p->sdeschmacsha256); | |
83 | if (rc) | |
84 | return rc; | |
85 | ||
86 | rc = cifs_alloc_hash("cmac(aes)", &p->cmacaes, &p->sdesccmacaes); | |
87 | if (rc) | |
88 | goto err; | |
89 | ||
90 | rc = cifs_alloc_hash("sha512", &p->sha512, &p->sdescsha512); | |
91 | if (rc) | |
92 | goto err; | |
93 | ||
94 | return 0; | |
95 | ||
96 | err: | |
97 | cifs_free_hash(&p->cmacaes, &p->sdesccmacaes); | |
98 | cifs_free_hash(&p->hmacsha256, &p->sdeschmacsha256); | |
99 | return rc; | |
100 | } | |
101 | #endif | |
102 | ||
38bd4906 SP |
103 | static struct cifs_ses * |
104 | smb2_find_smb_ses_unlocked(struct TCP_Server_Info *server, __u64 ses_id) | |
32811d24 SP |
105 | { |
106 | struct cifs_ses *ses; | |
107 | ||
32811d24 | 108 | list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { |
026e93dc | 109 | if (ses->Suid != ses_id) |
32811d24 | 110 | continue; |
32811d24 SP |
111 | return ses; |
112 | } | |
38bd4906 SP |
113 | |
114 | return NULL; | |
115 | } | |
116 | ||
117 | struct cifs_ses * | |
118 | smb2_find_smb_ses(struct TCP_Server_Info *server, __u64 ses_id) | |
119 | { | |
120 | struct cifs_ses *ses; | |
121 | ||
122 | spin_lock(&cifs_tcp_ses_lock); | |
123 | ses = smb2_find_smb_ses_unlocked(server, ses_id); | |
32811d24 SP |
124 | spin_unlock(&cifs_tcp_ses_lock); |
125 | ||
38bd4906 SP |
126 | return ses; |
127 | } | |
128 | ||
129 | static struct cifs_tcon * | |
130 | smb2_find_smb_sess_tcon_unlocked(struct cifs_ses *ses, __u32 tid) | |
131 | { | |
132 | struct cifs_tcon *tcon; | |
133 | ||
134 | list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { | |
135 | if (tcon->tid != tid) | |
136 | continue; | |
137 | ++tcon->tc_count; | |
138 | return tcon; | |
139 | } | |
140 | ||
32811d24 SP |
141 | return NULL; |
142 | } | |
143 | ||
38bd4906 SP |
144 | /* |
145 | * Obtain tcon corresponding to the tid in the given | |
146 | * cifs_ses | |
147 | */ | |
148 | ||
149 | struct cifs_tcon * | |
150 | smb2_find_smb_tcon(struct TCP_Server_Info *server, __u64 ses_id, __u32 tid) | |
151 | { | |
152 | struct cifs_ses *ses; | |
153 | struct cifs_tcon *tcon; | |
154 | ||
155 | spin_lock(&cifs_tcp_ses_lock); | |
156 | ses = smb2_find_smb_ses_unlocked(server, ses_id); | |
157 | if (!ses) { | |
158 | spin_unlock(&cifs_tcp_ses_lock); | |
159 | return NULL; | |
160 | } | |
161 | tcon = smb2_find_smb_sess_tcon_unlocked(ses, tid); | |
162 | spin_unlock(&cifs_tcp_ses_lock); | |
163 | ||
164 | return tcon; | |
165 | } | |
166 | ||
38107d45 | 167 | int |
0b688cfc | 168 | smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) |
3c1bf7e4 | 169 | { |
16c568ef | 170 | int rc; |
3c1bf7e4 PS |
171 | unsigned char smb2_signature[SMB2_HMACSHA256_SIZE]; |
172 | unsigned char *sigptr = smb2_signature; | |
0b688cfc | 173 | struct kvec *iov = rqst->rq_iov; |
738f9de5 | 174 | struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[1].iov_base; |
32811d24 SP |
175 | struct cifs_ses *ses; |
176 | ||
026e93dc | 177 | ses = smb2_find_smb_ses(server, shdr->SessionId); |
32811d24 SP |
178 | if (!ses) { |
179 | cifs_dbg(VFS, "%s: Could not find session\n", __func__); | |
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) { | |
188 | cifs_dbg(VFS, "%s: shah256 alloc failed\n", __func__); | |
189 | return rc; | |
190 | } | |
191 | ||
3c1bf7e4 | 192 | rc = crypto_shash_setkey(server->secmech.hmacsha256, |
32811d24 | 193 | ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE); |
3c1bf7e4 | 194 | if (rc) { |
f96637be | 195 | cifs_dbg(VFS, "%s: Could not update with response\n", __func__); |
3c1bf7e4 PS |
196 | return rc; |
197 | } | |
198 | ||
199 | rc = crypto_shash_init(&server->secmech.sdeschmacsha256->shash); | |
200 | if (rc) { | |
95dc8dd1 | 201 | cifs_dbg(VFS, "%s: Could not init sha256", __func__); |
3c1bf7e4 PS |
202 | return rc; |
203 | } | |
204 | ||
16c568ef AV |
205 | rc = __cifs_calc_signature(rqst, server, sigptr, |
206 | &server->secmech.sdeschmacsha256->shash); | |
3c1bf7e4 | 207 | |
16c568ef | 208 | if (!rc) |
31473fc4 | 209 | memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE); |
3c1bf7e4 PS |
210 | |
211 | return rc; | |
212 | } | |
213 | ||
373512ec SF |
214 | static int generate_key(struct cifs_ses *ses, struct kvec label, |
215 | struct kvec context, __u8 *key, unsigned int key_size) | |
429b46f4 SF |
216 | { |
217 | unsigned char zero = 0x0; | |
218 | __u8 i[4] = {0, 0, 0, 1}; | |
219 | __u8 L[4] = {0, 0, 0, 128}; | |
220 | int rc = 0; | |
221 | unsigned char prfhash[SMB2_HMACSHA256_SIZE]; | |
222 | unsigned char *hashptr = prfhash; | |
223 | ||
224 | memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE); | |
373512ec | 225 | memset(key, 0x0, key_size); |
429b46f4 | 226 | |
32811d24 | 227 | rc = smb3_crypto_shash_allocate(ses->server); |
95dc8dd1 SF |
228 | if (rc) { |
229 | cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__); | |
230 | goto smb3signkey_ret; | |
231 | } | |
232 | ||
32811d24 SP |
233 | rc = crypto_shash_setkey(ses->server->secmech.hmacsha256, |
234 | ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE); | |
429b46f4 SF |
235 | if (rc) { |
236 | cifs_dbg(VFS, "%s: Could not set with session key\n", __func__); | |
237 | goto smb3signkey_ret; | |
238 | } | |
239 | ||
32811d24 | 240 | rc = crypto_shash_init(&ses->server->secmech.sdeschmacsha256->shash); |
429b46f4 SF |
241 | if (rc) { |
242 | cifs_dbg(VFS, "%s: Could not init sign hmac\n", __func__); | |
243 | goto smb3signkey_ret; | |
244 | } | |
245 | ||
32811d24 | 246 | rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash, |
429b46f4 SF |
247 | i, 4); |
248 | if (rc) { | |
249 | cifs_dbg(VFS, "%s: Could not update with n\n", __func__); | |
250 | goto smb3signkey_ret; | |
251 | } | |
252 | ||
32811d24 | 253 | rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash, |
373512ec | 254 | label.iov_base, label.iov_len); |
429b46f4 SF |
255 | if (rc) { |
256 | cifs_dbg(VFS, "%s: Could not update with label\n", __func__); | |
257 | goto smb3signkey_ret; | |
258 | } | |
259 | ||
32811d24 | 260 | rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash, |
429b46f4 SF |
261 | &zero, 1); |
262 | if (rc) { | |
263 | cifs_dbg(VFS, "%s: Could not update with zero\n", __func__); | |
264 | goto smb3signkey_ret; | |
265 | } | |
266 | ||
32811d24 | 267 | rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash, |
373512ec | 268 | context.iov_base, context.iov_len); |
429b46f4 SF |
269 | if (rc) { |
270 | cifs_dbg(VFS, "%s: Could not update with context\n", __func__); | |
271 | goto smb3signkey_ret; | |
272 | } | |
273 | ||
32811d24 | 274 | rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash, |
429b46f4 SF |
275 | L, 4); |
276 | if (rc) { | |
277 | cifs_dbg(VFS, "%s: Could not update with L\n", __func__); | |
278 | goto smb3signkey_ret; | |
279 | } | |
280 | ||
32811d24 | 281 | rc = crypto_shash_final(&ses->server->secmech.sdeschmacsha256->shash, |
429b46f4 SF |
282 | hashptr); |
283 | if (rc) { | |
284 | cifs_dbg(VFS, "%s: Could not generate sha256 hash\n", __func__); | |
285 | goto smb3signkey_ret; | |
286 | } | |
287 | ||
373512ec | 288 | memcpy(key, hashptr, key_size); |
429b46f4 SF |
289 | |
290 | smb3signkey_ret: | |
32811d24 | 291 | return rc; |
429b46f4 SF |
292 | } |
293 | ||
373512ec SF |
294 | struct derivation { |
295 | struct kvec label; | |
296 | struct kvec context; | |
297 | }; | |
298 | ||
299 | struct derivation_triplet { | |
300 | struct derivation signing; | |
301 | struct derivation encryption; | |
302 | struct derivation decryption; | |
303 | }; | |
304 | ||
305 | static int | |
306 | generate_smb3signingkey(struct cifs_ses *ses, | |
307 | const struct derivation_triplet *ptriplet) | |
308 | { | |
309 | int rc; | |
310 | ||
311 | rc = generate_key(ses, ptriplet->signing.label, | |
312 | ptriplet->signing.context, ses->smb3signingkey, | |
313 | SMB3_SIGN_KEY_SIZE); | |
314 | if (rc) | |
315 | return rc; | |
316 | ||
317 | rc = generate_key(ses, ptriplet->encryption.label, | |
318 | ptriplet->encryption.context, ses->smb3encryptionkey, | |
319 | SMB3_SIGN_KEY_SIZE); | |
320 | if (rc) | |
321 | return rc; | |
322 | ||
d38de3c6 AA |
323 | rc = generate_key(ses, ptriplet->decryption.label, |
324 | ptriplet->decryption.context, | |
325 | ses->smb3decryptionkey, SMB3_SIGN_KEY_SIZE); | |
326 | ||
327 | if (rc) | |
328 | return rc; | |
329 | ||
330 | #ifdef CONFIG_CIFS_DEBUG_DUMP_KEYS | |
331 | cifs_dbg(VFS, "%s: dumping generated AES session keys\n", __func__); | |
332 | /* | |
333 | * The session id is opaque in terms of endianness, so we can't | |
334 | * print it as a long long. we dump it as we got it on the wire | |
335 | */ | |
336 | cifs_dbg(VFS, "Session Id %*ph\n", (int)sizeof(ses->Suid), | |
337 | &ses->Suid); | |
338 | cifs_dbg(VFS, "Session Key %*ph\n", | |
339 | SMB2_NTLMV2_SESSKEY_SIZE, ses->auth_key.response); | |
340 | cifs_dbg(VFS, "Signing Key %*ph\n", | |
341 | SMB3_SIGN_KEY_SIZE, ses->smb3signingkey); | |
342 | cifs_dbg(VFS, "ServerIn Key %*ph\n", | |
343 | SMB3_SIGN_KEY_SIZE, ses->smb3encryptionkey); | |
344 | cifs_dbg(VFS, "ServerOut Key %*ph\n", | |
345 | SMB3_SIGN_KEY_SIZE, ses->smb3decryptionkey); | |
346 | #endif | |
347 | return rc; | |
373512ec SF |
348 | } |
349 | ||
350 | int | |
351 | generate_smb30signingkey(struct cifs_ses *ses) | |
352 | ||
353 | { | |
354 | struct derivation_triplet triplet; | |
355 | struct derivation *d; | |
356 | ||
357 | d = &triplet.signing; | |
358 | d->label.iov_base = "SMB2AESCMAC"; | |
359 | d->label.iov_len = 12; | |
360 | d->context.iov_base = "SmbSign"; | |
361 | d->context.iov_len = 8; | |
362 | ||
363 | d = &triplet.encryption; | |
364 | d->label.iov_base = "SMB2AESCCM"; | |
365 | d->label.iov_len = 11; | |
366 | d->context.iov_base = "ServerIn "; | |
367 | d->context.iov_len = 10; | |
368 | ||
369 | d = &triplet.decryption; | |
370 | d->label.iov_base = "SMB2AESCCM"; | |
371 | d->label.iov_len = 11; | |
372 | d->context.iov_base = "ServerOut"; | |
373 | d->context.iov_len = 10; | |
374 | ||
375 | return generate_smb3signingkey(ses, &triplet); | |
376 | } | |
377 | ||
06e22908 | 378 | #ifdef CONFIG_CIFS_SMB311 |
373512ec SF |
379 | int |
380 | generate_smb311signingkey(struct cifs_ses *ses) | |
381 | ||
382 | { | |
383 | struct derivation_triplet triplet; | |
384 | struct derivation *d; | |
385 | ||
386 | d = &triplet.signing; | |
06e22908 SF |
387 | d->label.iov_base = "SMBSigningKey"; |
388 | d->label.iov_len = 14; | |
389 | d->context.iov_base = ses->preauth_sha_hash; | |
390 | d->context.iov_len = 64; | |
373512ec SF |
391 | |
392 | d = &triplet.encryption; | |
06e22908 SF |
393 | d->label.iov_base = "SMBC2SCipherKey"; |
394 | d->label.iov_len = 16; | |
395 | d->context.iov_base = ses->preauth_sha_hash; | |
396 | d->context.iov_len = 64; | |
373512ec SF |
397 | |
398 | d = &triplet.decryption; | |
06e22908 SF |
399 | d->label.iov_base = "SMBS2CCipherKey"; |
400 | d->label.iov_len = 16; | |
401 | d->context.iov_base = ses->preauth_sha_hash; | |
402 | d->context.iov_len = 64; | |
373512ec SF |
403 | |
404 | return generate_smb3signingkey(ses, &triplet); | |
405 | } | |
06e22908 | 406 | #endif /* 311 */ |
373512ec | 407 | |
38107d45 SF |
408 | int |
409 | smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) | |
410 | { | |
32811d24 | 411 | int rc = 0; |
429b46f4 SF |
412 | unsigned char smb3_signature[SMB2_CMACAES_SIZE]; |
413 | unsigned char *sigptr = smb3_signature; | |
414 | struct kvec *iov = rqst->rq_iov; | |
738f9de5 | 415 | struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[1].iov_base; |
32811d24 SP |
416 | struct cifs_ses *ses; |
417 | ||
026e93dc | 418 | ses = smb2_find_smb_ses(server, shdr->SessionId); |
32811d24 SP |
419 | if (!ses) { |
420 | cifs_dbg(VFS, "%s: Could not find session\n", __func__); | |
421 | return 0; | |
422 | } | |
429b46f4 SF |
423 | |
424 | memset(smb3_signature, 0x0, SMB2_CMACAES_SIZE); | |
31473fc4 | 425 | memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE); |
429b46f4 SF |
426 | |
427 | rc = crypto_shash_setkey(server->secmech.cmacaes, | |
32811d24 SP |
428 | ses->smb3signingkey, SMB2_CMACAES_SIZE); |
429 | ||
429b46f4 SF |
430 | if (rc) { |
431 | cifs_dbg(VFS, "%s: Could not set key for cmac aes\n", __func__); | |
432 | return rc; | |
433 | } | |
434 | ||
95dc8dd1 SF |
435 | /* |
436 | * we already allocate sdesccmacaes when we init smb3 signing key, | |
437 | * so unlike smb2 case we do not have to check here if secmech are | |
438 | * initialized | |
439 | */ | |
429b46f4 SF |
440 | rc = crypto_shash_init(&server->secmech.sdesccmacaes->shash); |
441 | if (rc) { | |
442 | cifs_dbg(VFS, "%s: Could not init cmac aes\n", __func__); | |
443 | return rc; | |
444 | } | |
82fb82be | 445 | |
16c568ef AV |
446 | rc = __cifs_calc_signature(rqst, server, sigptr, |
447 | &server->secmech.sdesccmacaes->shash); | |
429b46f4 | 448 | |
16c568ef | 449 | if (!rc) |
31473fc4 | 450 | memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE); |
429b46f4 SF |
451 | |
452 | return rc; | |
38107d45 SF |
453 | } |
454 | ||
3c1bf7e4 PS |
455 | /* must be called with server->srv_mutex held */ |
456 | static int | |
0b688cfc | 457 | smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server) |
3c1bf7e4 PS |
458 | { |
459 | int rc = 0; | |
738f9de5 PS |
460 | struct smb2_sync_hdr *shdr = |
461 | (struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base; | |
3c1bf7e4 | 462 | |
31473fc4 | 463 | if (!(shdr->Flags & SMB2_FLAGS_SIGNED) || |
3c1bf7e4 PS |
464 | server->tcpStatus == CifsNeedNegotiate) |
465 | return rc; | |
466 | ||
467 | if (!server->session_estab) { | |
31473fc4 | 468 | strncpy(shdr->Signature, "BSRSPYL", 8); |
3c1bf7e4 PS |
469 | return rc; |
470 | } | |
471 | ||
38107d45 | 472 | rc = server->ops->calc_signature(rqst, server); |
3c1bf7e4 PS |
473 | |
474 | return rc; | |
475 | } | |
476 | ||
477 | int | |
0b688cfc | 478 | smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) |
3c1bf7e4 PS |
479 | { |
480 | unsigned int rc; | |
481 | char server_response_sig[16]; | |
738f9de5 PS |
482 | struct smb2_sync_hdr *shdr = |
483 | (struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base; | |
3c1bf7e4 | 484 | |
31473fc4 PS |
485 | if ((shdr->Command == SMB2_NEGOTIATE) || |
486 | (shdr->Command == SMB2_SESSION_SETUP) || | |
487 | (shdr->Command == SMB2_OPLOCK_BREAK) || | |
3c1bf7e4 PS |
488 | (!server->session_estab)) |
489 | return 0; | |
490 | ||
491 | /* | |
492 | * BB what if signatures are supposed to be on for session but | |
493 | * server does not send one? BB | |
494 | */ | |
495 | ||
496 | /* Do not need to verify session setups with signature "BSRSPYL " */ | |
31473fc4 | 497 | if (memcmp(shdr->Signature, "BSRSPYL ", 8) == 0) |
f96637be | 498 | cifs_dbg(FYI, "dummy signature received for smb command 0x%x\n", |
31473fc4 | 499 | shdr->Command); |
3c1bf7e4 PS |
500 | |
501 | /* | |
502 | * Save off the origiginal signature so we can modify the smb and check | |
503 | * our calculated signature against what the server sent. | |
504 | */ | |
31473fc4 | 505 | memcpy(server_response_sig, shdr->Signature, SMB2_SIGNATURE_SIZE); |
3c1bf7e4 | 506 | |
31473fc4 | 507 | memset(shdr->Signature, 0, SMB2_SIGNATURE_SIZE); |
3c1bf7e4 PS |
508 | |
509 | mutex_lock(&server->srv_mutex); | |
38107d45 | 510 | rc = server->ops->calc_signature(rqst, server); |
3c1bf7e4 PS |
511 | mutex_unlock(&server->srv_mutex); |
512 | ||
513 | if (rc) | |
514 | return rc; | |
515 | ||
31473fc4 | 516 | if (memcmp(server_response_sig, shdr->Signature, SMB2_SIGNATURE_SIZE)) |
3c1bf7e4 PS |
517 | return -EACCES; |
518 | else | |
519 | return 0; | |
520 | } | |
521 | ||
2dc7e1c0 PS |
522 | /* |
523 | * Set message id for the request. Should be called after wait_for_free_request | |
524 | * and when srv_mutex is held. | |
525 | */ | |
526 | static inline void | |
31473fc4 PS |
527 | smb2_seq_num_into_buf(struct TCP_Server_Info *server, |
528 | struct smb2_sync_hdr *shdr) | |
2dc7e1c0 | 529 | { |
31473fc4 | 530 | unsigned int i, num = le16_to_cpu(shdr->CreditCharge); |
cb7e9eab | 531 | |
31473fc4 | 532 | shdr->MessageId = get_next_mid64(server); |
cb7e9eab PS |
533 | /* skip message numbers according to CreditCharge field */ |
534 | for (i = 1; i < num; i++) | |
535 | get_next_mid(server); | |
2dc7e1c0 PS |
536 | } |
537 | ||
538 | static struct mid_q_entry * | |
31473fc4 | 539 | smb2_mid_entry_alloc(const struct smb2_sync_hdr *shdr, |
2dc7e1c0 PS |
540 | struct TCP_Server_Info *server) |
541 | { | |
542 | struct mid_q_entry *temp; | |
543 | ||
544 | if (server == NULL) { | |
f96637be | 545 | cifs_dbg(VFS, "Null TCP session in smb2_mid_entry_alloc\n"); |
2dc7e1c0 PS |
546 | return NULL; |
547 | } | |
548 | ||
549 | temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS); | |
a6f74e80 N |
550 | memset(temp, 0, sizeof(struct mid_q_entry)); |
551 | temp->mid = le64_to_cpu(shdr->MessageId); | |
552 | temp->pid = current->pid; | |
553 | temp->command = shdr->Command; /* Always LE */ | |
554 | temp->when_alloc = jiffies; | |
555 | temp->server = server; | |
556 | ||
557 | /* | |
558 | * The default is for the mid to be synchronous, so the | |
559 | * default callback just wakes up the current task. | |
560 | */ | |
561 | temp->callback = cifs_wake_up_task; | |
562 | temp->callback_data = current; | |
2dc7e1c0 PS |
563 | |
564 | atomic_inc(&midCount); | |
565 | temp->mid_state = MID_REQUEST_ALLOCATED; | |
566 | return temp; | |
567 | } | |
568 | ||
569 | static int | |
31473fc4 | 570 | smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_sync_hdr *shdr, |
2dc7e1c0 PS |
571 | struct mid_q_entry **mid) |
572 | { | |
573 | if (ses->server->tcpStatus == CifsExiting) | |
574 | return -ENOENT; | |
575 | ||
576 | if (ses->server->tcpStatus == CifsNeedReconnect) { | |
f96637be | 577 | cifs_dbg(FYI, "tcp session dead - return to caller to retry\n"); |
2dc7e1c0 PS |
578 | return -EAGAIN; |
579 | } | |
580 | ||
7f48558e | 581 | if (ses->status == CifsNew) { |
31473fc4 PS |
582 | if ((shdr->Command != SMB2_SESSION_SETUP) && |
583 | (shdr->Command != SMB2_NEGOTIATE)) | |
2dc7e1c0 PS |
584 | return -EAGAIN; |
585 | /* else ok - we are setting up session */ | |
586 | } | |
7f48558e SP |
587 | |
588 | if (ses->status == CifsExiting) { | |
31473fc4 | 589 | if (shdr->Command != SMB2_LOGOFF) |
7f48558e SP |
590 | return -EAGAIN; |
591 | /* else ok - we are shutting down the session */ | |
592 | } | |
593 | ||
31473fc4 | 594 | *mid = smb2_mid_entry_alloc(shdr, ses->server); |
2dc7e1c0 PS |
595 | if (*mid == NULL) |
596 | return -ENOMEM; | |
597 | spin_lock(&GlobalMid_Lock); | |
598 | list_add_tail(&(*mid)->qhead, &ses->server->pending_mid_q); | |
599 | spin_unlock(&GlobalMid_Lock); | |
600 | return 0; | |
601 | } | |
602 | ||
603 | int | |
604 | smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server, | |
605 | bool log_error) | |
606 | { | |
e19b2bc0 | 607 | unsigned int len = mid->resp_buf_size; |
738f9de5 PS |
608 | struct kvec iov[2]; |
609 | struct smb_rqst rqst = { .rq_iov = iov, | |
610 | .rq_nvec = 2 }; | |
0b688cfc | 611 | |
738f9de5 PS |
612 | iov[0].iov_base = (char *)mid->resp_buf; |
613 | iov[0].iov_len = 4; | |
614 | iov[1].iov_base = (char *)mid->resp_buf + 4; | |
615 | iov[1].iov_len = len; | |
2dc7e1c0 PS |
616 | |
617 | dump_smb(mid->resp_buf, min_t(u32, 80, len)); | |
618 | /* convert the length into a more usable form */ | |
4326ed2f | 619 | if (len > 24 && server->sign && !mid->decrypted) { |
3c1bf7e4 PS |
620 | int rc; |
621 | ||
0b688cfc | 622 | rc = smb2_verify_signature(&rqst, server); |
3c1bf7e4 | 623 | if (rc) |
f96637be JP |
624 | cifs_dbg(VFS, "SMB signature verification returned error = %d\n", |
625 | rc); | |
3c1bf7e4 | 626 | } |
2dc7e1c0 PS |
627 | |
628 | return map_smb2_to_linux_error(mid->resp_buf, log_error); | |
629 | } | |
630 | ||
fec344e3 JL |
631 | struct mid_q_entry * |
632 | smb2_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst) | |
2dc7e1c0 PS |
633 | { |
634 | int rc; | |
738f9de5 PS |
635 | struct smb2_sync_hdr *shdr = |
636 | (struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base; | |
2dc7e1c0 PS |
637 | struct mid_q_entry *mid; |
638 | ||
31473fc4 | 639 | smb2_seq_num_into_buf(ses->server, shdr); |
2dc7e1c0 | 640 | |
31473fc4 | 641 | rc = smb2_get_mid_entry(ses, shdr, &mid); |
2dc7e1c0 | 642 | if (rc) |
fec344e3 JL |
643 | return ERR_PTR(rc); |
644 | rc = smb2_sign_rqst(rqst, ses->server); | |
645 | if (rc) { | |
3c1bf7e4 | 646 | cifs_delete_mid(mid); |
fec344e3 JL |
647 | return ERR_PTR(rc); |
648 | } | |
649 | return mid; | |
2dc7e1c0 PS |
650 | } |
651 | ||
fec344e3 JL |
652 | struct mid_q_entry * |
653 | smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst) | |
c95b8eed | 654 | { |
fec344e3 | 655 | int rc; |
738f9de5 PS |
656 | struct smb2_sync_hdr *shdr = |
657 | (struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base; | |
c95b8eed PS |
658 | struct mid_q_entry *mid; |
659 | ||
31473fc4 | 660 | smb2_seq_num_into_buf(server, shdr); |
c95b8eed | 661 | |
31473fc4 | 662 | mid = smb2_mid_entry_alloc(shdr, server); |
c95b8eed | 663 | if (mid == NULL) |
fec344e3 | 664 | return ERR_PTR(-ENOMEM); |
c95b8eed | 665 | |
fec344e3 | 666 | rc = smb2_sign_rqst(rqst, server); |
c95b8eed PS |
667 | if (rc) { |
668 | DeleteMidQEntry(mid); | |
fec344e3 | 669 | return ERR_PTR(rc); |
3c1bf7e4 PS |
670 | } |
671 | ||
fec344e3 | 672 | return mid; |
c95b8eed | 673 | } |
026e93dc PS |
674 | |
675 | int | |
676 | smb3_crypto_aead_allocate(struct TCP_Server_Info *server) | |
677 | { | |
678 | struct crypto_aead *tfm; | |
679 | ||
680 | if (!server->secmech.ccmaesencrypt) { | |
681 | tfm = crypto_alloc_aead("ccm(aes)", 0, 0); | |
682 | if (IS_ERR(tfm)) { | |
683 | cifs_dbg(VFS, "%s: Failed to alloc encrypt aead\n", | |
684 | __func__); | |
685 | return PTR_ERR(tfm); | |
686 | } | |
687 | server->secmech.ccmaesencrypt = tfm; | |
688 | } | |
689 | ||
690 | if (!server->secmech.ccmaesdecrypt) { | |
691 | tfm = crypto_alloc_aead("ccm(aes)", 0, 0); | |
692 | if (IS_ERR(tfm)) { | |
693 | crypto_free_aead(server->secmech.ccmaesencrypt); | |
694 | server->secmech.ccmaesencrypt = NULL; | |
695 | cifs_dbg(VFS, "%s: Failed to alloc decrypt aead\n", | |
696 | __func__); | |
697 | return PTR_ERR(tfm); | |
698 | } | |
699 | server->secmech.ccmaesdecrypt = tfm; | |
700 | } | |
701 | ||
702 | return 0; | |
703 | } |