diff options
Diffstat (limited to 'fs/cifs/sess.c')
-rw-r--r-- | fs/cifs/sess.c | 340 |
1 files changed, 277 insertions, 63 deletions
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index c652c73760dd..897a052270f9 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * SMB/CIFS session setup handling routines | 4 | * SMB/CIFS session setup handling routines |
5 | * | 5 | * |
6 | * Copyright (c) International Business Machines Corp., 2006, 2007 | 6 | * Copyright (c) International Business Machines Corp., 2006, 2009 |
7 | * Author(s): Steve French (sfrench@us.ibm.com) | 7 | * Author(s): Steve French (sfrench@us.ibm.com) |
8 | * | 8 | * |
9 | * This library is free software; you can redistribute it and/or modify | 9 | * This library is free software; you can redistribute it and/or modify |
@@ -111,7 +111,7 @@ static __le16 get_next_vcnum(struct cifsSesInfo *ses) | |||
111 | get_vc_num_exit: | 111 | get_vc_num_exit: |
112 | write_unlock(&cifs_tcp_ses_lock); | 112 | write_unlock(&cifs_tcp_ses_lock); |
113 | 113 | ||
114 | return le16_to_cpu(vcnum); | 114 | return cpu_to_le16(vcnum); |
115 | } | 115 | } |
116 | 116 | ||
117 | static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) | 117 | static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) |
@@ -277,12 +277,11 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses, | |||
277 | *pbcc_area = bcc_ptr; | 277 | *pbcc_area = bcc_ptr; |
278 | } | 278 | } |
279 | 279 | ||
280 | static int decode_unicode_ssetup(char **pbcc_area, int bleft, | 280 | static void |
281 | struct cifsSesInfo *ses, | 281 | decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifsSesInfo *ses, |
282 | const struct nls_table *nls_cp) | 282 | const struct nls_table *nls_cp) |
283 | { | 283 | { |
284 | int rc = 0; | 284 | int len; |
285 | int words_left, len; | ||
286 | char *data = *pbcc_area; | 285 | char *data = *pbcc_area; |
287 | 286 | ||
288 | cFYI(1, ("bleft %d", bleft)); | 287 | cFYI(1, ("bleft %d", bleft)); |
@@ -300,63 +299,29 @@ static int decode_unicode_ssetup(char **pbcc_area, int bleft, | |||
300 | ++bleft; | 299 | ++bleft; |
301 | } | 300 | } |
302 | 301 | ||
303 | words_left = bleft / 2; | ||
304 | |||
305 | /* save off server operating system */ | ||
306 | len = UniStrnlen((wchar_t *) data, words_left); | ||
307 | |||
308 | if (len >= words_left) | ||
309 | return rc; | ||
310 | |||
311 | kfree(ses->serverOS); | 302 | kfree(ses->serverOS); |
312 | /* UTF-8 string will not grow more than four times as big as UCS-16 */ | 303 | ses->serverOS = cifs_strndup_from_ucs(data, bleft, true, nls_cp); |
313 | ses->serverOS = kzalloc((4 * len) + 2 /* trailing null */, GFP_KERNEL); | 304 | cFYI(1, ("serverOS=%s", ses->serverOS)); |
314 | if (ses->serverOS != NULL) { | 305 | len = (UniStrnlen((wchar_t *) data, bleft / 2) * 2) + 2; |
315 | cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len, nls_cp); | 306 | data += len; |
316 | cFYI(1, ("serverOS=%s", ses->serverOS)); | 307 | bleft -= len; |
317 | } | 308 | if (bleft <= 0) |
318 | data += 2 * (len + 1); | 309 | return; |
319 | words_left -= len + 1; | ||
320 | |||
321 | /* save off server network operating system */ | ||
322 | len = UniStrnlen((wchar_t *) data, words_left); | ||
323 | |||
324 | if (len >= words_left) | ||
325 | return rc; | ||
326 | 310 | ||
327 | kfree(ses->serverNOS); | 311 | kfree(ses->serverNOS); |
328 | ses->serverNOS = kzalloc((4 * len) + 2 /* trailing null */, GFP_KERNEL); | 312 | ses->serverNOS = cifs_strndup_from_ucs(data, bleft, true, nls_cp); |
329 | if (ses->serverNOS != NULL) { | 313 | cFYI(1, ("serverNOS=%s", ses->serverNOS)); |
330 | cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len, | 314 | len = (UniStrnlen((wchar_t *) data, bleft / 2) * 2) + 2; |
331 | nls_cp); | 315 | data += len; |
332 | cFYI(1, ("serverNOS=%s", ses->serverNOS)); | 316 | bleft -= len; |
333 | if (strncmp(ses->serverNOS, "NT LAN Manager 4", 16) == 0) { | 317 | if (bleft <= 0) |
334 | cFYI(1, ("NT4 server")); | 318 | return; |
335 | ses->flags |= CIFS_SES_NT4; | ||
336 | } | ||
337 | } | ||
338 | data += 2 * (len + 1); | ||
339 | words_left -= len + 1; | ||
340 | |||
341 | /* save off server domain */ | ||
342 | len = UniStrnlen((wchar_t *) data, words_left); | ||
343 | |||
344 | if (len > words_left) | ||
345 | return rc; | ||
346 | 319 | ||
347 | kfree(ses->serverDomain); | 320 | kfree(ses->serverDomain); |
348 | ses->serverDomain = kzalloc((4 * len) + 2, GFP_KERNEL); | 321 | ses->serverDomain = cifs_strndup_from_ucs(data, bleft, true, nls_cp); |
349 | if (ses->serverDomain != NULL) { | 322 | cFYI(1, ("serverDomain=%s", ses->serverDomain)); |
350 | cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len, | ||
351 | nls_cp); | ||
352 | cFYI(1, ("serverDomain=%s", ses->serverDomain)); | ||
353 | } | ||
354 | data += 2 * (len + 1); | ||
355 | words_left -= len + 1; | ||
356 | |||
357 | cFYI(1, ("words left: %d", words_left)); | ||
358 | 323 | ||
359 | return rc; | 324 | return; |
360 | } | 325 | } |
361 | 326 | ||
362 | static int decode_ascii_ssetup(char **pbcc_area, int bleft, | 327 | static int decode_ascii_ssetup(char **pbcc_area, int bleft, |
@@ -413,6 +378,186 @@ static int decode_ascii_ssetup(char **pbcc_area, int bleft, | |||
413 | return rc; | 378 | return rc; |
414 | } | 379 | } |
415 | 380 | ||
381 | static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, | ||
382 | struct cifsSesInfo *ses) | ||
383 | { | ||
384 | CHALLENGE_MESSAGE *pblob = (CHALLENGE_MESSAGE *)bcc_ptr; | ||
385 | |||
386 | if (blob_len < sizeof(CHALLENGE_MESSAGE)) { | ||
387 | cERROR(1, ("challenge blob len %d too small", blob_len)); | ||
388 | return -EINVAL; | ||
389 | } | ||
390 | |||
391 | if (memcmp(pblob->Signature, "NTLMSSP", 8)) { | ||
392 | cERROR(1, ("blob signature incorrect %s", pblob->Signature)); | ||
393 | return -EINVAL; | ||
394 | } | ||
395 | if (pblob->MessageType != NtLmChallenge) { | ||
396 | cERROR(1, ("Incorrect message type %d", pblob->MessageType)); | ||
397 | return -EINVAL; | ||
398 | } | ||
399 | |||
400 | memcpy(ses->server->cryptKey, pblob->Challenge, CIFS_CRYPTO_KEY_SIZE); | ||
401 | /* BB we could decode pblob->NegotiateFlags; some may be useful */ | ||
402 | /* In particular we can examine sign flags */ | ||
403 | /* BB spec says that if AvId field of MsvAvTimestamp is populated then | ||
404 | we must set the MIC field of the AUTHENTICATE_MESSAGE */ | ||
405 | |||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
410 | /* BB Move to ntlmssp.c eventually */ | ||
411 | |||
412 | /* We do not malloc the blob, it is passed in pbuffer, because | ||
413 | it is fixed size, and small, making this approach cleaner */ | ||
414 | static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, | ||
415 | struct cifsSesInfo *ses) | ||
416 | { | ||
417 | NEGOTIATE_MESSAGE *sec_blob = (NEGOTIATE_MESSAGE *)pbuffer; | ||
418 | __u32 flags; | ||
419 | |||
420 | memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); | ||
421 | sec_blob->MessageType = NtLmNegotiate; | ||
422 | |||
423 | /* BB is NTLMV2 session security format easier to use here? */ | ||
424 | flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET | | ||
425 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | | ||
426 | NTLMSSP_NEGOTIATE_NT_ONLY | NTLMSSP_NEGOTIATE_NTLM; | ||
427 | if (ses->server->secMode & | ||
428 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
429 | flags |= NTLMSSP_NEGOTIATE_SIGN; | ||
430 | if (ses->server->secMode & SECMODE_SIGN_REQUIRED) | ||
431 | flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; | ||
432 | |||
433 | sec_blob->NegotiateFlags |= cpu_to_le32(flags); | ||
434 | |||
435 | sec_blob->WorkstationName.BufferOffset = 0; | ||
436 | sec_blob->WorkstationName.Length = 0; | ||
437 | sec_blob->WorkstationName.MaximumLength = 0; | ||
438 | |||
439 | /* Domain name is sent on the Challenge not Negotiate NTLMSSP request */ | ||
440 | sec_blob->DomainName.BufferOffset = 0; | ||
441 | sec_blob->DomainName.Length = 0; | ||
442 | sec_blob->DomainName.MaximumLength = 0; | ||
443 | } | ||
444 | |||
445 | /* We do not malloc the blob, it is passed in pbuffer, because its | ||
446 | maximum possible size is fixed and small, making this approach cleaner. | ||
447 | This function returns the length of the data in the blob */ | ||
448 | static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | ||
449 | struct cifsSesInfo *ses, | ||
450 | const struct nls_table *nls_cp, int first) | ||
451 | { | ||
452 | AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer; | ||
453 | __u32 flags; | ||
454 | unsigned char *tmp; | ||
455 | char ntlm_session_key[CIFS_SESS_KEY_SIZE]; | ||
456 | |||
457 | memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); | ||
458 | sec_blob->MessageType = NtLmAuthenticate; | ||
459 | |||
460 | flags = NTLMSSP_NEGOTIATE_56 | | ||
461 | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO | | ||
462 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | | ||
463 | NTLMSSP_NEGOTIATE_NT_ONLY | NTLMSSP_NEGOTIATE_NTLM; | ||
464 | if (ses->server->secMode & | ||
465 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
466 | flags |= NTLMSSP_NEGOTIATE_SIGN; | ||
467 | if (ses->server->secMode & SECMODE_SIGN_REQUIRED) | ||
468 | flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; | ||
469 | |||
470 | tmp = pbuffer + sizeof(AUTHENTICATE_MESSAGE); | ||
471 | sec_blob->NegotiateFlags |= cpu_to_le32(flags); | ||
472 | |||
473 | sec_blob->LmChallengeResponse.BufferOffset = | ||
474 | cpu_to_le32(sizeof(AUTHENTICATE_MESSAGE)); | ||
475 | sec_blob->LmChallengeResponse.Length = 0; | ||
476 | sec_blob->LmChallengeResponse.MaximumLength = 0; | ||
477 | |||
478 | /* calculate session key, BB what about adding similar ntlmv2 path? */ | ||
479 | SMBNTencrypt(ses->password, ses->server->cryptKey, ntlm_session_key); | ||
480 | if (first) | ||
481 | cifs_calculate_mac_key(&ses->server->mac_signing_key, | ||
482 | ntlm_session_key, ses->password); | ||
483 | |||
484 | memcpy(tmp, ntlm_session_key, CIFS_SESS_KEY_SIZE); | ||
485 | sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer); | ||
486 | sec_blob->NtChallengeResponse.Length = cpu_to_le16(CIFS_SESS_KEY_SIZE); | ||
487 | sec_blob->NtChallengeResponse.MaximumLength = | ||
488 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | ||
489 | |||
490 | tmp += CIFS_SESS_KEY_SIZE; | ||
491 | |||
492 | if (ses->domainName == NULL) { | ||
493 | sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); | ||
494 | sec_blob->DomainName.Length = 0; | ||
495 | sec_blob->DomainName.MaximumLength = 0; | ||
496 | tmp += 2; | ||
497 | } else { | ||
498 | int len; | ||
499 | len = cifs_strtoUCS((__le16 *)tmp, ses->domainName, | ||
500 | MAX_USERNAME_SIZE, nls_cp); | ||
501 | len *= 2; /* unicode is 2 bytes each */ | ||
502 | len += 2; /* trailing null */ | ||
503 | sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); | ||
504 | sec_blob->DomainName.Length = cpu_to_le16(len); | ||
505 | sec_blob->DomainName.MaximumLength = cpu_to_le16(len); | ||
506 | tmp += len; | ||
507 | } | ||
508 | |||
509 | if (ses->userName == NULL) { | ||
510 | sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); | ||
511 | sec_blob->UserName.Length = 0; | ||
512 | sec_blob->UserName.MaximumLength = 0; | ||
513 | tmp += 2; | ||
514 | } else { | ||
515 | int len; | ||
516 | len = cifs_strtoUCS((__le16 *)tmp, ses->userName, | ||
517 | MAX_USERNAME_SIZE, nls_cp); | ||
518 | len *= 2; /* unicode is 2 bytes each */ | ||
519 | len += 2; /* trailing null */ | ||
520 | sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); | ||
521 | sec_blob->UserName.Length = cpu_to_le16(len); | ||
522 | sec_blob->UserName.MaximumLength = cpu_to_le16(len); | ||
523 | tmp += len; | ||
524 | } | ||
525 | |||
526 | sec_blob->WorkstationName.BufferOffset = cpu_to_le32(tmp - pbuffer); | ||
527 | sec_blob->WorkstationName.Length = 0; | ||
528 | sec_blob->WorkstationName.MaximumLength = 0; | ||
529 | tmp += 2; | ||
530 | |||
531 | sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); | ||
532 | sec_blob->SessionKey.Length = 0; | ||
533 | sec_blob->SessionKey.MaximumLength = 0; | ||
534 | return tmp - pbuffer; | ||
535 | } | ||
536 | |||
537 | |||
538 | static void setup_ntlmssp_neg_req(SESSION_SETUP_ANDX *pSMB, | ||
539 | struct cifsSesInfo *ses) | ||
540 | { | ||
541 | build_ntlmssp_negotiate_blob(&pSMB->req.SecurityBlob[0], ses); | ||
542 | pSMB->req.SecurityBlobLength = cpu_to_le16(sizeof(NEGOTIATE_MESSAGE)); | ||
543 | |||
544 | return; | ||
545 | } | ||
546 | |||
547 | static int setup_ntlmssp_auth_req(SESSION_SETUP_ANDX *pSMB, | ||
548 | struct cifsSesInfo *ses, | ||
549 | const struct nls_table *nls, int first_time) | ||
550 | { | ||
551 | int bloblen; | ||
552 | |||
553 | bloblen = build_ntlmssp_auth_blob(&pSMB->req.SecurityBlob[0], ses, nls, | ||
554 | first_time); | ||
555 | pSMB->req.SecurityBlobLength = cpu_to_le16(bloblen); | ||
556 | |||
557 | return bloblen; | ||
558 | } | ||
559 | #endif | ||
560 | |||
416 | int | 561 | int |
417 | CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | 562 | CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, |
418 | const struct nls_table *nls_cp) | 563 | const struct nls_table *nls_cp) |
@@ -431,6 +576,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
431 | __u16 action; | 576 | __u16 action; |
432 | int bytes_remaining; | 577 | int bytes_remaining; |
433 | struct key *spnego_key = NULL; | 578 | struct key *spnego_key = NULL; |
579 | __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ | ||
434 | 580 | ||
435 | if (ses == NULL) | 581 | if (ses == NULL) |
436 | return -EINVAL; | 582 | return -EINVAL; |
@@ -438,6 +584,10 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
438 | type = ses->server->secType; | 584 | type = ses->server->secType; |
439 | 585 | ||
440 | cFYI(1, ("sess setup type %d", type)); | 586 | cFYI(1, ("sess setup type %d", type)); |
587 | ssetup_ntlmssp_authenticate: | ||
588 | if (phase == NtLmChallenge) | ||
589 | phase = NtLmAuthenticate; /* if ntlmssp, now final phase */ | ||
590 | |||
441 | if (type == LANMAN) { | 591 | if (type == LANMAN) { |
442 | #ifndef CONFIG_CIFS_WEAK_PW_HASH | 592 | #ifndef CONFIG_CIFS_WEAK_PW_HASH |
443 | /* LANMAN and plaintext are less secure and off by default. | 593 | /* LANMAN and plaintext are less secure and off by default. |
@@ -651,9 +801,53 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
651 | goto ssetup_exit; | 801 | goto ssetup_exit; |
652 | #endif /* CONFIG_CIFS_UPCALL */ | 802 | #endif /* CONFIG_CIFS_UPCALL */ |
653 | } else { | 803 | } else { |
804 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
805 | if ((experimEnabled > 1) && (type == RawNTLMSSP)) { | ||
806 | if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) { | ||
807 | cERROR(1, ("NTLMSSP requires Unicode support")); | ||
808 | rc = -ENOSYS; | ||
809 | goto ssetup_exit; | ||
810 | } | ||
811 | |||
812 | cFYI(1, ("ntlmssp session setup phase %d", phase)); | ||
813 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
814 | capabilities |= CAP_EXTENDED_SECURITY; | ||
815 | pSMB->req.Capabilities |= cpu_to_le32(capabilities); | ||
816 | if (phase == NtLmNegotiate) { | ||
817 | setup_ntlmssp_neg_req(pSMB, ses); | ||
818 | iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE); | ||
819 | } else if (phase == NtLmAuthenticate) { | ||
820 | int blob_len; | ||
821 | blob_len = setup_ntlmssp_auth_req(pSMB, ses, | ||
822 | nls_cp, | ||
823 | first_time); | ||
824 | iov[1].iov_len = blob_len; | ||
825 | /* Make sure that we tell the server that we | ||
826 | are using the uid that it just gave us back | ||
827 | on the response (challenge) */ | ||
828 | smb_buf->Uid = ses->Suid; | ||
829 | } else { | ||
830 | cERROR(1, ("invalid phase %d", phase)); | ||
831 | rc = -ENOSYS; | ||
832 | goto ssetup_exit; | ||
833 | } | ||
834 | iov[1].iov_base = &pSMB->req.SecurityBlob[0]; | ||
835 | /* unicode strings must be word aligned */ | ||
836 | if ((iov[0].iov_len + iov[1].iov_len) % 2) { | ||
837 | *bcc_ptr = 0; | ||
838 | bcc_ptr++; | ||
839 | } | ||
840 | unicode_oslm_strings(&bcc_ptr, nls_cp); | ||
841 | } else { | ||
842 | cERROR(1, ("secType %d not supported!", type)); | ||
843 | rc = -ENOSYS; | ||
844 | goto ssetup_exit; | ||
845 | } | ||
846 | #else | ||
654 | cERROR(1, ("secType %d not supported!", type)); | 847 | cERROR(1, ("secType %d not supported!", type)); |
655 | rc = -ENOSYS; | 848 | rc = -ENOSYS; |
656 | goto ssetup_exit; | 849 | goto ssetup_exit; |
850 | #endif | ||
657 | } | 851 | } |
658 | 852 | ||
659 | iov[2].iov_base = str_area; | 853 | iov[2].iov_base = str_area; |
@@ -669,12 +863,23 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
669 | /* SMB request buf freed in SendReceive2 */ | 863 | /* SMB request buf freed in SendReceive2 */ |
670 | 864 | ||
671 | cFYI(1, ("ssetup rc from sendrecv2 is %d", rc)); | 865 | cFYI(1, ("ssetup rc from sendrecv2 is %d", rc)); |
672 | if (rc) | ||
673 | goto ssetup_exit; | ||
674 | 866 | ||
675 | pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base; | 867 | pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base; |
676 | smb_buf = (struct smb_hdr *)iov[0].iov_base; | 868 | smb_buf = (struct smb_hdr *)iov[0].iov_base; |
677 | 869 | ||
870 | if ((type == RawNTLMSSP) && (smb_buf->Status.CifsError == | ||
871 | cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))) { | ||
872 | if (phase != NtLmNegotiate) { | ||
873 | cERROR(1, ("Unexpected more processing error")); | ||
874 | goto ssetup_exit; | ||
875 | } | ||
876 | /* NTLMSSP Negotiate sent now processing challenge (response) */ | ||
877 | phase = NtLmChallenge; /* process ntlmssp challenge */ | ||
878 | rc = 0; /* MORE_PROC rc is not an error here, but expected */ | ||
879 | } | ||
880 | if (rc) | ||
881 | goto ssetup_exit; | ||
882 | |||
678 | if ((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) { | 883 | if ((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) { |
679 | rc = -EIO; | 884 | rc = -EIO; |
680 | cERROR(1, ("bad word count %d", smb_buf->WordCount)); | 885 | cERROR(1, ("bad word count %d", smb_buf->WordCount)); |
@@ -693,12 +898,18 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
693 | if (smb_buf->WordCount == 4) { | 898 | if (smb_buf->WordCount == 4) { |
694 | __u16 blob_len; | 899 | __u16 blob_len; |
695 | blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength); | 900 | blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength); |
696 | bcc_ptr += blob_len; | ||
697 | if (blob_len > bytes_remaining) { | 901 | if (blob_len > bytes_remaining) { |
698 | cERROR(1, ("bad security blob length %d", blob_len)); | 902 | cERROR(1, ("bad security blob length %d", blob_len)); |
699 | rc = -EINVAL; | 903 | rc = -EINVAL; |
700 | goto ssetup_exit; | 904 | goto ssetup_exit; |
701 | } | 905 | } |
906 | if (phase == NtLmChallenge) { | ||
907 | rc = decode_ntlmssp_challenge(bcc_ptr, blob_len, ses); | ||
908 | /* now goto beginning for ntlmssp authenticate phase */ | ||
909 | if (rc) | ||
910 | goto ssetup_exit; | ||
911 | } | ||
912 | bcc_ptr += blob_len; | ||
702 | bytes_remaining -= blob_len; | 913 | bytes_remaining -= blob_len; |
703 | } | 914 | } |
704 | 915 | ||
@@ -709,8 +920,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
709 | ++bcc_ptr; | 920 | ++bcc_ptr; |
710 | --bytes_remaining; | 921 | --bytes_remaining; |
711 | } | 922 | } |
712 | rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining, | 923 | decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses, nls_cp); |
713 | ses, nls_cp); | ||
714 | } else { | 924 | } else { |
715 | rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, | 925 | rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, |
716 | ses, nls_cp); | 926 | ses, nls_cp); |
@@ -728,5 +938,9 @@ ssetup_exit: | |||
728 | } else if (resp_buf_type == CIFS_LARGE_BUFFER) | 938 | } else if (resp_buf_type == CIFS_LARGE_BUFFER) |
729 | cifs_buf_release(iov[0].iov_base); | 939 | cifs_buf_release(iov[0].iov_base); |
730 | 940 | ||
941 | /* if ntlmssp, and negotiate succeeded, proceed to authenticate phase */ | ||
942 | if ((phase == NtLmChallenge) && (rc == 0)) | ||
943 | goto ssetup_ntlmssp_authenticate; | ||
944 | |||
731 | return rc; | 945 | return rc; |
732 | } | 946 | } |