diff options
-rw-r--r-- | fs/cifs/Kconfig | 3 | ||||
-rw-r--r-- | fs/cifs/cifsencrypt.c | 427 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 1 | ||||
-rw-r--r-- | fs/cifs/cifsfs.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 55 | ||||
-rw-r--r-- | fs/cifs/cifspdu.h | 13 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 14 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 4 | ||||
-rw-r--r-- | fs/cifs/connect.c | 51 | ||||
-rw-r--r-- | fs/cifs/file.c | 57 | ||||
-rw-r--r-- | fs/cifs/inode.c | 15 | ||||
-rw-r--r-- | fs/cifs/misc.c | 2 | ||||
-rw-r--r-- | fs/cifs/sess.c | 166 | ||||
-rw-r--r-- | fs/cifs/transport.c | 6 |
14 files changed, 526 insertions, 290 deletions
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 917b7d449bb2..0ed213970ced 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig | |||
@@ -2,6 +2,9 @@ config CIFS | |||
2 | tristate "CIFS support (advanced network filesystem, SMBFS successor)" | 2 | tristate "CIFS support (advanced network filesystem, SMBFS successor)" |
3 | depends on INET | 3 | depends on INET |
4 | select NLS | 4 | select NLS |
5 | select CRYPTO | ||
6 | select CRYPTO_MD5 | ||
7 | select CRYPTO_ARC4 | ||
5 | help | 8 | help |
6 | This is the client VFS module for the Common Internet File System | 9 | This is the client VFS module for the Common Internet File System |
7 | (CIFS) protocol which is the successor to the Server Message Block | 10 | (CIFS) protocol which is the successor to the Server Message Block |
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 7ac0056294cf..f856732161ab 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c | |||
@@ -43,18 +43,32 @@ extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8, | |||
43 | unsigned char *p24); | 43 | unsigned char *p24); |
44 | 44 | ||
45 | static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, | 45 | static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, |
46 | const struct session_key *key, char *signature) | 46 | struct TCP_Server_Info *server, char *signature) |
47 | { | 47 | { |
48 | struct MD5Context context; | 48 | int rc; |
49 | 49 | ||
50 | if ((cifs_pdu == NULL) || (signature == NULL) || (key == NULL)) | 50 | if (cifs_pdu == NULL || signature == NULL || server == NULL) |
51 | return -EINVAL; | 51 | return -EINVAL; |
52 | 52 | ||
53 | cifs_MD5_init(&context); | 53 | if (!server->secmech.sdescmd5) { |
54 | cifs_MD5_update(&context, (char *)&key->data, key->len); | 54 | cERROR(1, "%s: Can't generate signature\n", __func__); |
55 | cifs_MD5_update(&context, cifs_pdu->Protocol, cifs_pdu->smb_buf_length); | 55 | return -1; |
56 | } | ||
57 | |||
58 | rc = crypto_shash_init(&server->secmech.sdescmd5->shash); | ||
59 | if (rc) { | ||
60 | cERROR(1, "%s: Oould not init md5\n", __func__); | ||
61 | return rc; | ||
62 | } | ||
63 | |||
64 | crypto_shash_update(&server->secmech.sdescmd5->shash, | ||
65 | server->session_key.response, server->session_key.len); | ||
66 | |||
67 | crypto_shash_update(&server->secmech.sdescmd5->shash, | ||
68 | cifs_pdu->Protocol, cifs_pdu->smb_buf_length); | ||
69 | |||
70 | rc = crypto_shash_final(&server->secmech.sdescmd5->shash, signature); | ||
56 | 71 | ||
57 | cifs_MD5_final(signature, &context); | ||
58 | return 0; | 72 | return 0; |
59 | } | 73 | } |
60 | 74 | ||
@@ -79,8 +93,7 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, | |||
79 | server->sequence_number++; | 93 | server->sequence_number++; |
80 | spin_unlock(&GlobalMid_Lock); | 94 | spin_unlock(&GlobalMid_Lock); |
81 | 95 | ||
82 | rc = cifs_calculate_signature(cifs_pdu, &server->session_key, | 96 | rc = cifs_calculate_signature(cifs_pdu, server, smb_signature); |
83 | smb_signature); | ||
84 | if (rc) | 97 | if (rc) |
85 | memset(cifs_pdu->Signature.SecuritySignature, 0, 8); | 98 | memset(cifs_pdu->Signature.SecuritySignature, 0, 8); |
86 | else | 99 | else |
@@ -90,16 +103,28 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, | |||
90 | } | 103 | } |
91 | 104 | ||
92 | static int cifs_calc_signature2(const struct kvec *iov, int n_vec, | 105 | static int cifs_calc_signature2(const struct kvec *iov, int n_vec, |
93 | const struct session_key *key, char *signature) | 106 | struct TCP_Server_Info *server, char *signature) |
94 | { | 107 | { |
95 | struct MD5Context context; | ||
96 | int i; | 108 | int i; |
109 | int rc; | ||
97 | 110 | ||
98 | if ((iov == NULL) || (signature == NULL) || (key == NULL)) | 111 | if (iov == NULL || signature == NULL || server == NULL) |
99 | return -EINVAL; | 112 | return -EINVAL; |
100 | 113 | ||
101 | cifs_MD5_init(&context); | 114 | if (!server->secmech.sdescmd5) { |
102 | cifs_MD5_update(&context, (char *)&key->data, key->len); | 115 | cERROR(1, "%s: Can't generate signature\n", __func__); |
116 | return -1; | ||
117 | } | ||
118 | |||
119 | rc = crypto_shash_init(&server->secmech.sdescmd5->shash); | ||
120 | if (rc) { | ||
121 | cERROR(1, "%s: Oould not init md5\n", __func__); | ||
122 | return rc; | ||
123 | } | ||
124 | |||
125 | crypto_shash_update(&server->secmech.sdescmd5->shash, | ||
126 | server->session_key.response, server->session_key.len); | ||
127 | |||
103 | for (i = 0; i < n_vec; i++) { | 128 | for (i = 0; i < n_vec; i++) { |
104 | if (iov[i].iov_len == 0) | 129 | if (iov[i].iov_len == 0) |
105 | continue; | 130 | continue; |
@@ -112,18 +137,18 @@ static int cifs_calc_signature2(const struct kvec *iov, int n_vec, | |||
112 | if (i == 0) { | 137 | if (i == 0) { |
113 | if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ | 138 | if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ |
114 | break; /* nothing to sign or corrupt header */ | 139 | break; /* nothing to sign or corrupt header */ |
115 | cifs_MD5_update(&context, iov[0].iov_base+4, | 140 | crypto_shash_update(&server->secmech.sdescmd5->shash, |
116 | iov[0].iov_len-4); | 141 | iov[i].iov_base + 4, iov[i].iov_len - 4); |
117 | } else | 142 | } else |
118 | cifs_MD5_update(&context, iov[i].iov_base, iov[i].iov_len); | 143 | crypto_shash_update(&server->secmech.sdescmd5->shash, |
144 | iov[i].iov_base, iov[i].iov_len); | ||
119 | } | 145 | } |
120 | 146 | ||
121 | cifs_MD5_final(signature, &context); | 147 | rc = crypto_shash_final(&server->secmech.sdescmd5->shash, signature); |
122 | 148 | ||
123 | return 0; | 149 | return rc; |
124 | } | 150 | } |
125 | 151 | ||
126 | |||
127 | int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, | 152 | int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, |
128 | __u32 *pexpected_response_sequence_number) | 153 | __u32 *pexpected_response_sequence_number) |
129 | { | 154 | { |
@@ -146,8 +171,7 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, | |||
146 | server->sequence_number++; | 171 | server->sequence_number++; |
147 | spin_unlock(&GlobalMid_Lock); | 172 | spin_unlock(&GlobalMid_Lock); |
148 | 173 | ||
149 | rc = cifs_calc_signature2(iov, n_vec, &server->session_key, | 174 | rc = cifs_calc_signature2(iov, n_vec, server, smb_signature); |
150 | smb_signature); | ||
151 | if (rc) | 175 | if (rc) |
152 | memset(cifs_pdu->Signature.SecuritySignature, 0, 8); | 176 | memset(cifs_pdu->Signature.SecuritySignature, 0, 8); |
153 | else | 177 | else |
@@ -157,14 +181,14 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, | |||
157 | } | 181 | } |
158 | 182 | ||
159 | int cifs_verify_signature(struct smb_hdr *cifs_pdu, | 183 | int cifs_verify_signature(struct smb_hdr *cifs_pdu, |
160 | const struct session_key *session_key, | 184 | struct TCP_Server_Info *server, |
161 | __u32 expected_sequence_number) | 185 | __u32 expected_sequence_number) |
162 | { | 186 | { |
163 | unsigned int rc; | 187 | unsigned int rc; |
164 | char server_response_sig[8]; | 188 | char server_response_sig[8]; |
165 | char what_we_think_sig_should_be[20]; | 189 | char what_we_think_sig_should_be[20]; |
166 | 190 | ||
167 | if (cifs_pdu == NULL || session_key == NULL) | 191 | if (cifs_pdu == NULL || server == NULL) |
168 | return -EINVAL; | 192 | return -EINVAL; |
169 | 193 | ||
170 | if (cifs_pdu->Command == SMB_COM_NEGOTIATE) | 194 | if (cifs_pdu->Command == SMB_COM_NEGOTIATE) |
@@ -193,7 +217,7 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu, | |||
193 | cpu_to_le32(expected_sequence_number); | 217 | cpu_to_le32(expected_sequence_number); |
194 | cifs_pdu->Signature.Sequence.Reserved = 0; | 218 | cifs_pdu->Signature.Sequence.Reserved = 0; |
195 | 219 | ||
196 | rc = cifs_calculate_signature(cifs_pdu, session_key, | 220 | rc = cifs_calculate_signature(cifs_pdu, server, |
197 | what_we_think_sig_should_be); | 221 | what_we_think_sig_should_be); |
198 | 222 | ||
199 | if (rc) | 223 | if (rc) |
@@ -209,18 +233,28 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu, | |||
209 | 233 | ||
210 | } | 234 | } |
211 | 235 | ||
212 | /* We fill in key by putting in 40 byte array which was allocated by caller */ | 236 | /* first calculate 24 bytes ntlm response and then 16 byte session key */ |
213 | int cifs_calculate_session_key(struct session_key *key, const char *rn, | 237 | int setup_ntlm_response(struct cifsSesInfo *ses) |
214 | const char *password) | ||
215 | { | 238 | { |
216 | char temp_key[16]; | 239 | unsigned int temp_len = CIFS_SESS_KEY_SIZE + CIFS_AUTH_RESP_SIZE; |
217 | if ((key == NULL) || (rn == NULL)) | 240 | char temp_key[CIFS_SESS_KEY_SIZE]; |
241 | |||
242 | if (!ses) | ||
218 | return -EINVAL; | 243 | return -EINVAL; |
219 | 244 | ||
220 | E_md4hash(password, temp_key); | 245 | ses->auth_key.response = kmalloc(temp_len, GFP_KERNEL); |
221 | mdfour(key->data.ntlm, temp_key, 16); | 246 | if (!ses->auth_key.response) { |
222 | memcpy(key->data.ntlm+16, rn, CIFS_SESS_KEY_SIZE); | 247 | cERROR(1, "NTLM can't allocate (%u bytes) memory", temp_len); |
223 | key->len = 40; | 248 | return -ENOMEM; |
249 | } | ||
250 | ses->auth_key.len = temp_len; | ||
251 | |||
252 | SMBNTencrypt(ses->password, ses->server->cryptkey, | ||
253 | ses->auth_key.response + CIFS_SESS_KEY_SIZE); | ||
254 | |||
255 | E_md4hash(ses->password, temp_key); | ||
256 | mdfour(ses->auth_key.response, temp_key, CIFS_SESS_KEY_SIZE); | ||
257 | |||
224 | return 0; | 258 | return 0; |
225 | } | 259 | } |
226 | 260 | ||
@@ -294,15 +328,15 @@ build_avpair_blob(struct cifsSesInfo *ses, const struct nls_table *nls_cp) | |||
294 | * two times the unicode length of a server name + | 328 | * two times the unicode length of a server name + |
295 | * size of a timestamp (which is 8 bytes). | 329 | * size of a timestamp (which is 8 bytes). |
296 | */ | 330 | */ |
297 | ses->tilen = size + 2 * (2 * dlen) + 2 * (2 * wlen) + 8; | 331 | ses->auth_key.len = size + 2 * (2 * dlen) + 2 * (2 * wlen) + 8; |
298 | ses->tiblob = kzalloc(ses->tilen, GFP_KERNEL); | 332 | ses->auth_key.response = kzalloc(ses->auth_key.len, GFP_KERNEL); |
299 | if (!ses->tiblob) { | 333 | if (!ses->auth_key.response) { |
300 | ses->tilen = 0; | 334 | ses->auth_key.len = 0; |
301 | cERROR(1, "Challenge target info allocation failure"); | 335 | cERROR(1, "Challenge target info allocation failure"); |
302 | return -ENOMEM; | 336 | return -ENOMEM; |
303 | } | 337 | } |
304 | 338 | ||
305 | blobptr = ses->tiblob; | 339 | blobptr = ses->auth_key.response; |
306 | attrptr = (struct ntlmssp2_name *) blobptr; | 340 | attrptr = (struct ntlmssp2_name *) blobptr; |
307 | 341 | ||
308 | attrptr->type = cpu_to_le16(NTLMSSP_AV_NB_DOMAIN_NAME); | 342 | attrptr->type = cpu_to_le16(NTLMSSP_AV_NB_DOMAIN_NAME); |
@@ -357,7 +391,7 @@ build_avpair_blob(struct cifsSesInfo *ses, const struct nls_table *nls_cp) | |||
357 | * about target string i.e. for some, just user name might suffice. | 391 | * about target string i.e. for some, just user name might suffice. |
358 | */ | 392 | */ |
359 | static int | 393 | static int |
360 | find_domain_name(struct cifsSesInfo *ses) | 394 | find_domain_name(struct cifsSesInfo *ses, const struct nls_table *nls_cp) |
361 | { | 395 | { |
362 | unsigned int attrsize; | 396 | unsigned int attrsize; |
363 | unsigned int type; | 397 | unsigned int type; |
@@ -366,11 +400,11 @@ find_domain_name(struct cifsSesInfo *ses) | |||
366 | unsigned char *blobend; | 400 | unsigned char *blobend; |
367 | struct ntlmssp2_name *attrptr; | 401 | struct ntlmssp2_name *attrptr; |
368 | 402 | ||
369 | if (!ses->tilen || !ses->tiblob) | 403 | if (!ses->auth_key.len || !ses->auth_key.response) |
370 | return 0; | 404 | return 0; |
371 | 405 | ||
372 | blobptr = ses->tiblob; | 406 | blobptr = ses->auth_key.response; |
373 | blobend = ses->tiblob + ses->tilen; | 407 | blobend = blobptr + ses->auth_key.len; |
374 | 408 | ||
375 | while (blobptr + onesize < blobend) { | 409 | while (blobptr + onesize < blobend) { |
376 | attrptr = (struct ntlmssp2_name *) blobptr; | 410 | attrptr = (struct ntlmssp2_name *) blobptr; |
@@ -386,16 +420,13 @@ find_domain_name(struct cifsSesInfo *ses) | |||
386 | if (!attrsize) | 420 | if (!attrsize) |
387 | break; | 421 | break; |
388 | if (!ses->domainName) { | 422 | if (!ses->domainName) { |
389 | struct nls_table *default_nls; | ||
390 | ses->domainName = | 423 | ses->domainName = |
391 | kmalloc(attrsize + 1, GFP_KERNEL); | 424 | kmalloc(attrsize + 1, GFP_KERNEL); |
392 | if (!ses->domainName) | 425 | if (!ses->domainName) |
393 | return -ENOMEM; | 426 | return -ENOMEM; |
394 | default_nls = load_nls_default(); | ||
395 | cifs_from_ucs2(ses->domainName, | 427 | cifs_from_ucs2(ses->domainName, |
396 | (__le16 *)blobptr, attrsize, attrsize, | 428 | (__le16 *)blobptr, attrsize, attrsize, |
397 | default_nls, false); | 429 | nls_cp, false); |
398 | unload_nls(default_nls); | ||
399 | break; | 430 | break; |
400 | } | 431 | } |
401 | } | 432 | } |
@@ -405,82 +436,136 @@ find_domain_name(struct cifsSesInfo *ses) | |||
405 | return 0; | 436 | return 0; |
406 | } | 437 | } |
407 | 438 | ||
408 | static int calc_ntlmv2_hash(struct cifsSesInfo *ses, | 439 | static int calc_ntlmv2_hash(struct cifsSesInfo *ses, char *ntlmv2_hash, |
409 | const struct nls_table *nls_cp) | 440 | const struct nls_table *nls_cp) |
410 | { | 441 | { |
411 | int rc = 0; | 442 | int rc = 0; |
412 | int len; | 443 | int len; |
413 | char nt_hash[16]; | 444 | char nt_hash[CIFS_NTHASH_SIZE]; |
414 | struct HMACMD5Context *pctxt; | ||
415 | wchar_t *user; | 445 | wchar_t *user; |
416 | wchar_t *domain; | 446 | wchar_t *domain; |
447 | wchar_t *server; | ||
417 | 448 | ||
418 | pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL); | 449 | if (!ses->server->secmech.sdeschmacmd5) { |
419 | 450 | cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n"); | |
420 | if (pctxt == NULL) | 451 | return -1; |
421 | return -ENOMEM; | 452 | } |
422 | 453 | ||
423 | /* calculate md4 hash of password */ | 454 | /* calculate md4 hash of password */ |
424 | E_md4hash(ses->password, nt_hash); | 455 | E_md4hash(ses->password, nt_hash); |
425 | 456 | ||
426 | /* convert Domainname to unicode and uppercase */ | 457 | crypto_shash_setkey(ses->server->secmech.hmacmd5, nt_hash, |
427 | hmac_md5_init_limK_to_64(nt_hash, 16, pctxt); | 458 | CIFS_NTHASH_SIZE); |
459 | |||
460 | rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash); | ||
461 | if (rc) { | ||
462 | cERROR(1, "calc_ntlmv2_hash: could not init hmacmd5\n"); | ||
463 | return rc; | ||
464 | } | ||
428 | 465 | ||
429 | /* convert ses->userName to unicode and uppercase */ | 466 | /* convert ses->userName to unicode and uppercase */ |
430 | len = strlen(ses->userName); | 467 | len = strlen(ses->userName); |
431 | user = kmalloc(2 + (len * 2), GFP_KERNEL); | 468 | user = kmalloc(2 + (len * 2), GFP_KERNEL); |
432 | if (user == NULL) | 469 | if (user == NULL) { |
470 | cERROR(1, "calc_ntlmv2_hash: user mem alloc failure\n"); | ||
471 | rc = -ENOMEM; | ||
433 | goto calc_exit_2; | 472 | goto calc_exit_2; |
473 | } | ||
434 | len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp); | 474 | len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp); |
435 | UniStrupr(user); | 475 | UniStrupr(user); |
436 | hmac_md5_update((char *)user, 2*len, pctxt); | 476 | |
477 | crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, | ||
478 | (char *)user, 2 * len); | ||
437 | 479 | ||
438 | /* convert ses->domainName to unicode and uppercase */ | 480 | /* convert ses->domainName to unicode and uppercase */ |
439 | if (ses->domainName) { | 481 | if (ses->domainName) { |
440 | len = strlen(ses->domainName); | 482 | len = strlen(ses->domainName); |
441 | 483 | ||
442 | domain = kmalloc(2 + (len * 2), GFP_KERNEL); | 484 | domain = kmalloc(2 + (len * 2), GFP_KERNEL); |
443 | if (domain == NULL) | 485 | if (domain == NULL) { |
486 | cERROR(1, "calc_ntlmv2_hash: domain mem alloc failure"); | ||
487 | rc = -ENOMEM; | ||
444 | goto calc_exit_1; | 488 | goto calc_exit_1; |
489 | } | ||
445 | len = cifs_strtoUCS((__le16 *)domain, ses->domainName, len, | 490 | len = cifs_strtoUCS((__le16 *)domain, ses->domainName, len, |
446 | nls_cp); | 491 | nls_cp); |
447 | /* the following line was removed since it didn't work well | 492 | crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, |
448 | with lower cased domain name that passed as an option. | 493 | (char *)domain, 2 * len); |
449 | Maybe converting the domain name earlier makes sense */ | ||
450 | /* UniStrupr(domain); */ | ||
451 | |||
452 | hmac_md5_update((char *)domain, 2*len, pctxt); | ||
453 | |||
454 | kfree(domain); | 494 | kfree(domain); |
495 | } else if (ses->serverName) { | ||
496 | len = strlen(ses->serverName); | ||
497 | |||
498 | server = kmalloc(2 + (len * 2), GFP_KERNEL); | ||
499 | if (server == NULL) { | ||
500 | cERROR(1, "calc_ntlmv2_hash: server mem alloc failure"); | ||
501 | rc = -ENOMEM; | ||
502 | goto calc_exit_1; | ||
503 | } | ||
504 | len = cifs_strtoUCS((__le16 *)server, ses->serverName, len, | ||
505 | nls_cp); | ||
506 | crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, | ||
507 | (char *)server, 2 * len); | ||
508 | kfree(server); | ||
455 | } | 509 | } |
510 | |||
511 | rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash, | ||
512 | ntlmv2_hash); | ||
513 | |||
456 | calc_exit_1: | 514 | calc_exit_1: |
457 | kfree(user); | 515 | kfree(user); |
458 | calc_exit_2: | 516 | calc_exit_2: |
459 | /* BB FIXME what about bytes 24 through 40 of the signing key? | 517 | return rc; |
460 | compare with the NTLM example */ | 518 | } |
461 | hmac_md5_final(ses->ntlmv2_hash, pctxt); | 519 | |
520 | static int | ||
521 | CalcNTLMv2_response(const struct cifsSesInfo *ses, char *ntlmv2_hash) | ||
522 | { | ||
523 | int rc; | ||
524 | unsigned int offset = CIFS_SESS_KEY_SIZE + 8; | ||
525 | |||
526 | if (!ses->server->secmech.sdeschmacmd5) { | ||
527 | cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n"); | ||
528 | return -1; | ||
529 | } | ||
530 | |||
531 | crypto_shash_setkey(ses->server->secmech.hmacmd5, | ||
532 | ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); | ||
533 | |||
534 | rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash); | ||
535 | if (rc) { | ||
536 | cERROR(1, "CalcNTLMv2_response: could not init hmacmd5"); | ||
537 | return rc; | ||
538 | } | ||
539 | |||
540 | if (ses->server->secType == RawNTLMSSP) | ||
541 | memcpy(ses->auth_key.response + offset, | ||
542 | ses->ntlmssp->cryptkey, CIFS_SERVER_CHALLENGE_SIZE); | ||
543 | else | ||
544 | memcpy(ses->auth_key.response + offset, | ||
545 | ses->server->cryptkey, CIFS_SERVER_CHALLENGE_SIZE); | ||
546 | crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, | ||
547 | ses->auth_key.response + offset, ses->auth_key.len - offset); | ||
548 | |||
549 | rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash, | ||
550 | ses->auth_key.response + CIFS_SESS_KEY_SIZE); | ||
462 | 551 | ||
463 | kfree(pctxt); | ||
464 | return rc; | 552 | return rc; |
465 | } | 553 | } |
466 | 554 | ||
555 | |||
467 | int | 556 | int |
468 | setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, | 557 | setup_ntlmv2_rsp(struct cifsSesInfo *ses, const struct nls_table *nls_cp) |
469 | const struct nls_table *nls_cp) | ||
470 | { | 558 | { |
471 | int rc; | 559 | int rc; |
472 | struct ntlmv2_resp *buf = (struct ntlmv2_resp *)resp_buf; | 560 | int baselen; |
473 | struct HMACMD5Context context; | 561 | unsigned int tilen; |
474 | 562 | struct ntlmv2_resp *buf; | |
475 | buf->blob_signature = cpu_to_le32(0x00000101); | 563 | char ntlmv2_hash[16]; |
476 | buf->reserved = 0; | 564 | unsigned char *tiblob = NULL; /* target info blob */ |
477 | buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | ||
478 | get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); | ||
479 | buf->reserved2 = 0; | ||
480 | 565 | ||
481 | if (ses->server->secType == RawNTLMSSP) { | 566 | if (ses->server->secType == RawNTLMSSP) { |
482 | if (!ses->domainName) { | 567 | if (!ses->domainName) { |
483 | rc = find_domain_name(ses); | 568 | rc = find_domain_name(ses, nls_cp); |
484 | if (rc) { | 569 | if (rc) { |
485 | cERROR(1, "error %d finding domain name", rc); | 570 | cERROR(1, "error %d finding domain name", rc); |
486 | goto setup_ntlmv2_rsp_ret; | 571 | goto setup_ntlmv2_rsp_ret; |
@@ -490,51 +575,179 @@ setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, | |||
490 | rc = build_avpair_blob(ses, nls_cp); | 575 | rc = build_avpair_blob(ses, nls_cp); |
491 | if (rc) { | 576 | if (rc) { |
492 | cERROR(1, "error %d building av pair blob", rc); | 577 | cERROR(1, "error %d building av pair blob", rc); |
493 | return rc; | 578 | goto setup_ntlmv2_rsp_ret; |
494 | } | 579 | } |
495 | } | 580 | } |
496 | 581 | ||
497 | /* calculate buf->ntlmv2_hash */ | 582 | baselen = CIFS_SESS_KEY_SIZE + sizeof(struct ntlmv2_resp); |
498 | rc = calc_ntlmv2_hash(ses, nls_cp); | 583 | tilen = ses->auth_key.len; |
584 | tiblob = ses->auth_key.response; | ||
585 | |||
586 | ses->auth_key.response = kmalloc(baselen + tilen, GFP_KERNEL); | ||
587 | if (!ses->auth_key.response) { | ||
588 | rc = ENOMEM; | ||
589 | ses->auth_key.len = 0; | ||
590 | cERROR(1, "%s: Can't allocate auth blob", __func__); | ||
591 | goto setup_ntlmv2_rsp_ret; | ||
592 | } | ||
593 | ses->auth_key.len += baselen; | ||
594 | |||
595 | buf = (struct ntlmv2_resp *) | ||
596 | (ses->auth_key.response + CIFS_SESS_KEY_SIZE); | ||
597 | buf->blob_signature = cpu_to_le32(0x00000101); | ||
598 | buf->reserved = 0; | ||
599 | buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | ||
600 | get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); | ||
601 | buf->reserved2 = 0; | ||
602 | |||
603 | memcpy(ses->auth_key.response + baselen, tiblob, tilen); | ||
604 | |||
605 | /* calculate ntlmv2_hash */ | ||
606 | rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp); | ||
499 | if (rc) { | 607 | if (rc) { |
500 | cERROR(1, "could not get v2 hash rc %d", rc); | 608 | cERROR(1, "could not get v2 hash rc %d", rc); |
501 | goto setup_ntlmv2_rsp_ret; | 609 | goto setup_ntlmv2_rsp_ret; |
502 | } | 610 | } |
503 | CalcNTLMv2_response(ses, resp_buf); | 611 | |
612 | /* calculate first part of the client response (CR1) */ | ||
613 | rc = CalcNTLMv2_response(ses, ntlmv2_hash); | ||
614 | if (rc) { | ||
615 | cERROR(1, "Could not calculate CR1 rc: %d", rc); | ||
616 | goto setup_ntlmv2_rsp_ret; | ||
617 | } | ||
504 | 618 | ||
505 | /* now calculate the session key for NTLMv2 */ | 619 | /* now calculate the session key for NTLMv2 */ |
506 | hmac_md5_init_limK_to_64(ses->ntlmv2_hash, 16, &context); | 620 | crypto_shash_setkey(ses->server->secmech.hmacmd5, |
507 | hmac_md5_update(resp_buf, 16, &context); | 621 | ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); |
508 | hmac_md5_final(ses->auth_key.data.ntlmv2.key, &context); | 622 | |
623 | rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash); | ||
624 | if (rc) { | ||
625 | cERROR(1, "%s: Could not init hmacmd5\n", __func__); | ||
626 | goto setup_ntlmv2_rsp_ret; | ||
627 | } | ||
509 | 628 | ||
510 | memcpy(&ses->auth_key.data.ntlmv2.resp, resp_buf, | 629 | crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, |
511 | sizeof(struct ntlmv2_resp)); | 630 | ses->auth_key.response + CIFS_SESS_KEY_SIZE, |
512 | ses->auth_key.len = 16 + sizeof(struct ntlmv2_resp); | 631 | CIFS_HMAC_MD5_HASH_SIZE); |
513 | 632 | ||
514 | return 0; | 633 | rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash, |
634 | ses->auth_key.response); | ||
515 | 635 | ||
516 | setup_ntlmv2_rsp_ret: | 636 | setup_ntlmv2_rsp_ret: |
517 | kfree(ses->tiblob); | 637 | kfree(tiblob); |
518 | ses->tiblob = NULL; | ||
519 | ses->tilen = 0; | ||
520 | 638 | ||
521 | return rc; | 639 | return rc; |
522 | } | 640 | } |
523 | 641 | ||
524 | void CalcNTLMv2_response(const struct cifsSesInfo *ses, | 642 | int |
525 | char *v2_session_response) | 643 | calc_seckey(struct cifsSesInfo *ses) |
526 | { | 644 | { |
527 | struct HMACMD5Context context; | 645 | int rc; |
528 | /* rest of v2 struct already generated */ | 646 | struct crypto_blkcipher *tfm_arc4; |
529 | memcpy(v2_session_response + 8, ses->cryptKey, 8); | 647 | struct scatterlist sgin, sgout; |
530 | hmac_md5_init_limK_to_64(ses->ntlmv2_hash, 16, &context); | 648 | struct blkcipher_desc desc; |
649 | unsigned char sec_key[CIFS_SESS_KEY_SIZE]; /* a nonce */ | ||
650 | |||
651 | get_random_bytes(sec_key, CIFS_SESS_KEY_SIZE); | ||
652 | |||
653 | tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); | ||
654 | if (!tfm_arc4 || IS_ERR(tfm_arc4)) { | ||
655 | cERROR(1, "could not allocate crypto API arc4\n"); | ||
656 | return PTR_ERR(tfm_arc4); | ||
657 | } | ||
531 | 658 | ||
532 | hmac_md5_update(v2_session_response+8, | 659 | desc.tfm = tfm_arc4; |
533 | sizeof(struct ntlmv2_resp) - 8, &context); | ||
534 | 660 | ||
535 | if (ses->tilen) | 661 | crypto_blkcipher_setkey(tfm_arc4, ses->auth_key.response, |
536 | hmac_md5_update(ses->tiblob, ses->tilen, &context); | 662 | CIFS_SESS_KEY_SIZE); |
537 | 663 | ||
538 | hmac_md5_final(v2_session_response, &context); | 664 | sg_init_one(&sgin, sec_key, CIFS_SESS_KEY_SIZE); |
539 | /* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */ | 665 | sg_init_one(&sgout, ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE); |
666 | |||
667 | rc = crypto_blkcipher_encrypt(&desc, &sgout, &sgin, CIFS_CPHTXT_SIZE); | ||
668 | if (rc) { | ||
669 | cERROR(1, "could not encrypt session key rc: %d\n", rc); | ||
670 | crypto_free_blkcipher(tfm_arc4); | ||
671 | return rc; | ||
672 | } | ||
673 | |||
674 | /* make secondary_key/nonce as session key */ | ||
675 | memcpy(ses->auth_key.response, sec_key, CIFS_SESS_KEY_SIZE); | ||
676 | /* and make len as that of session key only */ | ||
677 | ses->auth_key.len = CIFS_SESS_KEY_SIZE; | ||
678 | |||
679 | crypto_free_blkcipher(tfm_arc4); | ||
680 | |||
681 | return 0; | ||
682 | } | ||
683 | |||
684 | void | ||
685 | cifs_crypto_shash_release(struct TCP_Server_Info *server) | ||
686 | { | ||
687 | if (server->secmech.md5) | ||
688 | crypto_free_shash(server->secmech.md5); | ||
689 | |||
690 | if (server->secmech.hmacmd5) | ||
691 | crypto_free_shash(server->secmech.hmacmd5); | ||
692 | |||
693 | kfree(server->secmech.sdeschmacmd5); | ||
694 | |||
695 | kfree(server->secmech.sdescmd5); | ||
696 | } | ||
697 | |||
698 | int | ||
699 | cifs_crypto_shash_allocate(struct TCP_Server_Info *server) | ||
700 | { | ||
701 | int rc; | ||
702 | unsigned int size; | ||
703 | |||
704 | server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0); | ||
705 | if (!server->secmech.hmacmd5 || | ||
706 | IS_ERR(server->secmech.hmacmd5)) { | ||
707 | cERROR(1, "could not allocate crypto hmacmd5\n"); | ||
708 | return PTR_ERR(server->secmech.hmacmd5); | ||
709 | } | ||
710 | |||
711 | server->secmech.md5 = crypto_alloc_shash("md5", 0, 0); | ||
712 | if (!server->secmech.md5 || IS_ERR(server->secmech.md5)) { | ||
713 | cERROR(1, "could not allocate crypto md5\n"); | ||
714 | rc = PTR_ERR(server->secmech.md5); | ||
715 | goto crypto_allocate_md5_fail; | ||
716 | } | ||
717 | |||
718 | size = sizeof(struct shash_desc) + | ||
719 | crypto_shash_descsize(server->secmech.hmacmd5); | ||
720 | server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL); | ||
721 | if (!server->secmech.sdeschmacmd5) { | ||
722 | cERROR(1, "cifs_crypto_shash_allocate: can't alloc hmacmd5\n"); | ||
723 | rc = -ENOMEM; | ||
724 | goto crypto_allocate_hmacmd5_sdesc_fail; | ||
725 | } | ||
726 | server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5; | ||
727 | server->secmech.sdeschmacmd5->shash.flags = 0x0; | ||
728 | |||
729 | |||
730 | size = sizeof(struct shash_desc) + | ||
731 | crypto_shash_descsize(server->secmech.md5); | ||
732 | server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL); | ||
733 | if (!server->secmech.sdescmd5) { | ||
734 | cERROR(1, "cifs_crypto_shash_allocate: can't alloc md5\n"); | ||
735 | rc = -ENOMEM; | ||
736 | goto crypto_allocate_md5_sdesc_fail; | ||
737 | } | ||
738 | server->secmech.sdescmd5->shash.tfm = server->secmech.md5; | ||
739 | server->secmech.sdescmd5->shash.flags = 0x0; | ||
740 | |||
741 | return 0; | ||
742 | |||
743 | crypto_allocate_md5_sdesc_fail: | ||
744 | kfree(server->secmech.sdeschmacmd5); | ||
745 | |||
746 | crypto_allocate_hmacmd5_sdesc_fail: | ||
747 | crypto_free_shash(server->secmech.md5); | ||
748 | |||
749 | crypto_allocate_md5_fail: | ||
750 | crypto_free_shash(server->secmech.hmacmd5); | ||
751 | |||
752 | return rc; | ||
540 | } | 753 | } |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 8bd5c2c243a5..75c4eaa79588 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -318,7 +318,6 @@ cifs_alloc_inode(struct super_block *sb) | |||
318 | return NULL; | 318 | return NULL; |
319 | cifs_inode->cifsAttrs = 0x20; /* default */ | 319 | cifs_inode->cifsAttrs = 0x20; /* default */ |
320 | cifs_inode->time = 0; | 320 | cifs_inode->time = 0; |
321 | cifs_inode->write_behind_rc = 0; | ||
322 | /* Until the file is open and we have gotten oplock | 321 | /* Until the file is open and we have gotten oplock |
323 | info back from the server, can not assume caching of | 322 | info back from the server, can not assume caching of |
324 | file data or metadata */ | 323 | file data or metadata */ |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index f35795a16b42..897b2b2b28b5 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
@@ -112,5 +112,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); | |||
112 | extern const struct export_operations cifs_export_ops; | 112 | extern const struct export_operations cifs_export_ops; |
113 | #endif /* EXPERIMENTAL */ | 113 | #endif /* EXPERIMENTAL */ |
114 | 114 | ||
115 | #define CIFS_VERSION "1.67" | 115 | #define CIFS_VERSION "1.68" |
116 | #endif /* _CIFSFS_H */ | 116 | #endif /* _CIFSFS_H */ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 3365e77f6f24..f259e4d7612d 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -25,6 +25,9 @@ | |||
25 | #include <linux/workqueue.h> | 25 | #include <linux/workqueue.h> |
26 | #include "cifs_fs_sb.h" | 26 | #include "cifs_fs_sb.h" |
27 | #include "cifsacl.h" | 27 | #include "cifsacl.h" |
28 | #include <crypto/internal/hash.h> | ||
29 | #include <linux/scatterlist.h> | ||
30 | |||
28 | /* | 31 | /* |
29 | * The sizes of various internal tables and strings | 32 | * The sizes of various internal tables and strings |
30 | */ | 33 | */ |
@@ -74,7 +77,7 @@ | |||
74 | * CIFS vfs client Status information (based on what we know.) | 77 | * CIFS vfs client Status information (based on what we know.) |
75 | */ | 78 | */ |
76 | 79 | ||
77 | /* associated with each tcp and smb session */ | 80 | /* associated with each tcp and smb session */ |
78 | enum statusEnum { | 81 | enum statusEnum { |
79 | CifsNew = 0, | 82 | CifsNew = 0, |
80 | CifsGood, | 83 | CifsGood, |
@@ -99,14 +102,29 @@ enum protocolEnum { | |||
99 | 102 | ||
100 | struct session_key { | 103 | struct session_key { |
101 | unsigned int len; | 104 | unsigned int len; |
102 | union { | 105 | char *response; |
103 | char ntlm[CIFS_SESS_KEY_SIZE + 16]; | 106 | }; |
104 | char krb5[CIFS_SESS_KEY_SIZE + 16]; /* BB: length correct? */ | 107 | |
105 | struct { | 108 | /* crypto security descriptor definition */ |
106 | char key[16]; | 109 | struct sdesc { |
107 | struct ntlmv2_resp resp; | 110 | struct shash_desc shash; |
108 | } ntlmv2; | 111 | char ctx[]; |
109 | } data; | 112 | }; |
113 | |||
114 | /* crypto hashing related structure/fields, not specific to a sec mech */ | ||
115 | struct cifs_secmech { | ||
116 | struct crypto_shash *hmacmd5; /* hmac-md5 hash function */ | ||
117 | struct crypto_shash *md5; /* md5 hash function */ | ||
118 | struct sdesc *sdeschmacmd5; /* ctxt to generate ntlmv2 hash, CR1 */ | ||
119 | struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */ | ||
120 | }; | ||
121 | |||
122 | /* per smb session structure/fields */ | ||
123 | struct ntlmssp_auth { | ||
124 | __u32 client_flags; /* sent by client in type 1 ntlmsssp exchange */ | ||
125 | __u32 server_flags; /* sent by server in type 2 ntlmssp exchange */ | ||
126 | unsigned char ciphertext[CIFS_CPHTXT_SIZE]; /* sent to server */ | ||
127 | char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlmssp */ | ||
110 | }; | 128 | }; |
111 | 129 | ||
112 | struct cifs_cred { | 130 | struct cifs_cred { |
@@ -179,12 +197,14 @@ struct TCP_Server_Info { | |||
179 | int capabilities; /* allow selective disabling of caps by smb sess */ | 197 | int capabilities; /* allow selective disabling of caps by smb sess */ |
180 | int timeAdj; /* Adjust for difference in server time zone in sec */ | 198 | int timeAdj; /* Adjust for difference in server time zone in sec */ |
181 | __u16 CurrentMid; /* multiplex id - rotating counter */ | 199 | __u16 CurrentMid; /* multiplex id - rotating counter */ |
200 | char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlm, ntlmv2 etc */ | ||
182 | /* 16th byte of RFC1001 workstation name is always null */ | 201 | /* 16th byte of RFC1001 workstation name is always null */ |
183 | char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; | 202 | char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; |
184 | __u32 sequence_number; /* needed for CIFS PDU signature */ | 203 | __u32 sequence_number; /* needed for CIFS PDU signature */ |
185 | struct session_key session_key; | 204 | struct session_key session_key; |
186 | unsigned long lstrp; /* when we got last response from this server */ | 205 | unsigned long lstrp; /* when we got last response from this server */ |
187 | u16 dialect; /* dialect index that server chose */ | 206 | u16 dialect; /* dialect index that server chose */ |
207 | struct cifs_secmech secmech; /* crypto sec mech functs, descriptors */ | ||
188 | /* extended security flavors that server supports */ | 208 | /* extended security flavors that server supports */ |
189 | bool sec_kerberos; /* supports plain Kerberos */ | 209 | bool sec_kerberos; /* supports plain Kerberos */ |
190 | bool sec_mskerberos; /* supports legacy MS Kerberos */ | 210 | bool sec_mskerberos; /* supports legacy MS Kerberos */ |
@@ -222,11 +242,8 @@ struct cifsSesInfo { | |||
222 | char userName[MAX_USERNAME_SIZE + 1]; | 242 | char userName[MAX_USERNAME_SIZE + 1]; |
223 | char *domainName; | 243 | char *domainName; |
224 | char *password; | 244 | char *password; |
225 | char cryptKey[CIFS_CRYPTO_KEY_SIZE]; | ||
226 | struct session_key auth_key; | 245 | struct session_key auth_key; |
227 | char ntlmv2_hash[16]; | 246 | struct ntlmssp_auth *ntlmssp; /* ciphertext, flags, server challenge */ |
228 | unsigned int tilen; /* length of the target info blob */ | ||
229 | unsigned char *tiblob; /* target info blob in challenge response */ | ||
230 | bool need_reconnect:1; /* connection reset, uid now invalid */ | 247 | bool need_reconnect:1; /* connection reset, uid now invalid */ |
231 | }; | 248 | }; |
232 | /* no more than one of the following three session flags may be set */ | 249 | /* no more than one of the following three session flags may be set */ |
@@ -395,16 +412,19 @@ struct cifsFileInfo { | |||
395 | struct list_head llist; /* list of byte range locks we have. */ | 412 | struct list_head llist; /* list of byte range locks we have. */ |
396 | bool invalidHandle:1; /* file closed via session abend */ | 413 | bool invalidHandle:1; /* file closed via session abend */ |
397 | bool oplock_break_cancelled:1; | 414 | bool oplock_break_cancelled:1; |
398 | atomic_t count; /* reference count */ | 415 | int count; /* refcount protected by cifs_file_list_lock */ |
399 | struct mutex fh_mutex; /* prevents reopen race after dead ses*/ | 416 | struct mutex fh_mutex; /* prevents reopen race after dead ses*/ |
400 | struct cifs_search_info srch_inf; | 417 | struct cifs_search_info srch_inf; |
401 | struct work_struct oplock_break; /* work for oplock breaks */ | 418 | struct work_struct oplock_break; /* work for oplock breaks */ |
402 | }; | 419 | }; |
403 | 420 | ||
404 | /* Take a reference on the file private data */ | 421 | /* |
422 | * Take a reference on the file private data. Must be called with | ||
423 | * cifs_file_list_lock held. | ||
424 | */ | ||
405 | static inline void cifsFileInfo_get(struct cifsFileInfo *cifs_file) | 425 | static inline void cifsFileInfo_get(struct cifsFileInfo *cifs_file) |
406 | { | 426 | { |
407 | atomic_inc(&cifs_file->count); | 427 | ++cifs_file->count; |
408 | } | 428 | } |
409 | 429 | ||
410 | void cifsFileInfo_put(struct cifsFileInfo *cifs_file); | 430 | void cifsFileInfo_put(struct cifsFileInfo *cifs_file); |
@@ -417,7 +437,6 @@ struct cifsInodeInfo { | |||
417 | struct list_head lockList; | 437 | struct list_head lockList; |
418 | /* BB add in lists for dirty pages i.e. write caching info for oplock */ | 438 | /* BB add in lists for dirty pages i.e. write caching info for oplock */ |
419 | struct list_head openFileList; | 439 | struct list_head openFileList; |
420 | int write_behind_rc; | ||
421 | __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ | 440 | __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ |
422 | unsigned long time; /* jiffies of last update/check of inode */ | 441 | unsigned long time; /* jiffies of last update/check of inode */ |
423 | bool clientCanCacheRead:1; /* read oplock */ | 442 | bool clientCanCacheRead:1; /* read oplock */ |
@@ -668,7 +687,7 @@ require use of the stronger protocol */ | |||
668 | * GlobalMid_Lock protects: | 687 | * GlobalMid_Lock protects: |
669 | * list operations on pending_mid_q and oplockQ | 688 | * list operations on pending_mid_q and oplockQ |
670 | * updates to XID counters, multiplex id and SMB sequence numbers | 689 | * updates to XID counters, multiplex id and SMB sequence numbers |
671 | * GlobalSMBSesLock protects: | 690 | * cifs_file_list_lock protects: |
672 | * list operations on tcp and SMB session lists and tCon lists | 691 | * list operations on tcp and SMB session lists and tCon lists |
673 | * f_owner.lock protects certain per file struct operations | 692 | * f_owner.lock protects certain per file struct operations |
674 | * mapping->page_lock protects certain per page operations | 693 | * mapping->page_lock protects certain per page operations |
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index b0f4b5656d4c..de36b09763a8 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h | |||
@@ -131,9 +131,20 @@ | |||
131 | #define CIFS_CRYPTO_KEY_SIZE (8) | 131 | #define CIFS_CRYPTO_KEY_SIZE (8) |
132 | 132 | ||
133 | /* | 133 | /* |
134 | * Size of the ntlm client response | ||
135 | */ | ||
136 | #define CIFS_AUTH_RESP_SIZE (24) | ||
137 | |||
138 | /* | ||
134 | * Size of the session key (crypto key encrypted with the password | 139 | * Size of the session key (crypto key encrypted with the password |
135 | */ | 140 | */ |
136 | #define CIFS_SESS_KEY_SIZE (24) | 141 | #define CIFS_SESS_KEY_SIZE (16) |
142 | |||
143 | #define CIFS_CLIENT_CHALLENGE_SIZE (8) | ||
144 | #define CIFS_SERVER_CHALLENGE_SIZE (8) | ||
145 | #define CIFS_HMAC_MD5_HASH_SIZE (16) | ||
146 | #define CIFS_CPHTXT_SIZE (16) | ||
147 | #define CIFS_NTHASH_SIZE (16) | ||
137 | 148 | ||
138 | /* | 149 | /* |
139 | * Maximum user name length | 150 | * Maximum user name length |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index e593c40ba7ba..edb6d90efdf2 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -362,13 +362,15 @@ extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *, __u32 *); | |||
362 | extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *, | 362 | extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *, |
363 | __u32 *); | 363 | __u32 *); |
364 | extern int cifs_verify_signature(struct smb_hdr *, | 364 | extern int cifs_verify_signature(struct smb_hdr *, |
365 | const struct session_key *session_key, | 365 | struct TCP_Server_Info *server, |
366 | __u32 expected_sequence_number); | 366 | __u32 expected_sequence_number); |
367 | extern int cifs_calculate_session_key(struct session_key *key, const char *rn, | 367 | extern void SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *); |
368 | const char *pass); | 368 | extern int setup_ntlm_response(struct cifsSesInfo *); |
369 | extern void CalcNTLMv2_response(const struct cifsSesInfo *, char *); | 369 | extern int setup_ntlmv2_rsp(struct cifsSesInfo *, const struct nls_table *); |
370 | extern int setup_ntlmv2_rsp(struct cifsSesInfo *, char *, | 370 | extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *); |
371 | const struct nls_table *); | 371 | extern void cifs_crypto_shash_release(struct TCP_Server_Info *); |
372 | extern int calc_seckey(struct cifsSesInfo *); | ||
373 | |||
372 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 374 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
373 | extern void calc_lanman_hash(const char *password, const char *cryptkey, | 375 | extern void calc_lanman_hash(const char *password, const char *cryptkey, |
374 | bool encrypt, char *lnm_session_key); | 376 | bool encrypt, char *lnm_session_key); |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index e98f1f317b15..2f2632b6df5a 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -503,7 +503,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
503 | 503 | ||
504 | if (rsp->EncryptionKeyLength == | 504 | if (rsp->EncryptionKeyLength == |
505 | cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) { | 505 | cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) { |
506 | memcpy(ses->cryptKey, rsp->EncryptionKey, | 506 | memcpy(ses->server->cryptkey, rsp->EncryptionKey, |
507 | CIFS_CRYPTO_KEY_SIZE); | 507 | CIFS_CRYPTO_KEY_SIZE); |
508 | } else if (server->secMode & SECMODE_PW_ENCRYPT) { | 508 | } else if (server->secMode & SECMODE_PW_ENCRYPT) { |
509 | rc = -EIO; /* need cryptkey unless plain text */ | 509 | rc = -EIO; /* need cryptkey unless plain text */ |
@@ -574,7 +574,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
574 | server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone); | 574 | server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone); |
575 | server->timeAdj *= 60; | 575 | server->timeAdj *= 60; |
576 | if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { | 576 | if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { |
577 | memcpy(ses->cryptKey, pSMBr->u.EncryptionKey, | 577 | memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey, |
578 | CIFS_CRYPTO_KEY_SIZE); | 578 | CIFS_CRYPTO_KEY_SIZE); |
579 | } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) | 579 | } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) |
580 | && (pSMBr->EncryptionKeyLength == 0)) { | 580 | && (pSMBr->EncryptionKeyLength == 0)) { |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 7e73176acb58..9eb327defa1d 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -175,6 +175,9 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
175 | } | 175 | } |
176 | server->sequence_number = 0; | 176 | server->sequence_number = 0; |
177 | server->session_estab = false; | 177 | server->session_estab = false; |
178 | kfree(server->session_key.response); | ||
179 | server->session_key.response = NULL; | ||
180 | server->session_key.len = 0; | ||
178 | 181 | ||
179 | spin_lock(&GlobalMid_Lock); | 182 | spin_lock(&GlobalMid_Lock); |
180 | list_for_each(tmp, &server->pending_mid_q) { | 183 | list_for_each(tmp, &server->pending_mid_q) { |
@@ -1064,7 +1067,7 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1064 | } | 1067 | } |
1065 | i = cifs_convert_address((struct sockaddr *)&vol->srcaddr, | 1068 | i = cifs_convert_address((struct sockaddr *)&vol->srcaddr, |
1066 | value, strlen(value)); | 1069 | value, strlen(value)); |
1067 | if (i < 0) { | 1070 | if (i == 0) { |
1068 | printk(KERN_WARNING "CIFS: Could not parse" | 1071 | printk(KERN_WARNING "CIFS: Could not parse" |
1069 | " srcaddr: %s\n", | 1072 | " srcaddr: %s\n", |
1070 | value); | 1073 | value); |
@@ -1560,8 +1563,13 @@ cifs_put_tcp_session(struct TCP_Server_Info *server) | |||
1560 | server->tcpStatus = CifsExiting; | 1563 | server->tcpStatus = CifsExiting; |
1561 | spin_unlock(&GlobalMid_Lock); | 1564 | spin_unlock(&GlobalMid_Lock); |
1562 | 1565 | ||
1566 | cifs_crypto_shash_release(server); | ||
1563 | cifs_fscache_release_client_cookie(server); | 1567 | cifs_fscache_release_client_cookie(server); |
1564 | 1568 | ||
1569 | kfree(server->session_key.response); | ||
1570 | server->session_key.response = NULL; | ||
1571 | server->session_key.len = 0; | ||
1572 | |||
1565 | task = xchg(&server->tsk, NULL); | 1573 | task = xchg(&server->tsk, NULL); |
1566 | if (task) | 1574 | if (task) |
1567 | force_sig(SIGKILL, task); | 1575 | force_sig(SIGKILL, task); |
@@ -1614,10 +1622,16 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1614 | goto out_err; | 1622 | goto out_err; |
1615 | } | 1623 | } |
1616 | 1624 | ||
1625 | rc = cifs_crypto_shash_allocate(tcp_ses); | ||
1626 | if (rc) { | ||
1627 | cERROR(1, "could not setup hash structures rc %d", rc); | ||
1628 | goto out_err; | ||
1629 | } | ||
1630 | |||
1617 | tcp_ses->hostname = extract_hostname(volume_info->UNC); | 1631 | tcp_ses->hostname = extract_hostname(volume_info->UNC); |
1618 | if (IS_ERR(tcp_ses->hostname)) { | 1632 | if (IS_ERR(tcp_ses->hostname)) { |
1619 | rc = PTR_ERR(tcp_ses->hostname); | 1633 | rc = PTR_ERR(tcp_ses->hostname); |
1620 | goto out_err; | 1634 | goto out_err_crypto_release; |
1621 | } | 1635 | } |
1622 | 1636 | ||
1623 | tcp_ses->noblocksnd = volume_info->noblocksnd; | 1637 | tcp_ses->noblocksnd = volume_info->noblocksnd; |
@@ -1661,7 +1675,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1661 | } | 1675 | } |
1662 | if (rc < 0) { | 1676 | if (rc < 0) { |
1663 | cERROR(1, "Error connecting to socket. Aborting operation"); | 1677 | cERROR(1, "Error connecting to socket. Aborting operation"); |
1664 | goto out_err; | 1678 | goto out_err_crypto_release; |
1665 | } | 1679 | } |
1666 | 1680 | ||
1667 | /* | 1681 | /* |
@@ -1675,7 +1689,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1675 | rc = PTR_ERR(tcp_ses->tsk); | 1689 | rc = PTR_ERR(tcp_ses->tsk); |
1676 | cERROR(1, "error %d create cifsd thread", rc); | 1690 | cERROR(1, "error %d create cifsd thread", rc); |
1677 | module_put(THIS_MODULE); | 1691 | module_put(THIS_MODULE); |
1678 | goto out_err; | 1692 | goto out_err_crypto_release; |
1679 | } | 1693 | } |
1680 | 1694 | ||
1681 | /* thread spawned, put it on the list */ | 1695 | /* thread spawned, put it on the list */ |
@@ -1687,6 +1701,9 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1687 | 1701 | ||
1688 | return tcp_ses; | 1702 | return tcp_ses; |
1689 | 1703 | ||
1704 | out_err_crypto_release: | ||
1705 | cifs_crypto_shash_release(tcp_ses); | ||
1706 | |||
1690 | out_err: | 1707 | out_err: |
1691 | if (tcp_ses) { | 1708 | if (tcp_ses) { |
1692 | if (!IS_ERR(tcp_ses->hostname)) | 1709 | if (!IS_ERR(tcp_ses->hostname)) |
@@ -1801,8 +1818,6 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | |||
1801 | if (ses == NULL) | 1818 | if (ses == NULL) |
1802 | goto get_ses_fail; | 1819 | goto get_ses_fail; |
1803 | 1820 | ||
1804 | ses->tilen = 0; | ||
1805 | ses->tiblob = NULL; | ||
1806 | /* new SMB session uses our server ref */ | 1821 | /* new SMB session uses our server ref */ |
1807 | ses->server = server; | 1822 | ses->server = server; |
1808 | if (server->addr.sockAddr6.sin6_family == AF_INET6) | 1823 | if (server->addr.sockAddr6.sin6_family == AF_INET6) |
@@ -1823,10 +1838,9 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | |||
1823 | goto get_ses_fail; | 1838 | goto get_ses_fail; |
1824 | } | 1839 | } |
1825 | if (volume_info->domainname) { | 1840 | if (volume_info->domainname) { |
1826 | int len = strlen(volume_info->domainname); | 1841 | ses->domainName = kstrdup(volume_info->domainname, GFP_KERNEL); |
1827 | ses->domainName = kmalloc(len + 1, GFP_KERNEL); | 1842 | if (!ses->domainName) |
1828 | if (ses->domainName) | 1843 | goto get_ses_fail; |
1829 | strcpy(ses->domainName, volume_info->domainname); | ||
1830 | } | 1844 | } |
1831 | ses->cred_uid = volume_info->cred_uid; | 1845 | ses->cred_uid = volume_info->cred_uid; |
1832 | ses->linux_uid = volume_info->linux_uid; | 1846 | ses->linux_uid = volume_info->linux_uid; |
@@ -2985,13 +2999,13 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
2985 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 2999 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
2986 | if ((global_secflags & CIFSSEC_MAY_LANMAN) && | 3000 | if ((global_secflags & CIFSSEC_MAY_LANMAN) && |
2987 | (ses->server->secType == LANMAN)) | 3001 | (ses->server->secType == LANMAN)) |
2988 | calc_lanman_hash(tcon->password, ses->cryptKey, | 3002 | calc_lanman_hash(tcon->password, ses->server->cryptkey, |
2989 | ses->server->secMode & | 3003 | ses->server->secMode & |
2990 | SECMODE_PW_ENCRYPT ? true : false, | 3004 | SECMODE_PW_ENCRYPT ? true : false, |
2991 | bcc_ptr); | 3005 | bcc_ptr); |
2992 | else | 3006 | else |
2993 | #endif /* CIFS_WEAK_PW_HASH */ | 3007 | #endif /* CIFS_WEAK_PW_HASH */ |
2994 | SMBNTencrypt(tcon->password, ses->cryptKey, bcc_ptr); | 3008 | SMBNTencrypt(tcon->password, ses->server->cryptkey, bcc_ptr); |
2995 | 3009 | ||
2996 | bcc_ptr += CIFS_SESS_KEY_SIZE; | 3010 | bcc_ptr += CIFS_SESS_KEY_SIZE; |
2997 | if (ses->capabilities & CAP_UNICODE) { | 3011 | if (ses->capabilities & CAP_UNICODE) { |
@@ -3178,10 +3192,11 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *ses, | |||
3178 | } else { | 3192 | } else { |
3179 | mutex_lock(&ses->server->srv_mutex); | 3193 | mutex_lock(&ses->server->srv_mutex); |
3180 | if (!server->session_estab) { | 3194 | if (!server->session_estab) { |
3181 | memcpy(&server->session_key.data, | 3195 | server->session_key.response = ses->auth_key.response; |
3182 | &ses->auth_key.data, ses->auth_key.len); | ||
3183 | server->session_key.len = ses->auth_key.len; | 3196 | server->session_key.len = ses->auth_key.len; |
3184 | ses->server->session_estab = true; | 3197 | server->sequence_number = 0x2; |
3198 | server->session_estab = true; | ||
3199 | ses->auth_key.response = NULL; | ||
3185 | } | 3200 | } |
3186 | mutex_unlock(&server->srv_mutex); | 3201 | mutex_unlock(&server->srv_mutex); |
3187 | 3202 | ||
@@ -3192,6 +3207,12 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *ses, | |||
3192 | spin_unlock(&GlobalMid_Lock); | 3207 | spin_unlock(&GlobalMid_Lock); |
3193 | } | 3208 | } |
3194 | 3209 | ||
3210 | kfree(ses->auth_key.response); | ||
3211 | ses->auth_key.response = NULL; | ||
3212 | ses->auth_key.len = 0; | ||
3213 | kfree(ses->ntlmssp); | ||
3214 | ses->ntlmssp = NULL; | ||
3215 | |||
3195 | return rc; | 3216 | return rc; |
3196 | } | 3217 | } |
3197 | 3218 | ||
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 45af003865d2..ae82159cf7fa 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -131,8 +131,7 @@ static inline int cifs_open_inode_helper(struct inode *inode, | |||
131 | /* BB no need to lock inode until after invalidate | 131 | /* BB no need to lock inode until after invalidate |
132 | since namei code should already have it locked? */ | 132 | since namei code should already have it locked? */ |
133 | rc = filemap_write_and_wait(inode->i_mapping); | 133 | rc = filemap_write_and_wait(inode->i_mapping); |
134 | if (rc != 0) | 134 | mapping_set_error(inode->i_mapping, rc); |
135 | pCifsInode->write_behind_rc = rc; | ||
136 | } | 135 | } |
137 | cFYI(1, "invalidating remote inode since open detected it " | 136 | cFYI(1, "invalidating remote inode since open detected it " |
138 | "changed"); | 137 | "changed"); |
@@ -232,6 +231,7 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file, | |||
232 | if (pCifsFile == NULL) | 231 | if (pCifsFile == NULL) |
233 | return pCifsFile; | 232 | return pCifsFile; |
234 | 233 | ||
234 | pCifsFile->count = 1; | ||
235 | pCifsFile->netfid = fileHandle; | 235 | pCifsFile->netfid = fileHandle; |
236 | pCifsFile->pid = current->tgid; | 236 | pCifsFile->pid = current->tgid; |
237 | pCifsFile->uid = current_fsuid(); | 237 | pCifsFile->uid = current_fsuid(); |
@@ -242,7 +242,6 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file, | |||
242 | mutex_init(&pCifsFile->fh_mutex); | 242 | mutex_init(&pCifsFile->fh_mutex); |
243 | mutex_init(&pCifsFile->lock_mutex); | 243 | mutex_init(&pCifsFile->lock_mutex); |
244 | INIT_LIST_HEAD(&pCifsFile->llist); | 244 | INIT_LIST_HEAD(&pCifsFile->llist); |
245 | atomic_set(&pCifsFile->count, 1); | ||
246 | INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break); | 245 | INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break); |
247 | 246 | ||
248 | spin_lock(&cifs_file_list_lock); | 247 | spin_lock(&cifs_file_list_lock); |
@@ -267,7 +266,8 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file, | |||
267 | 266 | ||
268 | /* | 267 | /* |
269 | * Release a reference on the file private data. This may involve closing | 268 | * Release a reference on the file private data. This may involve closing |
270 | * the filehandle out on the server. | 269 | * the filehandle out on the server. Must be called without holding |
270 | * cifs_file_list_lock. | ||
271 | */ | 271 | */ |
272 | void cifsFileInfo_put(struct cifsFileInfo *cifs_file) | 272 | void cifsFileInfo_put(struct cifsFileInfo *cifs_file) |
273 | { | 273 | { |
@@ -276,7 +276,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) | |||
276 | struct cifsLockInfo *li, *tmp; | 276 | struct cifsLockInfo *li, *tmp; |
277 | 277 | ||
278 | spin_lock(&cifs_file_list_lock); | 278 | spin_lock(&cifs_file_list_lock); |
279 | if (!atomic_dec_and_test(&cifs_file->count)) { | 279 | if (--cifs_file->count > 0) { |
280 | spin_unlock(&cifs_file_list_lock); | 280 | spin_unlock(&cifs_file_list_lock); |
281 | return; | 281 | return; |
282 | } | 282 | } |
@@ -605,8 +605,7 @@ reopen_success: | |||
605 | 605 | ||
606 | if (can_flush) { | 606 | if (can_flush) { |
607 | rc = filemap_write_and_wait(inode->i_mapping); | 607 | rc = filemap_write_and_wait(inode->i_mapping); |
608 | if (rc != 0) | 608 | mapping_set_error(inode->i_mapping, rc); |
609 | CIFS_I(inode)->write_behind_rc = rc; | ||
610 | 609 | ||
611 | pCifsInode->clientCanCacheAll = false; | 610 | pCifsInode->clientCanCacheAll = false; |
612 | pCifsInode->clientCanCacheRead = false; | 611 | pCifsInode->clientCanCacheRead = false; |
@@ -1353,6 +1352,7 @@ static int cifs_writepages(struct address_space *mapping, | |||
1353 | if (!experimEnabled && tcon->ses->server->secMode & | 1352 | if (!experimEnabled && tcon->ses->server->secMode & |
1354 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { | 1353 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { |
1355 | cifsFileInfo_put(open_file); | 1354 | cifsFileInfo_put(open_file); |
1355 | kfree(iov); | ||
1356 | return generic_writepages(mapping, wbc); | 1356 | return generic_writepages(mapping, wbc); |
1357 | } | 1357 | } |
1358 | cifsFileInfo_put(open_file); | 1358 | cifsFileInfo_put(open_file); |
@@ -1478,12 +1478,7 @@ retry: | |||
1478 | if (rc || bytes_written < bytes_to_write) { | 1478 | if (rc || bytes_written < bytes_to_write) { |
1479 | cERROR(1, "Write2 ret %d, wrote %d", | 1479 | cERROR(1, "Write2 ret %d, wrote %d", |
1480 | rc, bytes_written); | 1480 | rc, bytes_written); |
1481 | /* BB what if continued retry is | 1481 | mapping_set_error(mapping, rc); |
1482 | requested via mount flags? */ | ||
1483 | if (rc == -ENOSPC) | ||
1484 | set_bit(AS_ENOSPC, &mapping->flags); | ||
1485 | else | ||
1486 | set_bit(AS_EIO, &mapping->flags); | ||
1487 | } else { | 1482 | } else { |
1488 | cifs_stats_bytes_written(tcon, bytes_written); | 1483 | cifs_stats_bytes_written(tcon, bytes_written); |
1489 | } | 1484 | } |
@@ -1628,11 +1623,10 @@ int cifs_fsync(struct file *file, int datasync) | |||
1628 | 1623 | ||
1629 | rc = filemap_write_and_wait(inode->i_mapping); | 1624 | rc = filemap_write_and_wait(inode->i_mapping); |
1630 | if (rc == 0) { | 1625 | if (rc == 0) { |
1631 | rc = CIFS_I(inode)->write_behind_rc; | 1626 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
1632 | CIFS_I(inode)->write_behind_rc = 0; | 1627 | |
1633 | tcon = tlink_tcon(smbfile->tlink); | 1628 | tcon = tlink_tcon(smbfile->tlink); |
1634 | if (!rc && tcon && smbfile && | 1629 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) |
1635 | !(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) | ||
1636 | rc = CIFSSMBFlush(xid, tcon, smbfile->netfid); | 1630 | rc = CIFSSMBFlush(xid, tcon, smbfile->netfid); |
1637 | } | 1631 | } |
1638 | 1632 | ||
@@ -1677,21 +1671,8 @@ int cifs_flush(struct file *file, fl_owner_t id) | |||
1677 | struct inode *inode = file->f_path.dentry->d_inode; | 1671 | struct inode *inode = file->f_path.dentry->d_inode; |
1678 | int rc = 0; | 1672 | int rc = 0; |
1679 | 1673 | ||
1680 | /* Rather than do the steps manually: | 1674 | if (file->f_mode & FMODE_WRITE) |
1681 | lock the inode for writing | 1675 | rc = filemap_write_and_wait(inode->i_mapping); |
1682 | loop through pages looking for write behind data (dirty pages) | ||
1683 | coalesce into contiguous 16K (or smaller) chunks to write to server | ||
1684 | send to server (prefer in parallel) | ||
1685 | deal with writebehind errors | ||
1686 | unlock inode for writing | ||
1687 | filemapfdatawrite appears easier for the time being */ | ||
1688 | |||
1689 | rc = filemap_fdatawrite(inode->i_mapping); | ||
1690 | /* reset wb rc if we were able to write out dirty pages */ | ||
1691 | if (!rc) { | ||
1692 | rc = CIFS_I(inode)->write_behind_rc; | ||
1693 | CIFS_I(inode)->write_behind_rc = 0; | ||
1694 | } | ||
1695 | 1676 | ||
1696 | cFYI(1, "Flush inode %p file %p rc %d", inode, file, rc); | 1677 | cFYI(1, "Flush inode %p file %p rc %d", inode, file, rc); |
1697 | 1678 | ||
@@ -2270,7 +2251,7 @@ void cifs_oplock_break(struct work_struct *work) | |||
2270 | oplock_break); | 2251 | oplock_break); |
2271 | struct inode *inode = cfile->dentry->d_inode; | 2252 | struct inode *inode = cfile->dentry->d_inode; |
2272 | struct cifsInodeInfo *cinode = CIFS_I(inode); | 2253 | struct cifsInodeInfo *cinode = CIFS_I(inode); |
2273 | int rc, waitrc = 0; | 2254 | int rc = 0; |
2274 | 2255 | ||
2275 | if (inode && S_ISREG(inode->i_mode)) { | 2256 | if (inode && S_ISREG(inode->i_mode)) { |
2276 | if (cinode->clientCanCacheRead) | 2257 | if (cinode->clientCanCacheRead) |
@@ -2279,13 +2260,10 @@ void cifs_oplock_break(struct work_struct *work) | |||
2279 | break_lease(inode, O_WRONLY); | 2260 | break_lease(inode, O_WRONLY); |
2280 | rc = filemap_fdatawrite(inode->i_mapping); | 2261 | rc = filemap_fdatawrite(inode->i_mapping); |
2281 | if (cinode->clientCanCacheRead == 0) { | 2262 | if (cinode->clientCanCacheRead == 0) { |
2282 | waitrc = filemap_fdatawait(inode->i_mapping); | 2263 | rc = filemap_fdatawait(inode->i_mapping); |
2264 | mapping_set_error(inode->i_mapping, rc); | ||
2283 | invalidate_remote_inode(inode); | 2265 | invalidate_remote_inode(inode); |
2284 | } | 2266 | } |
2285 | if (!rc) | ||
2286 | rc = waitrc; | ||
2287 | if (rc) | ||
2288 | cinode->write_behind_rc = rc; | ||
2289 | cFYI(1, "Oplock flush inode %p rc %d", inode, rc); | 2267 | cFYI(1, "Oplock flush inode %p rc %d", inode, rc); |
2290 | } | 2268 | } |
2291 | 2269 | ||
@@ -2304,7 +2282,7 @@ void cifs_oplock_break(struct work_struct *work) | |||
2304 | /* | 2282 | /* |
2305 | * We might have kicked in before is_valid_oplock_break() | 2283 | * We might have kicked in before is_valid_oplock_break() |
2306 | * finished grabbing reference for us. Make sure it's done by | 2284 | * finished grabbing reference for us. Make sure it's done by |
2307 | * waiting for GlobalSMSSeslock. | 2285 | * waiting for cifs_file_list_lock. |
2308 | */ | 2286 | */ |
2309 | spin_lock(&cifs_file_list_lock); | 2287 | spin_lock(&cifs_file_list_lock); |
2310 | spin_unlock(&cifs_file_list_lock); | 2288 | spin_unlock(&cifs_file_list_lock); |
@@ -2312,6 +2290,7 @@ void cifs_oplock_break(struct work_struct *work) | |||
2312 | cifs_oplock_break_put(cfile); | 2290 | cifs_oplock_break_put(cfile); |
2313 | } | 2291 | } |
2314 | 2292 | ||
2293 | /* must be called while holding cifs_file_list_lock */ | ||
2315 | void cifs_oplock_break_get(struct cifsFileInfo *cfile) | 2294 | void cifs_oplock_break_get(struct cifsFileInfo *cfile) |
2316 | { | 2295 | { |
2317 | cifs_sb_active(cfile->dentry->d_sb); | 2296 | cifs_sb_active(cfile->dentry->d_sb); |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 94979309698a..39869c3c3efb 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -1682,8 +1682,7 @@ cifs_invalidate_mapping(struct inode *inode) | |||
1682 | /* write back any cached data */ | 1682 | /* write back any cached data */ |
1683 | if (inode->i_mapping && inode->i_mapping->nrpages != 0) { | 1683 | if (inode->i_mapping && inode->i_mapping->nrpages != 0) { |
1684 | rc = filemap_write_and_wait(inode->i_mapping); | 1684 | rc = filemap_write_and_wait(inode->i_mapping); |
1685 | if (rc) | 1685 | mapping_set_error(inode->i_mapping, rc); |
1686 | cifs_i->write_behind_rc = rc; | ||
1687 | } | 1686 | } |
1688 | invalidate_remote_inode(inode); | 1687 | invalidate_remote_inode(inode); |
1689 | cifs_fscache_reset_inode_cookie(inode); | 1688 | cifs_fscache_reset_inode_cookie(inode); |
@@ -1943,10 +1942,8 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | |||
1943 | * the flush returns error? | 1942 | * the flush returns error? |
1944 | */ | 1943 | */ |
1945 | rc = filemap_write_and_wait(inode->i_mapping); | 1944 | rc = filemap_write_and_wait(inode->i_mapping); |
1946 | if (rc != 0) { | 1945 | mapping_set_error(inode->i_mapping, rc); |
1947 | cifsInode->write_behind_rc = rc; | 1946 | rc = 0; |
1948 | rc = 0; | ||
1949 | } | ||
1950 | 1947 | ||
1951 | if (attrs->ia_valid & ATTR_SIZE) { | 1948 | if (attrs->ia_valid & ATTR_SIZE) { |
1952 | rc = cifs_set_file_size(inode, attrs, xid, full_path); | 1949 | rc = cifs_set_file_size(inode, attrs, xid, full_path); |
@@ -2087,10 +2084,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) | |||
2087 | * the flush returns error? | 2084 | * the flush returns error? |
2088 | */ | 2085 | */ |
2089 | rc = filemap_write_and_wait(inode->i_mapping); | 2086 | rc = filemap_write_and_wait(inode->i_mapping); |
2090 | if (rc != 0) { | 2087 | mapping_set_error(inode->i_mapping, rc); |
2091 | cifsInode->write_behind_rc = rc; | 2088 | rc = 0; |
2092 | rc = 0; | ||
2093 | } | ||
2094 | 2089 | ||
2095 | if (attrs->ia_valid & ATTR_SIZE) { | 2090 | if (attrs->ia_valid & ATTR_SIZE) { |
2096 | rc = cifs_set_file_size(inode, attrs, xid, full_path); | 2091 | rc = cifs_set_file_size(inode, attrs, xid, full_path); |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 1c681f6a6803..c4e296fe3518 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
@@ -577,7 +577,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) | |||
577 | * cifs_oplock_break_put() can't be called | 577 | * cifs_oplock_break_put() can't be called |
578 | * from here. Get reference after queueing | 578 | * from here. Get reference after queueing |
579 | * succeeded. cifs_oplock_break() will | 579 | * succeeded. cifs_oplock_break() will |
580 | * synchronize using GlobalSMSSeslock. | 580 | * synchronize using cifs_file_list_lock. |
581 | */ | 581 | */ |
582 | if (queue_work(system_nrt_wq, | 582 | if (queue_work(system_nrt_wq, |
583 | &netfile->oplock_break)) | 583 | &netfile->oplock_break)) |
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 2a11efd96592..7b01d3f6eed6 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c | |||
@@ -32,9 +32,6 @@ | |||
32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
33 | #include "cifs_spnego.h" | 33 | #include "cifs_spnego.h" |
34 | 34 | ||
35 | extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, | ||
36 | unsigned char *p24); | ||
37 | |||
38 | /* | 35 | /* |
39 | * Checks if this is the first smb session to be reconnected after | 36 | * Checks if this is the first smb session to be reconnected after |
40 | * the socket has been reestablished (so we know whether to use vc 0). | 37 | * the socket has been reestablished (so we know whether to use vc 0). |
@@ -402,23 +399,22 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, | |||
402 | return -EINVAL; | 399 | return -EINVAL; |
403 | } | 400 | } |
404 | 401 | ||
405 | memcpy(ses->cryptKey, pblob->Challenge, CIFS_CRYPTO_KEY_SIZE); | 402 | memcpy(ses->ntlmssp->cryptkey, pblob->Challenge, CIFS_CRYPTO_KEY_SIZE); |
406 | /* BB we could decode pblob->NegotiateFlags; some may be useful */ | 403 | /* BB we could decode pblob->NegotiateFlags; some may be useful */ |
407 | /* In particular we can examine sign flags */ | 404 | /* In particular we can examine sign flags */ |
408 | /* BB spec says that if AvId field of MsvAvTimestamp is populated then | 405 | /* BB spec says that if AvId field of MsvAvTimestamp is populated then |
409 | we must set the MIC field of the AUTHENTICATE_MESSAGE */ | 406 | we must set the MIC field of the AUTHENTICATE_MESSAGE */ |
410 | 407 | ses->ntlmssp->server_flags = le32_to_cpu(pblob->NegotiateFlags); | |
411 | tioffset = cpu_to_le16(pblob->TargetInfoArray.BufferOffset); | 408 | tioffset = cpu_to_le16(pblob->TargetInfoArray.BufferOffset); |
412 | tilen = cpu_to_le16(pblob->TargetInfoArray.Length); | 409 | tilen = cpu_to_le16(pblob->TargetInfoArray.Length); |
413 | ses->tilen = tilen; | 410 | if (tilen) { |
414 | if (ses->tilen) { | 411 | ses->auth_key.response = kmalloc(tilen, GFP_KERNEL); |
415 | ses->tiblob = kmalloc(tilen, GFP_KERNEL); | 412 | if (!ses->auth_key.response) { |
416 | if (!ses->tiblob) { | ||
417 | cERROR(1, "Challenge target info allocation failure"); | 413 | cERROR(1, "Challenge target info allocation failure"); |
418 | ses->tilen = 0; | ||
419 | return -ENOMEM; | 414 | return -ENOMEM; |
420 | } | 415 | } |
421 | memcpy(ses->tiblob, bcc_ptr + tioffset, ses->tilen); | 416 | memcpy(ses->auth_key.response, bcc_ptr + tioffset, tilen); |
417 | ses->auth_key.len = tilen; | ||
422 | } | 418 | } |
423 | 419 | ||
424 | return 0; | 420 | return 0; |
@@ -443,10 +439,12 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, | |||
443 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | | 439 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | |
444 | NTLMSSP_NEGOTIATE_NTLM; | 440 | NTLMSSP_NEGOTIATE_NTLM; |
445 | if (ses->server->secMode & | 441 | if (ses->server->secMode & |
446 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | 442 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { |
447 | flags |= NTLMSSP_NEGOTIATE_SIGN; | 443 | flags |= NTLMSSP_NEGOTIATE_SIGN; |
448 | if (ses->server->secMode & SECMODE_SIGN_REQUIRED) | 444 | if (!ses->server->session_estab) |
449 | flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; | 445 | flags |= NTLMSSP_NEGOTIATE_KEY_XCH | |
446 | NTLMSSP_NEGOTIATE_EXTENDED_SEC; | ||
447 | } | ||
450 | 448 | ||
451 | sec_blob->NegotiateFlags |= cpu_to_le32(flags); | 449 | sec_blob->NegotiateFlags |= cpu_to_le32(flags); |
452 | 450 | ||
@@ -469,11 +467,9 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
469 | const struct nls_table *nls_cp) | 467 | const struct nls_table *nls_cp) |
470 | { | 468 | { |
471 | int rc; | 469 | int rc; |
472 | unsigned int size; | ||
473 | AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer; | 470 | AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer; |
474 | __u32 flags; | 471 | __u32 flags; |
475 | unsigned char *tmp; | 472 | unsigned char *tmp; |
476 | struct ntlmv2_resp ntlmv2_response = {}; | ||
477 | 473 | ||
478 | memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); | 474 | memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); |
479 | sec_blob->MessageType = NtLmAuthenticate; | 475 | sec_blob->MessageType = NtLmAuthenticate; |
@@ -497,25 +493,19 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
497 | sec_blob->LmChallengeResponse.MaximumLength = 0; | 493 | sec_blob->LmChallengeResponse.MaximumLength = 0; |
498 | 494 | ||
499 | sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer); | 495 | sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer); |
500 | rc = setup_ntlmv2_rsp(ses, (char *)&ntlmv2_response, nls_cp); | 496 | rc = setup_ntlmv2_rsp(ses, nls_cp); |
501 | if (rc) { | 497 | if (rc) { |
502 | cERROR(1, "Error %d during NTLMSSP authentication", rc); | 498 | cERROR(1, "Error %d during NTLMSSP authentication", rc); |
503 | goto setup_ntlmv2_ret; | 499 | goto setup_ntlmv2_ret; |
504 | } | 500 | } |
505 | size = sizeof(struct ntlmv2_resp); | 501 | memcpy(tmp, ses->auth_key.response + CIFS_SESS_KEY_SIZE, |
506 | memcpy(tmp, (char *)&ntlmv2_response, size); | 502 | ses->auth_key.len - CIFS_SESS_KEY_SIZE); |
507 | tmp += size; | 503 | tmp += ses->auth_key.len - CIFS_SESS_KEY_SIZE; |
508 | if (ses->tilen > 0) { | ||
509 | memcpy(tmp, ses->tiblob, ses->tilen); | ||
510 | tmp += ses->tilen; | ||
511 | } | ||
512 | 504 | ||
513 | sec_blob->NtChallengeResponse.Length = cpu_to_le16(size + ses->tilen); | 505 | sec_blob->NtChallengeResponse.Length = |
506 | cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE); | ||
514 | sec_blob->NtChallengeResponse.MaximumLength = | 507 | sec_blob->NtChallengeResponse.MaximumLength = |
515 | cpu_to_le16(size + ses->tilen); | 508 | cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE); |
516 | kfree(ses->tiblob); | ||
517 | ses->tiblob = NULL; | ||
518 | ses->tilen = 0; | ||
519 | 509 | ||
520 | if (ses->domainName == NULL) { | 510 | if (ses->domainName == NULL) { |
521 | sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); | 511 | sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); |
@@ -554,9 +544,19 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
554 | sec_blob->WorkstationName.MaximumLength = 0; | 544 | sec_blob->WorkstationName.MaximumLength = 0; |
555 | tmp += 2; | 545 | tmp += 2; |
556 | 546 | ||
557 | sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); | 547 | if ((ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) && |
558 | sec_blob->SessionKey.Length = 0; | 548 | !calc_seckey(ses)) { |
559 | sec_blob->SessionKey.MaximumLength = 0; | 549 | memcpy(tmp, ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE); |
550 | sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); | ||
551 | sec_blob->SessionKey.Length = cpu_to_le16(CIFS_CPHTXT_SIZE); | ||
552 | sec_blob->SessionKey.MaximumLength = | ||
553 | cpu_to_le16(CIFS_CPHTXT_SIZE); | ||
554 | tmp += CIFS_CPHTXT_SIZE; | ||
555 | } else { | ||
556 | sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); | ||
557 | sec_blob->SessionKey.Length = 0; | ||
558 | sec_blob->SessionKey.MaximumLength = 0; | ||
559 | } | ||
560 | 560 | ||
561 | setup_ntlmv2_ret: | 561 | setup_ntlmv2_ret: |
562 | *buflen = tmp - pbuffer; | 562 | *buflen = tmp - pbuffer; |
@@ -600,8 +600,16 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
600 | return -EINVAL; | 600 | return -EINVAL; |
601 | 601 | ||
602 | type = ses->server->secType; | 602 | type = ses->server->secType; |
603 | |||
604 | cFYI(1, "sess setup type %d", type); | 603 | cFYI(1, "sess setup type %d", type); |
604 | if (type == RawNTLMSSP) { | ||
605 | /* if memory allocation is successful, caller of this function | ||
606 | * frees it. | ||
607 | */ | ||
608 | ses->ntlmssp = kmalloc(sizeof(struct ntlmssp_auth), GFP_KERNEL); | ||
609 | if (!ses->ntlmssp) | ||
610 | return -ENOMEM; | ||
611 | } | ||
612 | |||
605 | ssetup_ntlmssp_authenticate: | 613 | ssetup_ntlmssp_authenticate: |
606 | if (phase == NtLmChallenge) | 614 | if (phase == NtLmChallenge) |
607 | phase = NtLmAuthenticate; /* if ntlmssp, now final phase */ | 615 | phase = NtLmAuthenticate; /* if ntlmssp, now final phase */ |
@@ -666,10 +674,14 @@ ssetup_ntlmssp_authenticate: | |||
666 | /* no capabilities flags in old lanman negotiation */ | 674 | /* no capabilities flags in old lanman negotiation */ |
667 | 675 | ||
668 | pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE); | 676 | pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE); |
669 | /* BB calculate hash with password */ | ||
670 | /* and copy into bcc */ | ||
671 | 677 | ||
672 | calc_lanman_hash(ses->password, ses->cryptKey, | 678 | /* Calculate hash with password and copy into bcc_ptr. |
679 | * Encryption Key (stored as in cryptkey) gets used if the | ||
680 | * security mode bit in Negottiate Protocol response states | ||
681 | * to use challenge/response method (i.e. Password bit is 1). | ||
682 | */ | ||
683 | |||
684 | calc_lanman_hash(ses->password, ses->server->cryptkey, | ||
673 | ses->server->secMode & SECMODE_PW_ENCRYPT ? | 685 | ses->server->secMode & SECMODE_PW_ENCRYPT ? |
674 | true : false, lnm_session_key); | 686 | true : false, lnm_session_key); |
675 | 687 | ||
@@ -687,24 +699,27 @@ ssetup_ntlmssp_authenticate: | |||
687 | ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); | 699 | ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); |
688 | #endif | 700 | #endif |
689 | } else if (type == NTLM) { | 701 | } else if (type == NTLM) { |
690 | char ntlm_session_key[CIFS_SESS_KEY_SIZE]; | ||
691 | |||
692 | pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); | 702 | pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); |
693 | pSMB->req_no_secext.CaseInsensitivePasswordLength = | 703 | pSMB->req_no_secext.CaseInsensitivePasswordLength = |
694 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | 704 | cpu_to_le16(CIFS_AUTH_RESP_SIZE); |
695 | pSMB->req_no_secext.CaseSensitivePasswordLength = | 705 | pSMB->req_no_secext.CaseSensitivePasswordLength = |
696 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | 706 | cpu_to_le16(CIFS_AUTH_RESP_SIZE); |
707 | |||
708 | /* calculate ntlm response and session key */ | ||
709 | rc = setup_ntlm_response(ses); | ||
710 | if (rc) { | ||
711 | cERROR(1, "Error %d during NTLM authentication", rc); | ||
712 | goto ssetup_exit; | ||
713 | } | ||
697 | 714 | ||
698 | /* calculate session key */ | 715 | /* copy ntlm response */ |
699 | SMBNTencrypt(ses->password, ses->cryptKey, ntlm_session_key); | 716 | memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE, |
717 | CIFS_AUTH_RESP_SIZE); | ||
718 | bcc_ptr += CIFS_AUTH_RESP_SIZE; | ||
719 | memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE, | ||
720 | CIFS_AUTH_RESP_SIZE); | ||
721 | bcc_ptr += CIFS_AUTH_RESP_SIZE; | ||
700 | 722 | ||
701 | cifs_calculate_session_key(&ses->auth_key, | ||
702 | ntlm_session_key, ses->password); | ||
703 | /* copy session key */ | ||
704 | memcpy(bcc_ptr, (char *)ntlm_session_key, CIFS_SESS_KEY_SIZE); | ||
705 | bcc_ptr += CIFS_SESS_KEY_SIZE; | ||
706 | memcpy(bcc_ptr, (char *)ntlm_session_key, CIFS_SESS_KEY_SIZE); | ||
707 | bcc_ptr += CIFS_SESS_KEY_SIZE; | ||
708 | if (ses->capabilities & CAP_UNICODE) { | 723 | if (ses->capabilities & CAP_UNICODE) { |
709 | /* unicode strings must be word aligned */ | 724 | /* unicode strings must be word aligned */ |
710 | if (iov[0].iov_len % 2) { | 725 | if (iov[0].iov_len % 2) { |
@@ -715,47 +730,26 @@ ssetup_ntlmssp_authenticate: | |||
715 | } else | 730 | } else |
716 | ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); | 731 | ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); |
717 | } else if (type == NTLMv2) { | 732 | } else if (type == NTLMv2) { |
718 | char *v2_sess_key = | ||
719 | kmalloc(sizeof(struct ntlmv2_resp), GFP_KERNEL); | ||
720 | |||
721 | /* BB FIXME change all users of v2_sess_key to | ||
722 | struct ntlmv2_resp */ | ||
723 | |||
724 | if (v2_sess_key == NULL) { | ||
725 | rc = -ENOMEM; | ||
726 | goto ssetup_exit; | ||
727 | } | ||
728 | |||
729 | pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); | 733 | pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); |
730 | 734 | ||
731 | /* LM2 password would be here if we supported it */ | 735 | /* LM2 password would be here if we supported it */ |
732 | pSMB->req_no_secext.CaseInsensitivePasswordLength = 0; | 736 | pSMB->req_no_secext.CaseInsensitivePasswordLength = 0; |
733 | /* cpu_to_le16(LM2_SESS_KEY_SIZE); */ | ||
734 | 737 | ||
735 | /* calculate session key */ | 738 | /* calculate nlmv2 response and session key */ |
736 | rc = setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp); | 739 | rc = setup_ntlmv2_rsp(ses, nls_cp); |
737 | if (rc) { | 740 | if (rc) { |
738 | cERROR(1, "Error %d during NTLMv2 authentication", rc); | 741 | cERROR(1, "Error %d during NTLMv2 authentication", rc); |
739 | kfree(v2_sess_key); | ||
740 | goto ssetup_exit; | 742 | goto ssetup_exit; |
741 | } | 743 | } |
742 | memcpy(bcc_ptr, (char *)v2_sess_key, | 744 | memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE, |
743 | sizeof(struct ntlmv2_resp)); | 745 | ses->auth_key.len - CIFS_SESS_KEY_SIZE); |
744 | bcc_ptr += sizeof(struct ntlmv2_resp); | 746 | bcc_ptr += ses->auth_key.len - CIFS_SESS_KEY_SIZE; |
745 | kfree(v2_sess_key); | 747 | |
746 | /* set case sensitive password length after tilen may get | 748 | /* set case sensitive password length after tilen may get |
747 | * assigned, tilen is 0 otherwise. | 749 | * assigned, tilen is 0 otherwise. |
748 | */ | 750 | */ |
749 | pSMB->req_no_secext.CaseSensitivePasswordLength = | 751 | pSMB->req_no_secext.CaseSensitivePasswordLength = |
750 | cpu_to_le16(sizeof(struct ntlmv2_resp) + ses->tilen); | 752 | cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE); |
751 | if (ses->tilen > 0) { | ||
752 | memcpy(bcc_ptr, ses->tiblob, ses->tilen); | ||
753 | bcc_ptr += ses->tilen; | ||
754 | /* we never did allocate ses->domainName to free */ | ||
755 | kfree(ses->tiblob); | ||
756 | ses->tiblob = NULL; | ||
757 | ses->tilen = 0; | ||
758 | } | ||
759 | 753 | ||
760 | if (ses->capabilities & CAP_UNICODE) { | 754 | if (ses->capabilities & CAP_UNICODE) { |
761 | if (iov[0].iov_len % 2) { | 755 | if (iov[0].iov_len % 2) { |
@@ -768,6 +762,7 @@ ssetup_ntlmssp_authenticate: | |||
768 | } else if (type == Kerberos) { | 762 | } else if (type == Kerberos) { |
769 | #ifdef CONFIG_CIFS_UPCALL | 763 | #ifdef CONFIG_CIFS_UPCALL |
770 | struct cifs_spnego_msg *msg; | 764 | struct cifs_spnego_msg *msg; |
765 | |||
771 | spnego_key = cifs_get_spnego_key(ses); | 766 | spnego_key = cifs_get_spnego_key(ses); |
772 | if (IS_ERR(spnego_key)) { | 767 | if (IS_ERR(spnego_key)) { |
773 | rc = PTR_ERR(spnego_key); | 768 | rc = PTR_ERR(spnego_key); |
@@ -785,16 +780,17 @@ ssetup_ntlmssp_authenticate: | |||
785 | rc = -EKEYREJECTED; | 780 | rc = -EKEYREJECTED; |
786 | goto ssetup_exit; | 781 | goto ssetup_exit; |
787 | } | 782 | } |
788 | /* bail out if key is too long */ | 783 | |
789 | if (msg->sesskey_len > | 784 | ses->auth_key.response = kmalloc(msg->sesskey_len, GFP_KERNEL); |
790 | sizeof(ses->auth_key.data.krb5)) { | 785 | if (!ses->auth_key.response) { |
791 | cERROR(1, "Kerberos signing key too long (%u bytes)", | 786 | cERROR(1, "Kerberos can't allocate (%u bytes) memory", |
792 | msg->sesskey_len); | 787 | msg->sesskey_len); |
793 | rc = -EOVERFLOW; | 788 | rc = -ENOMEM; |
794 | goto ssetup_exit; | 789 | goto ssetup_exit; |
795 | } | 790 | } |
791 | memcpy(ses->auth_key.response, msg->data, msg->sesskey_len); | ||
796 | ses->auth_key.len = msg->sesskey_len; | 792 | ses->auth_key.len = msg->sesskey_len; |
797 | memcpy(ses->auth_key.data.krb5, msg->data, msg->sesskey_len); | 793 | |
798 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | 794 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; |
799 | capabilities |= CAP_EXTENDED_SECURITY; | 795 | capabilities |= CAP_EXTENDED_SECURITY; |
800 | pSMB->req.Capabilities = cpu_to_le32(capabilities); | 796 | pSMB->req.Capabilities = cpu_to_le32(capabilities); |
@@ -897,8 +893,6 @@ ssetup_ntlmssp_authenticate: | |||
897 | CIFS_STD_OP /* not long */ | CIFS_LOG_ERROR); | 893 | CIFS_STD_OP /* not long */ | CIFS_LOG_ERROR); |
898 | /* SMB request buf freed in SendReceive2 */ | 894 | /* SMB request buf freed in SendReceive2 */ |
899 | 895 | ||
900 | cFYI(1, "ssetup rc from sendrecv2 is %d", rc); | ||
901 | |||
902 | pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base; | 896 | pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base; |
903 | smb_buf = (struct smb_hdr *)iov[0].iov_base; | 897 | smb_buf = (struct smb_hdr *)iov[0].iov_base; |
904 | 898 | ||
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index a66c91eb6eb4..e0588cdf4cc5 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -543,7 +543,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
543 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | | 543 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | |
544 | SECMODE_SIGN_ENABLED))) { | 544 | SECMODE_SIGN_ENABLED))) { |
545 | rc = cifs_verify_signature(midQ->resp_buf, | 545 | rc = cifs_verify_signature(midQ->resp_buf, |
546 | &ses->server->session_key, | 546 | ses->server, |
547 | midQ->sequence_number+1); | 547 | midQ->sequence_number+1); |
548 | if (rc) { | 548 | if (rc) { |
549 | cERROR(1, "Unexpected SMB signature"); | 549 | cERROR(1, "Unexpected SMB signature"); |
@@ -731,7 +731,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
731 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | | 731 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | |
732 | SECMODE_SIGN_ENABLED))) { | 732 | SECMODE_SIGN_ENABLED))) { |
733 | rc = cifs_verify_signature(out_buf, | 733 | rc = cifs_verify_signature(out_buf, |
734 | &ses->server->session_key, | 734 | ses->server, |
735 | midQ->sequence_number+1); | 735 | midQ->sequence_number+1); |
736 | if (rc) { | 736 | if (rc) { |
737 | cERROR(1, "Unexpected SMB signature"); | 737 | cERROR(1, "Unexpected SMB signature"); |
@@ -981,7 +981,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
981 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | | 981 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | |
982 | SECMODE_SIGN_ENABLED))) { | 982 | SECMODE_SIGN_ENABLED))) { |
983 | rc = cifs_verify_signature(out_buf, | 983 | rc = cifs_verify_signature(out_buf, |
984 | &ses->server->session_key, | 984 | ses->server, |
985 | midQ->sequence_number+1); | 985 | midQ->sequence_number+1); |
986 | if (rc) { | 986 | if (rc) { |
987 | cERROR(1, "Unexpected SMB signature"); | 987 | cERROR(1, "Unexpected SMB signature"); |