]>
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 ([email protected]) | |
7 | * Jeremy Allison ([email protected]) 2006 | |
8 | * Pavel Shilovsky ([email protected]) 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 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) { | |
a5c62f48 | 188 | cifs_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) { |
f96637be | 195 | cifs_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) { |
95dc8dd1 | 202 | cifs_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) { | |
218 | cifs_dbg(VFS, "%s: Could not update with payload\n", | |
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; | |
242 | ||
243 | memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE); | |
373512ec | 244 | memset(key, 0x0, key_size); |
429b46f4 | 245 | |
32811d24 | 246 | rc = smb3_crypto_shash_allocate(ses->server); |
95dc8dd1 SF |
247 | if (rc) { |
248 | cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__); | |
249 | goto smb3signkey_ret; | |
250 | } | |
251 | ||
32811d24 SP |
252 | rc = crypto_shash_setkey(ses->server->secmech.hmacsha256, |
253 | ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE); | |
429b46f4 SF |
254 | if (rc) { |
255 | cifs_dbg(VFS, "%s: Could not set with session key\n", __func__); | |
256 | goto smb3signkey_ret; | |
257 | } | |
258 | ||
32811d24 | 259 | rc = crypto_shash_init(&ses->server->secmech.sdeschmacsha256->shash); |
429b46f4 SF |
260 | if (rc) { |
261 | cifs_dbg(VFS, "%s: Could not init sign hmac\n", __func__); | |
262 | goto smb3signkey_ret; | |
263 | } | |
264 | ||
32811d24 | 265 | rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash, |
429b46f4 SF |
266 | i, 4); |
267 | if (rc) { | |
268 | cifs_dbg(VFS, "%s: Could not update with n\n", __func__); | |
269 | goto smb3signkey_ret; | |
270 | } | |
271 | ||
32811d24 | 272 | rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash, |
373512ec | 273 | label.iov_base, label.iov_len); |
429b46f4 SF |
274 | if (rc) { |
275 | cifs_dbg(VFS, "%s: Could not update with label\n", __func__); | |
276 | goto smb3signkey_ret; | |
277 | } | |
278 | ||
32811d24 | 279 | rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash, |
429b46f4 SF |
280 | &zero, 1); |
281 | if (rc) { | |
282 | cifs_dbg(VFS, "%s: Could not update with zero\n", __func__); | |
283 | goto smb3signkey_ret; | |
284 | } | |
285 | ||
32811d24 | 286 | rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash, |
373512ec | 287 | context.iov_base, context.iov_len); |
429b46f4 SF |
288 | if (rc) { |
289 | cifs_dbg(VFS, "%s: Could not update with context\n", __func__); | |
290 | goto smb3signkey_ret; | |
291 | } | |
292 | ||
32811d24 | 293 | rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash, |
429b46f4 SF |
294 | L, 4); |
295 | if (rc) { | |
296 | cifs_dbg(VFS, "%s: Could not update with L\n", __func__); | |
297 | goto smb3signkey_ret; | |
298 | } | |
299 | ||
32811d24 | 300 | rc = crypto_shash_final(&ses->server->secmech.sdeschmacsha256->shash, |
429b46f4 SF |
301 | hashptr); |
302 | if (rc) { | |
303 | cifs_dbg(VFS, "%s: Could not generate sha256 hash\n", __func__); | |
304 | goto smb3signkey_ret; | |
305 | } | |
306 | ||
373512ec | 307 | memcpy(key, hashptr, key_size); |
429b46f4 SF |
308 | |
309 | smb3signkey_ret: | |
32811d24 | 310 | return rc; |
429b46f4 SF |
311 | } |
312 | ||
373512ec SF |
313 | struct derivation { |
314 | struct kvec label; | |
315 | struct kvec context; | |
316 | }; | |
317 | ||
318 | struct derivation_triplet { | |
319 | struct derivation signing; | |
320 | struct derivation encryption; | |
321 | struct derivation decryption; | |
322 | }; | |
323 | ||
324 | static int | |
325 | generate_smb3signingkey(struct cifs_ses *ses, | |
326 | const struct derivation_triplet *ptriplet) | |
327 | { | |
328 | int rc; | |
329 | ||
330 | rc = generate_key(ses, ptriplet->signing.label, | |
331 | ptriplet->signing.context, ses->smb3signingkey, | |
332 | SMB3_SIGN_KEY_SIZE); | |
333 | if (rc) | |
334 | return rc; | |
335 | ||
336 | rc = generate_key(ses, ptriplet->encryption.label, | |
337 | ptriplet->encryption.context, ses->smb3encryptionkey, | |
338 | SMB3_SIGN_KEY_SIZE); | |
339 | if (rc) | |
340 | return rc; | |
341 | ||
d38de3c6 AA |
342 | rc = generate_key(ses, ptriplet->decryption.label, |
343 | ptriplet->decryption.context, | |
344 | ses->smb3decryptionkey, SMB3_SIGN_KEY_SIZE); | |
345 | ||
346 | if (rc) | |
347 | return rc; | |
348 | ||
349 | #ifdef CONFIG_CIFS_DEBUG_DUMP_KEYS | |
350 | cifs_dbg(VFS, "%s: dumping generated AES session keys\n", __func__); | |
351 | /* | |
352 | * The session id is opaque in terms of endianness, so we can't | |
353 | * print it as a long long. we dump it as we got it on the wire | |
354 | */ | |
355 | cifs_dbg(VFS, "Session Id %*ph\n", (int)sizeof(ses->Suid), | |
356 | &ses->Suid); | |
357 | cifs_dbg(VFS, "Session Key %*ph\n", | |
358 | SMB2_NTLMV2_SESSKEY_SIZE, ses->auth_key.response); | |
359 | cifs_dbg(VFS, "Signing Key %*ph\n", | |
360 | SMB3_SIGN_KEY_SIZE, ses->smb3signingkey); | |
361 | cifs_dbg(VFS, "ServerIn Key %*ph\n", | |
362 | SMB3_SIGN_KEY_SIZE, ses->smb3encryptionkey); | |
363 | cifs_dbg(VFS, "ServerOut Key %*ph\n", | |
364 | SMB3_SIGN_KEY_SIZE, ses->smb3decryptionkey); | |
365 | #endif | |
366 | return rc; | |
373512ec SF |
367 | } |
368 | ||
369 | int | |
370 | generate_smb30signingkey(struct cifs_ses *ses) | |
371 | ||
372 | { | |
373 | struct derivation_triplet triplet; | |
374 | struct derivation *d; | |
375 | ||
376 | d = &triplet.signing; | |
377 | d->label.iov_base = "SMB2AESCMAC"; | |
378 | d->label.iov_len = 12; | |
379 | d->context.iov_base = "SmbSign"; | |
380 | d->context.iov_len = 8; | |
381 | ||
382 | d = &triplet.encryption; | |
383 | d->label.iov_base = "SMB2AESCCM"; | |
384 | d->label.iov_len = 11; | |
385 | d->context.iov_base = "ServerIn "; | |
386 | d->context.iov_len = 10; | |
387 | ||
388 | d = &triplet.decryption; | |
389 | d->label.iov_base = "SMB2AESCCM"; | |
390 | d->label.iov_len = 11; | |
391 | d->context.iov_base = "ServerOut"; | |
392 | d->context.iov_len = 10; | |
393 | ||
394 | return generate_smb3signingkey(ses, &triplet); | |
395 | } | |
396 | ||
397 | int | |
398 | generate_smb311signingkey(struct cifs_ses *ses) | |
399 | ||
400 | { | |
401 | struct derivation_triplet triplet; | |
402 | struct derivation *d; | |
403 | ||
404 | d = &triplet.signing; | |
06e22908 SF |
405 | d->label.iov_base = "SMBSigningKey"; |
406 | d->label.iov_len = 14; | |
407 | d->context.iov_base = ses->preauth_sha_hash; | |
408 | d->context.iov_len = 64; | |
373512ec SF |
409 | |
410 | d = &triplet.encryption; | |
06e22908 SF |
411 | d->label.iov_base = "SMBC2SCipherKey"; |
412 | d->label.iov_len = 16; | |
413 | d->context.iov_base = ses->preauth_sha_hash; | |
414 | d->context.iov_len = 64; | |
373512ec SF |
415 | |
416 | d = &triplet.decryption; | |
06e22908 SF |
417 | d->label.iov_base = "SMBS2CCipherKey"; |
418 | d->label.iov_len = 16; | |
419 | d->context.iov_base = ses->preauth_sha_hash; | |
420 | d->context.iov_len = 64; | |
373512ec SF |
421 | |
422 | return generate_smb3signingkey(ses, &triplet); | |
423 | } | |
424 | ||
38107d45 SF |
425 | int |
426 | smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) | |
427 | { | |
27c32b49 | 428 | int rc; |
429b46f4 SF |
429 | unsigned char smb3_signature[SMB2_CMACAES_SIZE]; |
430 | unsigned char *sigptr = smb3_signature; | |
431 | struct kvec *iov = rqst->rq_iov; | |
c713c877 | 432 | struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[0].iov_base; |
32811d24 | 433 | struct cifs_ses *ses; |
27c32b49 PA |
434 | struct shash_desc *shash = &server->secmech.sdesccmacaes->shash; |
435 | struct smb_rqst drqst; | |
32811d24 | 436 | |
026e93dc | 437 | ses = smb2_find_smb_ses(server, shdr->SessionId); |
32811d24 SP |
438 | if (!ses) { |
439 | cifs_dbg(VFS, "%s: Could not find session\n", __func__); | |
440 | return 0; | |
441 | } | |
429b46f4 SF |
442 | |
443 | memset(smb3_signature, 0x0, SMB2_CMACAES_SIZE); | |
31473fc4 | 444 | memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE); |
429b46f4 SF |
445 | |
446 | rc = crypto_shash_setkey(server->secmech.cmacaes, | |
27c32b49 | 447 | ses->smb3signingkey, SMB2_CMACAES_SIZE); |
429b46f4 SF |
448 | if (rc) { |
449 | cifs_dbg(VFS, "%s: Could not set key for cmac aes\n", __func__); | |
450 | return rc; | |
451 | } | |
452 | ||
95dc8dd1 SF |
453 | /* |
454 | * we already allocate sdesccmacaes when we init smb3 signing key, | |
455 | * so unlike smb2 case we do not have to check here if secmech are | |
456 | * initialized | |
457 | */ | |
27c32b49 | 458 | rc = crypto_shash_init(shash); |
429b46f4 SF |
459 | if (rc) { |
460 | cifs_dbg(VFS, "%s: Could not init cmac aes\n", __func__); | |
461 | return rc; | |
462 | } | |
82fb82be | 463 | |
27c32b49 PA |
464 | /* |
465 | * For SMB2+, __cifs_calc_signature() expects to sign only the actual | |
466 | * data, that is, iov[0] should not contain a rfc1002 length. | |
467 | * | |
468 | * Sign the rfc1002 length prior to passing the data (iov[1-N]) down to | |
469 | * __cifs_calc_signature(). | |
470 | */ | |
471 | drqst = *rqst; | |
472 | if (drqst.rq_nvec >= 2 && iov[0].iov_len == 4) { | |
473 | rc = crypto_shash_update(shash, iov[0].iov_base, | |
474 | iov[0].iov_len); | |
475 | if (rc) { | |
476 | cifs_dbg(VFS, "%s: Could not update with payload\n", | |
477 | __func__); | |
478 | return rc; | |
479 | } | |
480 | drqst.rq_iov++; | |
481 | drqst.rq_nvec--; | |
482 | } | |
429b46f4 | 483 | |
27c32b49 | 484 | rc = __cifs_calc_signature(&drqst, server, sigptr, shash); |
16c568ef | 485 | if (!rc) |
31473fc4 | 486 | memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE); |
429b46f4 SF |
487 | |
488 | return rc; | |
38107d45 SF |
489 | } |
490 | ||
3c1bf7e4 PS |
491 | /* must be called with server->srv_mutex held */ |
492 | static int | |
0b688cfc | 493 | smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server) |
3c1bf7e4 PS |
494 | { |
495 | int rc = 0; | |
738f9de5 | 496 | struct smb2_sync_hdr *shdr = |
c713c877 | 497 | (struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base; |
3c1bf7e4 | 498 | |
31473fc4 | 499 | if (!(shdr->Flags & SMB2_FLAGS_SIGNED) || |
3c1bf7e4 PS |
500 | server->tcpStatus == CifsNeedNegotiate) |
501 | return rc; | |
502 | ||
503 | if (!server->session_estab) { | |
31473fc4 | 504 | strncpy(shdr->Signature, "BSRSPYL", 8); |
3c1bf7e4 PS |
505 | return rc; |
506 | } | |
507 | ||
38107d45 | 508 | rc = server->ops->calc_signature(rqst, server); |
3c1bf7e4 PS |
509 | |
510 | return rc; | |
511 | } | |
512 | ||
513 | int | |
0b688cfc | 514 | smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) |
3c1bf7e4 PS |
515 | { |
516 | unsigned int rc; | |
517 | char server_response_sig[16]; | |
738f9de5 | 518 | struct smb2_sync_hdr *shdr = |
977b6170 | 519 | (struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base; |
3c1bf7e4 | 520 | |
31473fc4 PS |
521 | if ((shdr->Command == SMB2_NEGOTIATE) || |
522 | (shdr->Command == SMB2_SESSION_SETUP) || | |
523 | (shdr->Command == SMB2_OPLOCK_BREAK) || | |
3c1bf7e4 PS |
524 | (!server->session_estab)) |
525 | return 0; | |
526 | ||
527 | /* | |
528 | * BB what if signatures are supposed to be on for session but | |
529 | * server does not send one? BB | |
530 | */ | |
531 | ||
532 | /* Do not need to verify session setups with signature "BSRSPYL " */ | |
31473fc4 | 533 | if (memcmp(shdr->Signature, "BSRSPYL ", 8) == 0) |
f96637be | 534 | cifs_dbg(FYI, "dummy signature received for smb command 0x%x\n", |
31473fc4 | 535 | shdr->Command); |
3c1bf7e4 PS |
536 | |
537 | /* | |
538 | * Save off the origiginal signature so we can modify the smb and check | |
539 | * our calculated signature against what the server sent. | |
540 | */ | |
31473fc4 | 541 | memcpy(server_response_sig, shdr->Signature, SMB2_SIGNATURE_SIZE); |
3c1bf7e4 | 542 | |
31473fc4 | 543 | memset(shdr->Signature, 0, SMB2_SIGNATURE_SIZE); |
3c1bf7e4 PS |
544 | |
545 | mutex_lock(&server->srv_mutex); | |
38107d45 | 546 | rc = server->ops->calc_signature(rqst, server); |
3c1bf7e4 PS |
547 | mutex_unlock(&server->srv_mutex); |
548 | ||
549 | if (rc) | |
550 | return rc; | |
551 | ||
31473fc4 | 552 | if (memcmp(server_response_sig, shdr->Signature, SMB2_SIGNATURE_SIZE)) |
3c1bf7e4 PS |
553 | return -EACCES; |
554 | else | |
555 | return 0; | |
556 | } | |
557 | ||
2dc7e1c0 PS |
558 | /* |
559 | * Set message id for the request. Should be called after wait_for_free_request | |
560 | * and when srv_mutex is held. | |
561 | */ | |
562 | static inline void | |
31473fc4 PS |
563 | smb2_seq_num_into_buf(struct TCP_Server_Info *server, |
564 | struct smb2_sync_hdr *shdr) | |
2dc7e1c0 | 565 | { |
31473fc4 | 566 | unsigned int i, num = le16_to_cpu(shdr->CreditCharge); |
cb7e9eab | 567 | |
31473fc4 | 568 | shdr->MessageId = get_next_mid64(server); |
cb7e9eab PS |
569 | /* skip message numbers according to CreditCharge field */ |
570 | for (i = 1; i < num; i++) | |
571 | get_next_mid(server); | |
2dc7e1c0 PS |
572 | } |
573 | ||
574 | static struct mid_q_entry * | |
31473fc4 | 575 | smb2_mid_entry_alloc(const struct smb2_sync_hdr *shdr, |
2dc7e1c0 PS |
576 | struct TCP_Server_Info *server) |
577 | { | |
578 | struct mid_q_entry *temp; | |
c781af7e | 579 | unsigned int credits = le16_to_cpu(shdr->CreditCharge); |
2dc7e1c0 PS |
580 | |
581 | if (server == NULL) { | |
f96637be | 582 | cifs_dbg(VFS, "Null TCP session in smb2_mid_entry_alloc\n"); |
2dc7e1c0 PS |
583 | return NULL; |
584 | } | |
585 | ||
586 | temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS); | |
a6f74e80 | 587 | memset(temp, 0, sizeof(struct mid_q_entry)); |
696e420b | 588 | kref_init(&temp->refcount); |
a6f74e80 | 589 | temp->mid = le64_to_cpu(shdr->MessageId); |
c781af7e | 590 | temp->credits = credits > 0 ? credits : 1; |
a6f74e80 N |
591 | temp->pid = current->pid; |
592 | temp->command = shdr->Command; /* Always LE */ | |
593 | temp->when_alloc = jiffies; | |
594 | temp->server = server; | |
595 | ||
596 | /* | |
597 | * The default is for the mid to be synchronous, so the | |
598 | * default callback just wakes up the current task. | |
599 | */ | |
600 | temp->callback = cifs_wake_up_task; | |
601 | temp->callback_data = current; | |
2dc7e1c0 PS |
602 | |
603 | atomic_inc(&midCount); | |
604 | temp->mid_state = MID_REQUEST_ALLOCATED; | |
53a3e0d9 SF |
605 | trace_smb3_cmd_enter(shdr->TreeId, shdr->SessionId, |
606 | le16_to_cpu(shdr->Command), temp->mid); | |
2dc7e1c0 PS |
607 | return temp; |
608 | } | |
609 | ||
610 | static int | |
31473fc4 | 611 | smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_sync_hdr *shdr, |
2dc7e1c0 PS |
612 | struct mid_q_entry **mid) |
613 | { | |
614 | if (ses->server->tcpStatus == CifsExiting) | |
615 | return -ENOENT; | |
616 | ||
617 | if (ses->server->tcpStatus == CifsNeedReconnect) { | |
f96637be | 618 | cifs_dbg(FYI, "tcp session dead - return to caller to retry\n"); |
2dc7e1c0 PS |
619 | return -EAGAIN; |
620 | } | |
621 | ||
2084ed57 PS |
622 | if (ses->server->tcpStatus == CifsNeedNegotiate && |
623 | shdr->Command != SMB2_NEGOTIATE) | |
624 | return -EAGAIN; | |
625 | ||
7f48558e | 626 | if (ses->status == CifsNew) { |
31473fc4 PS |
627 | if ((shdr->Command != SMB2_SESSION_SETUP) && |
628 | (shdr->Command != SMB2_NEGOTIATE)) | |
2dc7e1c0 PS |
629 | return -EAGAIN; |
630 | /* else ok - we are setting up session */ | |
631 | } | |
7f48558e SP |
632 | |
633 | if (ses->status == CifsExiting) { | |
31473fc4 | 634 | if (shdr->Command != SMB2_LOGOFF) |
7f48558e SP |
635 | return -EAGAIN; |
636 | /* else ok - we are shutting down the session */ | |
637 | } | |
638 | ||
31473fc4 | 639 | *mid = smb2_mid_entry_alloc(shdr, ses->server); |
2dc7e1c0 PS |
640 | if (*mid == NULL) |
641 | return -ENOMEM; | |
642 | spin_lock(&GlobalMid_Lock); | |
643 | list_add_tail(&(*mid)->qhead, &ses->server->pending_mid_q); | |
644 | spin_unlock(&GlobalMid_Lock); | |
53a3e0d9 | 645 | |
2dc7e1c0 PS |
646 | return 0; |
647 | } | |
648 | ||
649 | int | |
650 | smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server, | |
651 | bool log_error) | |
652 | { | |
e19b2bc0 | 653 | unsigned int len = mid->resp_buf_size; |
977b6170 | 654 | struct kvec iov[1]; |
738f9de5 | 655 | struct smb_rqst rqst = { .rq_iov = iov, |
977b6170 | 656 | .rq_nvec = 1 }; |
0b688cfc | 657 | |
738f9de5 | 658 | iov[0].iov_base = (char *)mid->resp_buf; |
977b6170 | 659 | iov[0].iov_len = len; |
2dc7e1c0 PS |
660 | |
661 | dump_smb(mid->resp_buf, min_t(u32, 80, len)); | |
662 | /* convert the length into a more usable form */ | |
4326ed2f | 663 | if (len > 24 && server->sign && !mid->decrypted) { |
3c1bf7e4 PS |
664 | int rc; |
665 | ||
0b688cfc | 666 | rc = smb2_verify_signature(&rqst, server); |
3c1bf7e4 | 667 | if (rc) |
f96637be JP |
668 | cifs_dbg(VFS, "SMB signature verification returned error = %d\n", |
669 | rc); | |
3c1bf7e4 | 670 | } |
2dc7e1c0 PS |
671 | |
672 | return map_smb2_to_linux_error(mid->resp_buf, log_error); | |
673 | } | |
674 | ||
fec344e3 JL |
675 | struct mid_q_entry * |
676 | smb2_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst) | |
2dc7e1c0 PS |
677 | { |
678 | int rc; | |
738f9de5 | 679 | struct smb2_sync_hdr *shdr = |
c713c877 | 680 | (struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base; |
2dc7e1c0 PS |
681 | struct mid_q_entry *mid; |
682 | ||
31473fc4 | 683 | smb2_seq_num_into_buf(ses->server, shdr); |
2dc7e1c0 | 684 | |
31473fc4 | 685 | rc = smb2_get_mid_entry(ses, shdr, &mid); |
c781af7e PS |
686 | if (rc) { |
687 | revert_current_mid_from_hdr(ses->server, shdr); | |
fec344e3 | 688 | return ERR_PTR(rc); |
c781af7e PS |
689 | } |
690 | ||
fec344e3 JL |
691 | rc = smb2_sign_rqst(rqst, ses->server); |
692 | if (rc) { | |
c781af7e | 693 | revert_current_mid_from_hdr(ses->server, shdr); |
3c1bf7e4 | 694 | cifs_delete_mid(mid); |
fec344e3 JL |
695 | return ERR_PTR(rc); |
696 | } | |
c781af7e | 697 | |
fec344e3 | 698 | return mid; |
2dc7e1c0 PS |
699 | } |
700 | ||
fec344e3 JL |
701 | struct mid_q_entry * |
702 | smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst) | |
c95b8eed | 703 | { |
fec344e3 | 704 | int rc; |
738f9de5 | 705 | struct smb2_sync_hdr *shdr = |
c713c877 | 706 | (struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base; |
c95b8eed PS |
707 | struct mid_q_entry *mid; |
708 | ||
2084ed57 PS |
709 | if (server->tcpStatus == CifsNeedNegotiate && |
710 | shdr->Command != SMB2_NEGOTIATE) | |
711 | return ERR_PTR(-EAGAIN); | |
712 | ||
31473fc4 | 713 | smb2_seq_num_into_buf(server, shdr); |
c95b8eed | 714 | |
31473fc4 | 715 | mid = smb2_mid_entry_alloc(shdr, server); |
c781af7e PS |
716 | if (mid == NULL) { |
717 | revert_current_mid_from_hdr(server, shdr); | |
fec344e3 | 718 | return ERR_PTR(-ENOMEM); |
c781af7e | 719 | } |
c95b8eed | 720 | |
fec344e3 | 721 | rc = smb2_sign_rqst(rqst, server); |
c95b8eed | 722 | if (rc) { |
c781af7e | 723 | revert_current_mid_from_hdr(server, shdr); |
c95b8eed | 724 | DeleteMidQEntry(mid); |
fec344e3 | 725 | return ERR_PTR(rc); |
3c1bf7e4 PS |
726 | } |
727 | ||
fec344e3 | 728 | return mid; |
c95b8eed | 729 | } |
026e93dc PS |
730 | |
731 | int | |
732 | smb3_crypto_aead_allocate(struct TCP_Server_Info *server) | |
733 | { | |
734 | struct crypto_aead *tfm; | |
735 | ||
736 | if (!server->secmech.ccmaesencrypt) { | |
737 | tfm = crypto_alloc_aead("ccm(aes)", 0, 0); | |
738 | if (IS_ERR(tfm)) { | |
739 | cifs_dbg(VFS, "%s: Failed to alloc encrypt aead\n", | |
740 | __func__); | |
741 | return PTR_ERR(tfm); | |
742 | } | |
743 | server->secmech.ccmaesencrypt = tfm; | |
744 | } | |
745 | ||
746 | if (!server->secmech.ccmaesdecrypt) { | |
747 | tfm = crypto_alloc_aead("ccm(aes)", 0, 0); | |
748 | if (IS_ERR(tfm)) { | |
749 | crypto_free_aead(server->secmech.ccmaesencrypt); | |
750 | server->secmech.ccmaesencrypt = NULL; | |
751 | cifs_dbg(VFS, "%s: Failed to alloc decrypt aead\n", | |
752 | __func__); | |
753 | return PTR_ERR(tfm); | |
754 | } | |
755 | server->secmech.ccmaesdecrypt = tfm; | |
756 | } | |
757 | ||
758 | return 0; | |
759 | } |