aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/sess.c
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2009-05-04 04:37:12 -0400
committerSteve French <sfrench@us.ibm.com>2009-05-04 04:37:12 -0400
commit0b3cc858003b79b6c66ad79415ead907cbe4074e (patch)
tree88449edd4cdb48502ddd98c2c71388f99ed1b59b /fs/cifs/sess.c
parent24d35add2bd09a427cacb7a39e14f3e47ed4d766 (diff)
[CIFS] NTLMSSP reenabled after move from connect.c to sess.c
The NTLMSSP code was removed from fs/cifs/connect.c and merged (75% smaller, cleaner) into fs/cifs/sess.c As with the old code it requires that cifs be built with CONFIG_CIFS_EXPERIMENTAL, the /proc/fs/cifs/Experimental flag must be set to 2, and mount must turn on extended security (e.g. with sec=krb5). Although NTLMSSP encapsulated in SPNEGO is not enabled yet, "raw" ntlmssp is common and useful in some cases since it offers more complete security negotiation, and is the default way of negotiating security for many Windows systems. SPNEGO encapsulated NTLMSSP will be able to reuse the same code. Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs/sess.c')
-rw-r--r--fs/cifs/sess.c252
1 files changed, 249 insertions, 3 deletions
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index b2bdc2a33833..e68744e169b3 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -378,6 +378,186 @@ static int decode_ascii_ssetup(char **pbcc_area, int bleft,
378 return rc; 378 return rc;
379} 379}
380 380
381static 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 */
414static 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 */
448static 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
538static 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
547static 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
381int 561int
382CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, 562CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
383 const struct nls_table *nls_cp) 563 const struct nls_table *nls_cp)
@@ -396,6 +576,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
396 __u16 action; 576 __u16 action;
397 int bytes_remaining; 577 int bytes_remaining;
398 struct key *spnego_key = NULL; 578 struct key *spnego_key = NULL;
579 __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */
399 580
400 if (ses == NULL) 581 if (ses == NULL)
401 return -EINVAL; 582 return -EINVAL;
@@ -403,6 +584,10 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
403 type = ses->server->secType; 584 type = ses->server->secType;
404 585
405 cFYI(1, ("sess setup type %d", type)); 586 cFYI(1, ("sess setup type %d", type));
587ssetup_ntlmssp_authenticate:
588 if (phase == NtLmChallenge)
589 phase = NtLmAuthenticate; /* if ntlmssp, now final phase */
590
406 if (type == LANMAN) { 591 if (type == LANMAN) {
407#ifndef CONFIG_CIFS_WEAK_PW_HASH 592#ifndef CONFIG_CIFS_WEAK_PW_HASH
408 /* LANMAN and plaintext are less secure and off by default. 593 /* LANMAN and plaintext are less secure and off by default.
@@ -616,9 +801,49 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
616 goto ssetup_exit; 801 goto ssetup_exit;
617#endif /* CONFIG_CIFS_UPCALL */ 802#endif /* CONFIG_CIFS_UPCALL */
618 } 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 } else {
826 cERROR(1, ("invalid phase %d", phase));
827 rc = -ENOSYS;
828 goto ssetup_exit;
829 }
830 iov[1].iov_base = &pSMB->req.SecurityBlob[0];
831 /* unicode strings must be word aligned */
832 if ((iov[0].iov_len + iov[1].iov_len) % 2) {
833 *bcc_ptr = 0;
834 bcc_ptr++;
835 }
836 unicode_oslm_strings(&bcc_ptr, nls_cp);
837 } else {
838 cERROR(1, ("secType %d not supported!", type));
839 rc = -ENOSYS;
840 goto ssetup_exit;
841 }
842#else
619 cERROR(1, ("secType %d not supported!", type)); 843 cERROR(1, ("secType %d not supported!", type));
620 rc = -ENOSYS; 844 rc = -ENOSYS;
621 goto ssetup_exit; 845 goto ssetup_exit;
846#endif
622 } 847 }
623 848
624 iov[2].iov_base = str_area; 849 iov[2].iov_base = str_area;
@@ -634,12 +859,23 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
634 /* SMB request buf freed in SendReceive2 */ 859 /* SMB request buf freed in SendReceive2 */
635 860
636 cFYI(1, ("ssetup rc from sendrecv2 is %d", rc)); 861 cFYI(1, ("ssetup rc from sendrecv2 is %d", rc));
637 if (rc)
638 goto ssetup_exit;
639 862
640 pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base; 863 pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base;
641 smb_buf = (struct smb_hdr *)iov[0].iov_base; 864 smb_buf = (struct smb_hdr *)iov[0].iov_base;
642 865
866 if ((type == RawNTLMSSP) && (smb_buf->Status.CifsError ==
867 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))) {
868 if (phase != NtLmNegotiate) {
869 cERROR(1, ("Unexpected more processing error"));
870 goto ssetup_exit;
871 }
872 /* NTLMSSP Negotiate sent now processing challenge (response) */
873 phase = NtLmChallenge; /* process ntlmssp challenge */
874 rc = 0; /* MORE_PROC rc is not an error here, but expected */
875 }
876 if (rc)
877 goto ssetup_exit;
878
643 if ((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) { 879 if ((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) {
644 rc = -EIO; 880 rc = -EIO;
645 cERROR(1, ("bad word count %d", smb_buf->WordCount)); 881 cERROR(1, ("bad word count %d", smb_buf->WordCount));
@@ -658,12 +894,18 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
658 if (smb_buf->WordCount == 4) { 894 if (smb_buf->WordCount == 4) {
659 __u16 blob_len; 895 __u16 blob_len;
660 blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength); 896 blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength);
661 bcc_ptr += blob_len;
662 if (blob_len > bytes_remaining) { 897 if (blob_len > bytes_remaining) {
663 cERROR(1, ("bad security blob length %d", blob_len)); 898 cERROR(1, ("bad security blob length %d", blob_len));
664 rc = -EINVAL; 899 rc = -EINVAL;
665 goto ssetup_exit; 900 goto ssetup_exit;
666 } 901 }
902 if (phase == NtLmChallenge) {
903 rc = decode_ntlmssp_challenge(bcc_ptr, blob_len, ses);
904 /* now goto beginning for ntlmssp authenticate phase */
905 if (rc)
906 goto ssetup_exit;
907 }
908 bcc_ptr += blob_len;
667 bytes_remaining -= blob_len; 909 bytes_remaining -= blob_len;
668 } 910 }
669 911
@@ -692,5 +934,9 @@ ssetup_exit:
692 } else if (resp_buf_type == CIFS_LARGE_BUFFER) 934 } else if (resp_buf_type == CIFS_LARGE_BUFFER)
693 cifs_buf_release(iov[0].iov_base); 935 cifs_buf_release(iov[0].iov_base);
694 936
937 /* if ntlmssp, and negotiate succeeded, proceed to authenticate phase */
938 if ((phase == NtLmChallenge) && (rc == 0))
939 goto ssetup_ntlmssp_authenticate;
940
695 return rc; 941 return rc;
696} 942}