diff options
-rw-r--r-- | fs/cifs/cifsencrypt.c | 121 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifspdu.h | 1 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 16 | ||||
-rw-r--r-- | fs/cifs/connect.c | 2 | ||||
-rw-r--r-- | fs/cifs/ntlmssp.h | 15 | ||||
-rw-r--r-- | fs/cifs/sess.c | 119 |
8 files changed, 225 insertions, 53 deletions
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index eed70cae1275..730038a12982 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include "md5.h" | 27 | #include "md5.h" |
28 | #include "cifs_unicode.h" | 28 | #include "cifs_unicode.h" |
29 | #include "cifsproto.h" | 29 | #include "cifsproto.h" |
30 | #include "ntlmssp.h" | ||
30 | #include <linux/ctype.h> | 31 | #include <linux/ctype.h> |
31 | #include <linux/random.h> | 32 | #include <linux/random.h> |
32 | 33 | ||
@@ -262,6 +263,87 @@ void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, | |||
262 | } | 263 | } |
263 | #endif /* CIFS_WEAK_PW_HASH */ | 264 | #endif /* CIFS_WEAK_PW_HASH */ |
264 | 265 | ||
266 | /* This is just a filler for ntlmv2 type of security mechanisms. | ||
267 | * Older servers are not very particular about the contents of av pairs | ||
268 | * in the blob and for sec mechs like ntlmv2, there is no negotiation | ||
269 | * as in ntlmssp, so unless domain and server netbios and dns names | ||
270 | * are specified, there is no way to obtain name. In case of ntlmssp, | ||
271 | * server provides that info in type 2 challenge packet | ||
272 | */ | ||
273 | static int | ||
274 | build_avpair_blob(struct cifsSesInfo *ses) | ||
275 | { | ||
276 | struct ntlmssp2_name *attrptr; | ||
277 | |||
278 | ses->tilen = 2 * sizeof(struct ntlmssp2_name); | ||
279 | ses->tiblob = kzalloc(ses->tilen, GFP_KERNEL); | ||
280 | if (!ses->tiblob) { | ||
281 | ses->tilen = 0; | ||
282 | cERROR(1, "Challenge target info allocation failure"); | ||
283 | return -ENOMEM; | ||
284 | } | ||
285 | attrptr = (struct ntlmssp2_name *) ses->tiblob; | ||
286 | attrptr->type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE); | ||
287 | |||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | /* Server has provided av pairs/target info in the type 2 challenge | ||
292 | * packet and we have plucked it and stored within smb session. | ||
293 | * We parse that blob here to find netbios domain name to be used | ||
294 | * as part of ntlmv2 authentication (in Target String), if not already | ||
295 | * specified on the command line. | ||
296 | * If this function returns without any error but without fetching | ||
297 | * domain name, authentication may fail against some server but | ||
298 | * may not fail against other (those who are not very particular | ||
299 | * about target string i.e. for some, just user name might suffice. | ||
300 | */ | ||
301 | static int | ||
302 | find_domain_name(struct cifsSesInfo *ses) | ||
303 | { | ||
304 | unsigned int attrsize; | ||
305 | unsigned int type; | ||
306 | unsigned int onesize = sizeof(struct ntlmssp2_name); | ||
307 | unsigned char *blobptr; | ||
308 | unsigned char *blobend; | ||
309 | struct ntlmssp2_name *attrptr; | ||
310 | |||
311 | if (!ses->tilen || !ses->tiblob) | ||
312 | return 0; | ||
313 | |||
314 | blobptr = ses->tiblob; | ||
315 | blobend = ses->tiblob + ses->tilen; | ||
316 | |||
317 | while (blobptr + onesize < blobend) { | ||
318 | attrptr = (struct ntlmssp2_name *) blobptr; | ||
319 | type = le16_to_cpu(attrptr->type); | ||
320 | if (type == NTLMSSP_AV_EOL) | ||
321 | break; | ||
322 | blobptr += 2; /* advance attr type */ | ||
323 | attrsize = le16_to_cpu(attrptr->length); | ||
324 | blobptr += 2; /* advance attr size */ | ||
325 | if (blobptr + attrsize > blobend) | ||
326 | break; | ||
327 | if (type == NTLMSSP_AV_NB_DOMAIN_NAME) { | ||
328 | if (!attrsize) | ||
329 | break; | ||
330 | if (!ses->domainName) { | ||
331 | ses->domainName = | ||
332 | kmalloc(attrsize + 1, GFP_KERNEL); | ||
333 | if (!ses->domainName) | ||
334 | return -ENOMEM; | ||
335 | cifs_from_ucs2(ses->domainName, | ||
336 | (__le16 *)blobptr, attrsize, attrsize, | ||
337 | load_nls_default(), false); | ||
338 | break; | ||
339 | } | ||
340 | } | ||
341 | blobptr += attrsize; /* advance attr value */ | ||
342 | } | ||
343 | |||
344 | return 0; | ||
345 | } | ||
346 | |||
265 | static int calc_ntlmv2_hash(struct cifsSesInfo *ses, | 347 | static int calc_ntlmv2_hash(struct cifsSesInfo *ses, |
266 | const struct nls_table *nls_cp) | 348 | const struct nls_table *nls_cp) |
267 | { | 349 | { |
@@ -321,7 +403,8 @@ calc_exit_2: | |||
321 | return rc; | 403 | return rc; |
322 | } | 404 | } |
323 | 405 | ||
324 | void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, | 406 | int |
407 | setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, | ||
325 | const struct nls_table *nls_cp) | 408 | const struct nls_table *nls_cp) |
326 | { | 409 | { |
327 | int rc; | 410 | int rc; |
@@ -333,15 +416,29 @@ void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, | |||
333 | buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | 416 | buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); |
334 | get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); | 417 | get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); |
335 | buf->reserved2 = 0; | 418 | buf->reserved2 = 0; |
336 | buf->names[0].type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE); | 419 | |
337 | buf->names[0].length = 0; | 420 | if (ses->server->secType == RawNTLMSSP) { |
338 | buf->names[1].type = 0; | 421 | if (!ses->domainName) { |
339 | buf->names[1].length = 0; | 422 | rc = find_domain_name(ses); |
423 | if (rc) { | ||
424 | cERROR(1, "error %d finding domain name", rc); | ||
425 | goto setup_ntlmv2_rsp_ret; | ||
426 | } | ||
427 | } | ||
428 | } else { | ||
429 | rc = build_avpair_blob(ses); | ||
430 | if (rc) { | ||
431 | cERROR(1, "error %d building av pair blob", rc); | ||
432 | return rc; | ||
433 | } | ||
434 | } | ||
340 | 435 | ||
341 | /* calculate buf->ntlmv2_hash */ | 436 | /* calculate buf->ntlmv2_hash */ |
342 | rc = calc_ntlmv2_hash(ses, nls_cp); | 437 | rc = calc_ntlmv2_hash(ses, nls_cp); |
343 | if (rc) | 438 | if (rc) { |
344 | cERROR(1, "could not get v2 hash rc %d", rc); | 439 | cERROR(1, "could not get v2 hash rc %d", rc); |
440 | goto setup_ntlmv2_rsp_ret; | ||
441 | } | ||
345 | CalcNTLMv2_response(ses, resp_buf); | 442 | CalcNTLMv2_response(ses, resp_buf); |
346 | 443 | ||
347 | /* now calculate the MAC key for NTLMv2 */ | 444 | /* now calculate the MAC key for NTLMv2 */ |
@@ -352,6 +449,15 @@ void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, | |||
352 | memcpy(&ses->server->session_key.data.ntlmv2.resp, resp_buf, | 449 | memcpy(&ses->server->session_key.data.ntlmv2.resp, resp_buf, |
353 | sizeof(struct ntlmv2_resp)); | 450 | sizeof(struct ntlmv2_resp)); |
354 | ses->server->session_key.len = 16 + sizeof(struct ntlmv2_resp); | 451 | ses->server->session_key.len = 16 + sizeof(struct ntlmv2_resp); |
452 | |||
453 | return 0; | ||
454 | |||
455 | setup_ntlmv2_rsp_ret: | ||
456 | kfree(ses->tiblob); | ||
457 | ses->tiblob = NULL; | ||
458 | ses->tilen = 0; | ||
459 | |||
460 | return rc; | ||
355 | } | 461 | } |
356 | 462 | ||
357 | void CalcNTLMv2_response(const struct cifsSesInfo *ses, | 463 | void CalcNTLMv2_response(const struct cifsSesInfo *ses, |
@@ -365,6 +471,9 @@ void CalcNTLMv2_response(const struct cifsSesInfo *ses, | |||
365 | hmac_md5_update(v2_session_response+8, | 471 | hmac_md5_update(v2_session_response+8, |
366 | sizeof(struct ntlmv2_resp) - 8, &context); | 472 | sizeof(struct ntlmv2_resp) - 8, &context); |
367 | 473 | ||
474 | if (ses->tilen) | ||
475 | hmac_md5_update(ses->tiblob, ses->tilen, &context); | ||
476 | |||
368 | hmac_md5_final(v2_session_response, &context); | 477 | hmac_md5_final(v2_session_response, &context); |
369 | /* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */ | 478 | /* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */ |
370 | } | 479 | } |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 14dfa9a067e5..c68f31cf4550 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -222,6 +222,8 @@ struct cifsSesInfo { | |||
222 | char userName[MAX_USERNAME_SIZE + 1]; | 222 | char userName[MAX_USERNAME_SIZE + 1]; |
223 | char *domainName; | 223 | char *domainName; |
224 | char *password; | 224 | char *password; |
225 | unsigned int tilen; /* length of the target info blob */ | ||
226 | unsigned char *tiblob; /* target info blob in challenge response */ | ||
225 | bool need_reconnect:1; /* connection reset, uid now invalid */ | 227 | bool need_reconnect:1; /* connection reset, uid now invalid */ |
226 | }; | 228 | }; |
227 | /* no more than one of the following three session flags may be set */ | 229 | /* no more than one of the following three session flags may be set */ |
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 14d036d8db11..b0f4b5656d4c 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h | |||
@@ -663,7 +663,6 @@ struct ntlmv2_resp { | |||
663 | __le64 time; | 663 | __le64 time; |
664 | __u64 client_chal; /* random */ | 664 | __u64 client_chal; /* random */ |
665 | __u32 reserved2; | 665 | __u32 reserved2; |
666 | struct ntlmssp2_name names[2]; | ||
667 | /* array of name entries could follow ending in minimum 4 byte struct */ | 666 | /* array of name entries could follow ending in minimum 4 byte struct */ |
668 | } __attribute__((packed)); | 667 | } __attribute__((packed)); |
669 | 668 | ||
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 099fd6173e01..588612867451 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -368,7 +368,7 @@ extern int cifs_verify_signature(struct smb_hdr *, | |||
368 | extern int cifs_calculate_session_key(struct session_key *key, const char *rn, | 368 | extern int cifs_calculate_session_key(struct session_key *key, const char *rn, |
369 | const char *pass); | 369 | const char *pass); |
370 | extern void CalcNTLMv2_response(const struct cifsSesInfo *, char *); | 370 | extern void CalcNTLMv2_response(const struct cifsSesInfo *, char *); |
371 | extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *, | 371 | extern int setup_ntlmv2_rsp(struct cifsSesInfo *, char *, |
372 | const struct nls_table *); | 372 | const struct nls_table *); |
373 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 373 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
374 | extern void calc_lanman_hash(const char *password, const char *cryptkey, | 374 | extern void calc_lanman_hash(const char *password, const char *cryptkey, |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index c65c3419dd37..13c854e41073 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -603,13 +603,15 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
603 | rc = 0; | 603 | rc = 0; |
604 | else | 604 | else |
605 | rc = -EINVAL; | 605 | rc = -EINVAL; |
606 | 606 | if (server->secType == Kerberos) { | |
607 | if (server->sec_kerberos || server->sec_mskerberos) | 607 | if (!server->sec_kerberos && |
608 | server->secType = Kerberos; | 608 | !server->sec_mskerberos) |
609 | else if (server->sec_ntlmssp) | 609 | rc = -EOPNOTSUPP; |
610 | server->secType = RawNTLMSSP; | 610 | } else if (server->secType == RawNTLMSSP) { |
611 | else | 611 | if (!server->sec_ntlmssp) |
612 | rc = -EOPNOTSUPP; | 612 | rc = -EOPNOTSUPP; |
613 | } else | ||
614 | rc = -EOPNOTSUPP; | ||
613 | } | 615 | } |
614 | } else | 616 | } else |
615 | server->capabilities &= ~CAP_EXTENDED_SECURITY; | 617 | server->capabilities &= ~CAP_EXTENDED_SECURITY; |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 88c84a38bccb..c99760a523bf 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -1740,6 +1740,8 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | |||
1740 | if (ses == NULL) | 1740 | if (ses == NULL) |
1741 | goto get_ses_fail; | 1741 | goto get_ses_fail; |
1742 | 1742 | ||
1743 | ses->tilen = 0; | ||
1744 | ses->tiblob = NULL; | ||
1743 | /* new SMB session uses our server ref */ | 1745 | /* new SMB session uses our server ref */ |
1744 | ses->server = server; | 1746 | ses->server = server; |
1745 | if (server->addr.sockAddr6.sin6_family == AF_INET6) | 1747 | if (server->addr.sockAddr6.sin6_family == AF_INET6) |
diff --git a/fs/cifs/ntlmssp.h b/fs/cifs/ntlmssp.h index 49c9a4e75319..5d52e4a3b1ed 100644 --- a/fs/cifs/ntlmssp.h +++ b/fs/cifs/ntlmssp.h | |||
@@ -61,6 +61,21 @@ | |||
61 | #define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000 | 61 | #define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000 |
62 | #define NTLMSSP_NEGOTIATE_56 0x80000000 | 62 | #define NTLMSSP_NEGOTIATE_56 0x80000000 |
63 | 63 | ||
64 | /* Define AV Pair Field IDs */ | ||
65 | enum av_field_type { | ||
66 | NTLMSSP_AV_EOL = 0, | ||
67 | NTLMSSP_AV_NB_COMPUTER_NAME, | ||
68 | NTLMSSP_AV_NB_DOMAIN_NAME, | ||
69 | NTLMSSP_AV_DNS_COMPUTER_NAME, | ||
70 | NTLMSSP_AV_DNS_DOMAIN_NAME, | ||
71 | NTLMSSP_AV_DNS_TREE_NAME, | ||
72 | NTLMSSP_AV_FLAGS, | ||
73 | NTLMSSP_AV_TIMESTAMP, | ||
74 | NTLMSSP_AV_RESTRICTION, | ||
75 | NTLMSSP_AV_TARGET_NAME, | ||
76 | NTLMSSP_AV_CHANNEL_BINDINGS | ||
77 | }; | ||
78 | |||
64 | /* Although typedefs are not commonly used for structure definitions */ | 79 | /* Although typedefs are not commonly used for structure definitions */ |
65 | /* in the Linux kernel, in this particular case they are useful */ | 80 | /* in the Linux kernel, in this particular case they are useful */ |
66 | /* to more closely match the standards document for NTLMSSP from */ | 81 | /* to more closely match the standards document for NTLMSSP from */ |
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 88820127650e..af18a500f7e0 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c | |||
@@ -383,6 +383,9 @@ static int decode_ascii_ssetup(char **pbcc_area, int bleft, | |||
383 | static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, | 383 | static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, |
384 | struct cifsSesInfo *ses) | 384 | struct cifsSesInfo *ses) |
385 | { | 385 | { |
386 | unsigned int tioffset; /* challenge message target info area */ | ||
387 | unsigned int tilen; /* challenge message target info area length */ | ||
388 | |||
386 | CHALLENGE_MESSAGE *pblob = (CHALLENGE_MESSAGE *)bcc_ptr; | 389 | CHALLENGE_MESSAGE *pblob = (CHALLENGE_MESSAGE *)bcc_ptr; |
387 | 390 | ||
388 | if (blob_len < sizeof(CHALLENGE_MESSAGE)) { | 391 | if (blob_len < sizeof(CHALLENGE_MESSAGE)) { |
@@ -405,6 +408,19 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, | |||
405 | /* BB spec says that if AvId field of MsvAvTimestamp is populated then | 408 | /* BB spec says that if AvId field of MsvAvTimestamp is populated then |
406 | we must set the MIC field of the AUTHENTICATE_MESSAGE */ | 409 | we must set the MIC field of the AUTHENTICATE_MESSAGE */ |
407 | 410 | ||
411 | tioffset = cpu_to_le16(pblob->TargetInfoArray.BufferOffset); | ||
412 | tilen = cpu_to_le16(pblob->TargetInfoArray.Length); | ||
413 | ses->tilen = tilen; | ||
414 | if (ses->tilen) { | ||
415 | ses->tiblob = kmalloc(tilen, GFP_KERNEL); | ||
416 | if (!ses->tiblob) { | ||
417 | cERROR(1, "Challenge target info allocation failure"); | ||
418 | ses->tilen = 0; | ||
419 | return -ENOMEM; | ||
420 | } | ||
421 | memcpy(ses->tiblob, bcc_ptr + tioffset, ses->tilen); | ||
422 | } | ||
423 | |||
408 | return 0; | 424 | return 0; |
409 | } | 425 | } |
410 | 426 | ||
@@ -425,7 +441,7 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, | |||
425 | /* BB is NTLMV2 session security format easier to use here? */ | 441 | /* BB is NTLMV2 session security format easier to use here? */ |
426 | flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET | | 442 | flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET | |
427 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | | 443 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | |
428 | NTLMSSP_NEGOTIATE_NT_ONLY | NTLMSSP_NEGOTIATE_NTLM; | 444 | NTLMSSP_NEGOTIATE_NTLM; |
429 | if (ses->server->secMode & | 445 | if (ses->server->secMode & |
430 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | 446 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) |
431 | flags |= NTLMSSP_NEGOTIATE_SIGN; | 447 | flags |= NTLMSSP_NEGOTIATE_SIGN; |
@@ -449,12 +465,14 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, | |||
449 | This function returns the length of the data in the blob */ | 465 | This function returns the length of the data in the blob */ |
450 | static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | 466 | static int build_ntlmssp_auth_blob(unsigned char *pbuffer, |
451 | struct cifsSesInfo *ses, | 467 | struct cifsSesInfo *ses, |
452 | const struct nls_table *nls_cp, bool first) | 468 | const struct nls_table *nls_cp) |
453 | { | 469 | { |
470 | int rc; | ||
471 | unsigned int size; | ||
454 | AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer; | 472 | AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer; |
455 | __u32 flags; | 473 | __u32 flags; |
456 | unsigned char *tmp; | 474 | unsigned char *tmp; |
457 | char ntlm_session_key[CIFS_SESS_KEY_SIZE]; | 475 | struct ntlmv2_resp ntlmv2_response = {}; |
458 | 476 | ||
459 | memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); | 477 | memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); |
460 | sec_blob->MessageType = NtLmAuthenticate; | 478 | sec_blob->MessageType = NtLmAuthenticate; |
@@ -462,7 +480,7 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
462 | flags = NTLMSSP_NEGOTIATE_56 | | 480 | flags = NTLMSSP_NEGOTIATE_56 | |
463 | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO | | 481 | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO | |
464 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | | 482 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | |
465 | NTLMSSP_NEGOTIATE_NT_ONLY | NTLMSSP_NEGOTIATE_NTLM; | 483 | NTLMSSP_NEGOTIATE_NTLM; |
466 | if (ses->server->secMode & | 484 | if (ses->server->secMode & |
467 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | 485 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) |
468 | flags |= NTLMSSP_NEGOTIATE_SIGN; | 486 | flags |= NTLMSSP_NEGOTIATE_SIGN; |
@@ -477,19 +495,26 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
477 | sec_blob->LmChallengeResponse.Length = 0; | 495 | sec_blob->LmChallengeResponse.Length = 0; |
478 | sec_blob->LmChallengeResponse.MaximumLength = 0; | 496 | sec_blob->LmChallengeResponse.MaximumLength = 0; |
479 | 497 | ||
480 | /* calculate session key, BB what about adding similar ntlmv2 path? */ | ||
481 | SMBNTencrypt(ses->password, ses->server->cryptKey, ntlm_session_key); | ||
482 | if (first) | ||
483 | cifs_calculate_session_key(&ses->server->session_key, | ||
484 | ntlm_session_key, ses->password); | ||
485 | |||
486 | memcpy(tmp, ntlm_session_key, CIFS_SESS_KEY_SIZE); | ||
487 | sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer); | 498 | sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer); |
488 | sec_blob->NtChallengeResponse.Length = cpu_to_le16(CIFS_SESS_KEY_SIZE); | 499 | rc = setup_ntlmv2_rsp(ses, (char *)&ntlmv2_response, nls_cp); |
489 | sec_blob->NtChallengeResponse.MaximumLength = | 500 | if (rc) { |
490 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | 501 | cERROR(1, "Error %d during NTLMSSP authentication", rc); |
502 | goto setup_ntlmv2_ret; | ||
503 | } | ||
504 | size = sizeof(struct ntlmv2_resp); | ||
505 | memcpy(tmp, (char *)&ntlmv2_response, size); | ||
506 | tmp += size; | ||
507 | if (ses->tilen > 0) { | ||
508 | memcpy(tmp, ses->tiblob, ses->tilen); | ||
509 | tmp += ses->tilen; | ||
510 | } | ||
491 | 511 | ||
492 | tmp += CIFS_SESS_KEY_SIZE; | 512 | sec_blob->NtChallengeResponse.Length = cpu_to_le16(size + ses->tilen); |
513 | sec_blob->NtChallengeResponse.MaximumLength = | ||
514 | cpu_to_le16(size + ses->tilen); | ||
515 | kfree(ses->tiblob); | ||
516 | ses->tiblob = NULL; | ||
517 | ses->tilen = 0; | ||
493 | 518 | ||
494 | if (ses->domainName == NULL) { | 519 | if (ses->domainName == NULL) { |
495 | sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); | 520 | sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); |
@@ -501,7 +526,6 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
501 | len = cifs_strtoUCS((__le16 *)tmp, ses->domainName, | 526 | len = cifs_strtoUCS((__le16 *)tmp, ses->domainName, |
502 | MAX_USERNAME_SIZE, nls_cp); | 527 | MAX_USERNAME_SIZE, nls_cp); |
503 | len *= 2; /* unicode is 2 bytes each */ | 528 | len *= 2; /* unicode is 2 bytes each */ |
504 | len += 2; /* trailing null */ | ||
505 | sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); | 529 | sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); |
506 | sec_blob->DomainName.Length = cpu_to_le16(len); | 530 | sec_blob->DomainName.Length = cpu_to_le16(len); |
507 | sec_blob->DomainName.MaximumLength = cpu_to_le16(len); | 531 | sec_blob->DomainName.MaximumLength = cpu_to_le16(len); |
@@ -518,7 +542,6 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
518 | len = cifs_strtoUCS((__le16 *)tmp, ses->userName, | 542 | len = cifs_strtoUCS((__le16 *)tmp, ses->userName, |
519 | MAX_USERNAME_SIZE, nls_cp); | 543 | MAX_USERNAME_SIZE, nls_cp); |
520 | len *= 2; /* unicode is 2 bytes each */ | 544 | len *= 2; /* unicode is 2 bytes each */ |
521 | len += 2; /* trailing null */ | ||
522 | sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); | 545 | sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); |
523 | sec_blob->UserName.Length = cpu_to_le16(len); | 546 | sec_blob->UserName.Length = cpu_to_le16(len); |
524 | sec_blob->UserName.MaximumLength = cpu_to_le16(len); | 547 | sec_blob->UserName.MaximumLength = cpu_to_le16(len); |
@@ -533,6 +556,8 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
533 | sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); | 556 | sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); |
534 | sec_blob->SessionKey.Length = 0; | 557 | sec_blob->SessionKey.Length = 0; |
535 | sec_blob->SessionKey.MaximumLength = 0; | 558 | sec_blob->SessionKey.MaximumLength = 0; |
559 | |||
560 | setup_ntlmv2_ret: | ||
536 | return tmp - pbuffer; | 561 | return tmp - pbuffer; |
537 | } | 562 | } |
538 | 563 | ||
@@ -545,19 +570,6 @@ static void setup_ntlmssp_neg_req(SESSION_SETUP_ANDX *pSMB, | |||
545 | 570 | ||
546 | return; | 571 | return; |
547 | } | 572 | } |
548 | |||
549 | static int setup_ntlmssp_auth_req(SESSION_SETUP_ANDX *pSMB, | ||
550 | struct cifsSesInfo *ses, | ||
551 | const struct nls_table *nls, bool first_time) | ||
552 | { | ||
553 | int bloblen; | ||
554 | |||
555 | bloblen = build_ntlmssp_auth_blob(&pSMB->req.SecurityBlob[0], ses, nls, | ||
556 | first_time); | ||
557 | pSMB->req.SecurityBlobLength = cpu_to_le16(bloblen); | ||
558 | |||
559 | return bloblen; | ||
560 | } | ||
561 | #endif | 573 | #endif |
562 | 574 | ||
563 | int | 575 | int |
@@ -580,6 +592,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
580 | struct key *spnego_key = NULL; | 592 | struct key *spnego_key = NULL; |
581 | __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ | 593 | __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ |
582 | bool first_time; | 594 | bool first_time; |
595 | int blob_len; | ||
596 | char *ntlmsspblob = NULL; | ||
583 | 597 | ||
584 | if (ses == NULL) | 598 | if (ses == NULL) |
585 | return -EINVAL; | 599 | return -EINVAL; |
@@ -729,12 +743,24 @@ ssetup_ntlmssp_authenticate: | |||
729 | cpu_to_le16(sizeof(struct ntlmv2_resp)); | 743 | cpu_to_le16(sizeof(struct ntlmv2_resp)); |
730 | 744 | ||
731 | /* calculate session key */ | 745 | /* calculate session key */ |
732 | setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp); | 746 | rc = setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp); |
733 | /* FIXME: calculate MAC key */ | 747 | if (rc) { |
748 | cERROR(1, "Error %d during NTLMv2 authentication", rc); | ||
749 | kfree(v2_sess_key); | ||
750 | goto ssetup_exit; | ||
751 | } | ||
734 | memcpy(bcc_ptr, (char *)v2_sess_key, | 752 | memcpy(bcc_ptr, (char *)v2_sess_key, |
735 | sizeof(struct ntlmv2_resp)); | 753 | sizeof(struct ntlmv2_resp)); |
736 | bcc_ptr += sizeof(struct ntlmv2_resp); | 754 | bcc_ptr += sizeof(struct ntlmv2_resp); |
737 | kfree(v2_sess_key); | 755 | kfree(v2_sess_key); |
756 | if (ses->tilen > 0) { | ||
757 | memcpy(bcc_ptr, ses->tiblob, ses->tilen); | ||
758 | bcc_ptr += ses->tilen; | ||
759 | /* we never did allocate ses->domainName to free */ | ||
760 | kfree(ses->tiblob); | ||
761 | ses->tiblob = NULL; | ||
762 | ses->tilen = 0; | ||
763 | } | ||
738 | if (ses->capabilities & CAP_UNICODE) { | 764 | if (ses->capabilities & CAP_UNICODE) { |
739 | if (iov[0].iov_len % 2) { | 765 | if (iov[0].iov_len % 2) { |
740 | *bcc_ptr = 0; | 766 | *bcc_ptr = 0; |
@@ -815,12 +841,28 @@ ssetup_ntlmssp_authenticate: | |||
815 | if (phase == NtLmNegotiate) { | 841 | if (phase == NtLmNegotiate) { |
816 | setup_ntlmssp_neg_req(pSMB, ses); | 842 | setup_ntlmssp_neg_req(pSMB, ses); |
817 | iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE); | 843 | iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE); |
844 | iov[1].iov_base = &pSMB->req.SecurityBlob[0]; | ||
818 | } else if (phase == NtLmAuthenticate) { | 845 | } else if (phase == NtLmAuthenticate) { |
819 | int blob_len; | 846 | /* 5 is an empirical value, large enought to |
820 | blob_len = setup_ntlmssp_auth_req(pSMB, ses, | 847 | * hold authenticate message, max 10 of |
821 | nls_cp, | 848 | * av paris, doamin,user,workstation mames, |
822 | first_time); | 849 | * flags etc.. |
850 | */ | ||
851 | ntlmsspblob = kmalloc( | ||
852 | 5*sizeof(struct _AUTHENTICATE_MESSAGE), | ||
853 | GFP_KERNEL); | ||
854 | if (!ntlmsspblob) { | ||
855 | cERROR(1, "Can't allocate NTLMSSP"); | ||
856 | rc = -ENOMEM; | ||
857 | goto ssetup_exit; | ||
858 | } | ||
859 | |||
860 | blob_len = build_ntlmssp_auth_blob(ntlmsspblob, | ||
861 | ses, nls_cp); | ||
823 | iov[1].iov_len = blob_len; | 862 | iov[1].iov_len = blob_len; |
863 | iov[1].iov_base = ntlmsspblob; | ||
864 | pSMB->req.SecurityBlobLength = | ||
865 | cpu_to_le16(blob_len); | ||
824 | /* Make sure that we tell the server that we | 866 | /* Make sure that we tell the server that we |
825 | are using the uid that it just gave us back | 867 | are using the uid that it just gave us back |
826 | on the response (challenge) */ | 868 | on the response (challenge) */ |
@@ -830,7 +872,6 @@ ssetup_ntlmssp_authenticate: | |||
830 | rc = -ENOSYS; | 872 | rc = -ENOSYS; |
831 | goto ssetup_exit; | 873 | goto ssetup_exit; |
832 | } | 874 | } |
833 | iov[1].iov_base = &pSMB->req.SecurityBlob[0]; | ||
834 | /* unicode strings must be word aligned */ | 875 | /* unicode strings must be word aligned */ |
835 | if ((iov[0].iov_len + iov[1].iov_len) % 2) { | 876 | if ((iov[0].iov_len + iov[1].iov_len) % 2) { |
836 | *bcc_ptr = 0; | 877 | *bcc_ptr = 0; |
@@ -931,6 +972,8 @@ ssetup_exit: | |||
931 | key_put(spnego_key); | 972 | key_put(spnego_key); |
932 | } | 973 | } |
933 | kfree(str_area); | 974 | kfree(str_area); |
975 | kfree(ntlmsspblob); | ||
976 | ntlmsspblob = NULL; | ||
934 | if (resp_buf_type == CIFS_SMALL_BUFFER) { | 977 | if (resp_buf_type == CIFS_SMALL_BUFFER) { |
935 | cFYI(1, "ssetup freeing small buf %p", iov[0].iov_base); | 978 | cFYI(1, "ssetup freeing small buf %p", iov[0].iov_base); |
936 | cifs_small_buf_release(iov[0].iov_base); | 979 | cifs_small_buf_release(iov[0].iov_base); |