diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/cifs/connect.c | 381 |
1 files changed, 7 insertions, 374 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index e94d6b29af64..579a628d1e65 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -2593,310 +2593,6 @@ out: | |||
2593 | } | 2593 | } |
2594 | 2594 | ||
2595 | static int | 2595 | static int |
2596 | CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | ||
2597 | char session_key[CIFS_SESS_KEY_SIZE], | ||
2598 | const struct nls_table *nls_codepage) | ||
2599 | { | ||
2600 | struct smb_hdr *smb_buffer; | ||
2601 | struct smb_hdr *smb_buffer_response; | ||
2602 | SESSION_SETUP_ANDX *pSMB; | ||
2603 | SESSION_SETUP_ANDX *pSMBr; | ||
2604 | char *bcc_ptr; | ||
2605 | char *user; | ||
2606 | char *domain; | ||
2607 | int rc = 0; | ||
2608 | int remaining_words = 0; | ||
2609 | int bytes_returned = 0; | ||
2610 | int len; | ||
2611 | __u32 capabilities; | ||
2612 | __u16 count; | ||
2613 | |||
2614 | cFYI(1, ("In sesssetup")); | ||
2615 | if (ses == NULL) | ||
2616 | return -EINVAL; | ||
2617 | user = ses->userName; | ||
2618 | domain = ses->domainName; | ||
2619 | smb_buffer = cifs_buf_get(); | ||
2620 | |||
2621 | if (smb_buffer == NULL) | ||
2622 | return -ENOMEM; | ||
2623 | |||
2624 | smb_buffer_response = smb_buffer; | ||
2625 | pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer; | ||
2626 | |||
2627 | /* send SMBsessionSetup here */ | ||
2628 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | ||
2629 | NULL /* no tCon exists yet */ , 13 /* wct */ ); | ||
2630 | |||
2631 | smb_buffer->Mid = GetNextMid(ses->server); | ||
2632 | pSMB->req_no_secext.AndXCommand = 0xFF; | ||
2633 | pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); | ||
2634 | pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq); | ||
2635 | |||
2636 | if (ses->server->secMode & | ||
2637 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
2638 | smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | ||
2639 | |||
2640 | capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | | ||
2641 | CAP_LARGE_WRITE_X | CAP_LARGE_READ_X; | ||
2642 | if (ses->capabilities & CAP_UNICODE) { | ||
2643 | smb_buffer->Flags2 |= SMBFLG2_UNICODE; | ||
2644 | capabilities |= CAP_UNICODE; | ||
2645 | } | ||
2646 | if (ses->capabilities & CAP_STATUS32) { | ||
2647 | smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; | ||
2648 | capabilities |= CAP_STATUS32; | ||
2649 | } | ||
2650 | if (ses->capabilities & CAP_DFS) { | ||
2651 | smb_buffer->Flags2 |= SMBFLG2_DFS; | ||
2652 | capabilities |= CAP_DFS; | ||
2653 | } | ||
2654 | pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); | ||
2655 | |||
2656 | pSMB->req_no_secext.CaseInsensitivePasswordLength = | ||
2657 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | ||
2658 | |||
2659 | pSMB->req_no_secext.CaseSensitivePasswordLength = | ||
2660 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | ||
2661 | bcc_ptr = pByteArea(smb_buffer); | ||
2662 | memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE); | ||
2663 | bcc_ptr += CIFS_SESS_KEY_SIZE; | ||
2664 | memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE); | ||
2665 | bcc_ptr += CIFS_SESS_KEY_SIZE; | ||
2666 | |||
2667 | if (ses->capabilities & CAP_UNICODE) { | ||
2668 | if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */ | ||
2669 | *bcc_ptr = 0; | ||
2670 | bcc_ptr++; | ||
2671 | } | ||
2672 | if (user == NULL) | ||
2673 | bytes_returned = 0; /* skip null user */ | ||
2674 | else | ||
2675 | bytes_returned = | ||
2676 | cifs_strtoUCS((__le16 *) bcc_ptr, user, 100, | ||
2677 | nls_codepage); | ||
2678 | /* convert number of 16 bit words to bytes */ | ||
2679 | bcc_ptr += 2 * bytes_returned; | ||
2680 | bcc_ptr += 2; /* trailing null */ | ||
2681 | if (domain == NULL) | ||
2682 | bytes_returned = | ||
2683 | cifs_strtoUCS((__le16 *) bcc_ptr, | ||
2684 | "CIFS_LINUX_DOM", 32, nls_codepage); | ||
2685 | else | ||
2686 | bytes_returned = | ||
2687 | cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64, | ||
2688 | nls_codepage); | ||
2689 | bcc_ptr += 2 * bytes_returned; | ||
2690 | bcc_ptr += 2; | ||
2691 | bytes_returned = | ||
2692 | cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", | ||
2693 | 32, nls_codepage); | ||
2694 | bcc_ptr += 2 * bytes_returned; | ||
2695 | bytes_returned = | ||
2696 | cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, | ||
2697 | 32, nls_codepage); | ||
2698 | bcc_ptr += 2 * bytes_returned; | ||
2699 | bcc_ptr += 2; | ||
2700 | bytes_returned = | ||
2701 | cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, | ||
2702 | 64, nls_codepage); | ||
2703 | bcc_ptr += 2 * bytes_returned; | ||
2704 | bcc_ptr += 2; | ||
2705 | } else { | ||
2706 | if (user != NULL) { | ||
2707 | strncpy(bcc_ptr, user, 200); | ||
2708 | bcc_ptr += strnlen(user, 200); | ||
2709 | } | ||
2710 | *bcc_ptr = 0; | ||
2711 | bcc_ptr++; | ||
2712 | if (domain == NULL) { | ||
2713 | strcpy(bcc_ptr, "CIFS_LINUX_DOM"); | ||
2714 | bcc_ptr += strlen("CIFS_LINUX_DOM") + 1; | ||
2715 | } else { | ||
2716 | strncpy(bcc_ptr, domain, 64); | ||
2717 | bcc_ptr += strnlen(domain, 64); | ||
2718 | *bcc_ptr = 0; | ||
2719 | bcc_ptr++; | ||
2720 | } | ||
2721 | strcpy(bcc_ptr, "Linux version "); | ||
2722 | bcc_ptr += strlen("Linux version "); | ||
2723 | strcpy(bcc_ptr, utsname()->release); | ||
2724 | bcc_ptr += strlen(utsname()->release) + 1; | ||
2725 | strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); | ||
2726 | bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; | ||
2727 | } | ||
2728 | count = (long) bcc_ptr - (long) pByteArea(smb_buffer); | ||
2729 | smb_buffer->smb_buf_length += count; | ||
2730 | pSMB->req_no_secext.ByteCount = cpu_to_le16(count); | ||
2731 | |||
2732 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, | ||
2733 | &bytes_returned, CIFS_LONG_OP); | ||
2734 | if (rc) { | ||
2735 | /* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */ | ||
2736 | } else if ((smb_buffer_response->WordCount == 3) | ||
2737 | || (smb_buffer_response->WordCount == 4)) { | ||
2738 | __u16 action = le16_to_cpu(pSMBr->resp.Action); | ||
2739 | __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); | ||
2740 | if (action & GUEST_LOGIN) | ||
2741 | cFYI(1, ("Guest login")); /* BB mark SesInfo struct? */ | ||
2742 | ses->Suid = smb_buffer_response->Uid; /* UID left in wire format | ||
2743 | (little endian) */ | ||
2744 | cFYI(1, ("UID = %d ", ses->Suid)); | ||
2745 | /* response can have either 3 or 4 word count - Samba sends 3 */ | ||
2746 | bcc_ptr = pByteArea(smb_buffer_response); | ||
2747 | if ((pSMBr->resp.hdr.WordCount == 3) | ||
2748 | || ((pSMBr->resp.hdr.WordCount == 4) | ||
2749 | && (blob_len < pSMBr->resp.ByteCount))) { | ||
2750 | if (pSMBr->resp.hdr.WordCount == 4) | ||
2751 | bcc_ptr += blob_len; | ||
2752 | |||
2753 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { | ||
2754 | if ((long) (bcc_ptr) % 2) { | ||
2755 | remaining_words = | ||
2756 | (BCC(smb_buffer_response) - 1) / 2; | ||
2757 | /* Unicode strings must be word | ||
2758 | aligned */ | ||
2759 | bcc_ptr++; | ||
2760 | } else { | ||
2761 | remaining_words = | ||
2762 | BCC(smb_buffer_response) / 2; | ||
2763 | } | ||
2764 | len = | ||
2765 | UniStrnlen((wchar_t *) bcc_ptr, | ||
2766 | remaining_words - 1); | ||
2767 | /* We look for obvious messed up bcc or strings in response so we do not go off | ||
2768 | the end since (at least) WIN2K and Windows XP have a major bug in not null | ||
2769 | terminating last Unicode string in response */ | ||
2770 | kfree(ses->serverOS); | ||
2771 | ses->serverOS = kzalloc(2 * (len + 1), | ||
2772 | GFP_KERNEL); | ||
2773 | if (ses->serverOS == NULL) | ||
2774 | goto sesssetup_nomem; | ||
2775 | cifs_strfromUCS_le(ses->serverOS, | ||
2776 | (__le16 *)bcc_ptr, | ||
2777 | len, nls_codepage); | ||
2778 | bcc_ptr += 2 * (len + 1); | ||
2779 | remaining_words -= len + 1; | ||
2780 | ses->serverOS[2 * len] = 0; | ||
2781 | ses->serverOS[1 + (2 * len)] = 0; | ||
2782 | if (remaining_words > 0) { | ||
2783 | len = UniStrnlen((wchar_t *)bcc_ptr, | ||
2784 | remaining_words-1); | ||
2785 | kfree(ses->serverNOS); | ||
2786 | ses->serverNOS = kzalloc(2 * (len + 1), | ||
2787 | GFP_KERNEL); | ||
2788 | if (ses->serverNOS == NULL) | ||
2789 | goto sesssetup_nomem; | ||
2790 | cifs_strfromUCS_le(ses->serverNOS, | ||
2791 | (__le16 *)bcc_ptr, | ||
2792 | len, nls_codepage); | ||
2793 | bcc_ptr += 2 * (len + 1); | ||
2794 | ses->serverNOS[2 * len] = 0; | ||
2795 | ses->serverNOS[1 + (2 * len)] = 0; | ||
2796 | if (strncmp(ses->serverNOS, | ||
2797 | "NT LAN Manager 4", 16) == 0) { | ||
2798 | cFYI(1, ("NT4 server")); | ||
2799 | ses->flags |= CIFS_SES_NT4; | ||
2800 | } | ||
2801 | remaining_words -= len + 1; | ||
2802 | if (remaining_words > 0) { | ||
2803 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); | ||
2804 | /* last string is not always null terminated | ||
2805 | (for e.g. for Windows XP & 2000) */ | ||
2806 | kfree(ses->serverDomain); | ||
2807 | ses->serverDomain = | ||
2808 | kzalloc(2*(len+1), | ||
2809 | GFP_KERNEL); | ||
2810 | if (ses->serverDomain == NULL) | ||
2811 | goto sesssetup_nomem; | ||
2812 | cifs_strfromUCS_le(ses->serverDomain, | ||
2813 | (__le16 *)bcc_ptr, | ||
2814 | len, nls_codepage); | ||
2815 | bcc_ptr += 2 * (len + 1); | ||
2816 | ses->serverDomain[2*len] = 0; | ||
2817 | ses->serverDomain[1+(2*len)] = 0; | ||
2818 | } else { /* else no more room so create | ||
2819 | dummy domain string */ | ||
2820 | kfree(ses->serverDomain); | ||
2821 | ses->serverDomain = | ||
2822 | kzalloc(2, GFP_KERNEL); | ||
2823 | } | ||
2824 | } else { /* no room so create dummy domain | ||
2825 | and NOS string */ | ||
2826 | |||
2827 | /* if these kcallocs fail not much we | ||
2828 | can do, but better to not fail the | ||
2829 | sesssetup itself */ | ||
2830 | kfree(ses->serverDomain); | ||
2831 | ses->serverDomain = | ||
2832 | kzalloc(2, GFP_KERNEL); | ||
2833 | kfree(ses->serverNOS); | ||
2834 | ses->serverNOS = | ||
2835 | kzalloc(2, GFP_KERNEL); | ||
2836 | } | ||
2837 | } else { /* ASCII */ | ||
2838 | len = strnlen(bcc_ptr, 1024); | ||
2839 | if (((long) bcc_ptr + len) - (long) | ||
2840 | pByteArea(smb_buffer_response) | ||
2841 | <= BCC(smb_buffer_response)) { | ||
2842 | kfree(ses->serverOS); | ||
2843 | ses->serverOS = kzalloc(len + 1, | ||
2844 | GFP_KERNEL); | ||
2845 | if (ses->serverOS == NULL) | ||
2846 | goto sesssetup_nomem; | ||
2847 | strncpy(ses->serverOS, bcc_ptr, len); | ||
2848 | |||
2849 | bcc_ptr += len; | ||
2850 | /* null terminate the string */ | ||
2851 | bcc_ptr[0] = 0; | ||
2852 | bcc_ptr++; | ||
2853 | |||
2854 | len = strnlen(bcc_ptr, 1024); | ||
2855 | kfree(ses->serverNOS); | ||
2856 | ses->serverNOS = kzalloc(len + 1, | ||
2857 | GFP_KERNEL); | ||
2858 | if (ses->serverNOS == NULL) | ||
2859 | goto sesssetup_nomem; | ||
2860 | strncpy(ses->serverNOS, bcc_ptr, len); | ||
2861 | bcc_ptr += len; | ||
2862 | bcc_ptr[0] = 0; | ||
2863 | bcc_ptr++; | ||
2864 | |||
2865 | len = strnlen(bcc_ptr, 1024); | ||
2866 | kfree(ses->serverDomain); | ||
2867 | ses->serverDomain = kzalloc(len + 1, | ||
2868 | GFP_KERNEL); | ||
2869 | if (ses->serverDomain == NULL) | ||
2870 | goto sesssetup_nomem; | ||
2871 | strncpy(ses->serverDomain, bcc_ptr, | ||
2872 | len); | ||
2873 | bcc_ptr += len; | ||
2874 | bcc_ptr[0] = 0; | ||
2875 | bcc_ptr++; | ||
2876 | } else | ||
2877 | cFYI(1, | ||
2878 | ("Variable field of length %d " | ||
2879 | "extends beyond end of smb ", | ||
2880 | len)); | ||
2881 | } | ||
2882 | } else { | ||
2883 | cERROR(1, ("Security Blob Length extends beyond " | ||
2884 | "end of SMB")); | ||
2885 | } | ||
2886 | } else { | ||
2887 | cERROR(1, ("Invalid Word count %d: ", | ||
2888 | smb_buffer_response->WordCount)); | ||
2889 | rc = -EIO; | ||
2890 | } | ||
2891 | sesssetup_nomem: /* do not return an error on nomem for the info strings, | ||
2892 | since that could make reconnection harder, and | ||
2893 | reconnection might be needed to free memory */ | ||
2894 | cifs_buf_release(smb_buffer); | ||
2895 | |||
2896 | return rc; | ||
2897 | } | ||
2898 | |||
2899 | static int | ||
2900 | CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | 2596 | CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, |
2901 | struct cifsSesInfo *ses, bool *pNTLMv2_flag, | 2597 | struct cifsSesInfo *ses, bool *pNTLMv2_flag, |
2902 | const struct nls_table *nls_codepage) | 2598 | const struct nls_table *nls_codepage) |
@@ -3229,6 +2925,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | |||
3229 | 2925 | ||
3230 | return rc; | 2926 | return rc; |
3231 | } | 2927 | } |
2928 | |||
3232 | static int | 2929 | static int |
3233 | CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, | 2930 | CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, |
3234 | char *ntlm_session_key, bool ntlmv2_flag, | 2931 | char *ntlm_session_key, bool ntlmv2_flag, |
@@ -3831,83 +3528,19 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | |||
3831 | pSesInfo->capabilities = server->capabilities; | 3528 | pSesInfo->capabilities = server->capabilities; |
3832 | if (linuxExtEnabled == 0) | 3529 | if (linuxExtEnabled == 0) |
3833 | pSesInfo->capabilities &= (~CAP_UNIX); | 3530 | pSesInfo->capabilities &= (~CAP_UNIX); |
3834 | /* pSesInfo->sequence_number = 0;*/ | 3531 | |
3835 | cFYI(1, ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d", | 3532 | cFYI(1, ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d", |
3836 | server->secMode, server->capabilities, server->timeAdj)); | 3533 | server->secMode, server->capabilities, server->timeAdj)); |
3837 | 3534 | ||
3838 | if (experimEnabled < 2) | 3535 | rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info); |
3839 | rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info); | ||
3840 | else if (extended_security | ||
3841 | && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) | ||
3842 | && (server->secType == NTLMSSP)) { | ||
3843 | rc = -EOPNOTSUPP; | ||
3844 | } else if (extended_security | ||
3845 | && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) | ||
3846 | && (server->secType == RawNTLMSSP)) { | ||
3847 | cFYI(1, ("NTLMSSP sesssetup")); | ||
3848 | rc = CIFSNTLMSSPNegotiateSessSetup(xid, pSesInfo, &ntlmv2_flag, | ||
3849 | nls_info); | ||
3850 | if (!rc) { | ||
3851 | if (ntlmv2_flag) { | ||
3852 | char *v2_response; | ||
3853 | cFYI(1, ("more secure NTLM ver2 hash")); | ||
3854 | if (CalcNTLMv2_partial_mac_key(pSesInfo, | ||
3855 | nls_info)) { | ||
3856 | rc = -ENOMEM; | ||
3857 | goto ss_err_exit; | ||
3858 | } else | ||
3859 | v2_response = kmalloc(16 + 64 /* blob*/, | ||
3860 | GFP_KERNEL); | ||
3861 | if (v2_response) { | ||
3862 | CalcNTLMv2_response(pSesInfo, | ||
3863 | v2_response); | ||
3864 | /* if (first_time) | ||
3865 | cifs_calculate_ntlmv2_mac_key */ | ||
3866 | kfree(v2_response); | ||
3867 | /* BB Put dummy sig in SessSetup PDU? */ | ||
3868 | } else { | ||
3869 | rc = -ENOMEM; | ||
3870 | goto ss_err_exit; | ||
3871 | } | ||
3872 | |||
3873 | } else { | ||
3874 | SMBNTencrypt(pSesInfo->password, | ||
3875 | server->cryptKey, | ||
3876 | ntlm_session_key); | ||
3877 | |||
3878 | if (first_time) | ||
3879 | cifs_calculate_mac_key( | ||
3880 | &server->mac_signing_key, | ||
3881 | ntlm_session_key, | ||
3882 | pSesInfo->password); | ||
3883 | } | ||
3884 | /* for better security the weaker lanman hash not sent | ||
3885 | in AuthSessSetup so we no longer calculate it */ | ||
3886 | |||
3887 | rc = CIFSNTLMSSPAuthSessSetup(xid, pSesInfo, | ||
3888 | ntlm_session_key, | ||
3889 | ntlmv2_flag, | ||
3890 | nls_info); | ||
3891 | } | ||
3892 | } else { /* old style NTLM 0.12 session setup */ | ||
3893 | SMBNTencrypt(pSesInfo->password, server->cryptKey, | ||
3894 | ntlm_session_key); | ||
3895 | |||
3896 | if (first_time) | ||
3897 | cifs_calculate_mac_key(&server->mac_signing_key, | ||
3898 | ntlm_session_key, | ||
3899 | pSesInfo->password); | ||
3900 | |||
3901 | rc = CIFSSessSetup(xid, pSesInfo, ntlm_session_key, nls_info); | ||
3902 | } | ||
3903 | if (rc) { | 3536 | if (rc) { |
3904 | cERROR(1, ("Send error in SessSetup = %d", rc)); | 3537 | cERROR(1, ("Send error in SessSetup = %d", rc)); |
3905 | } else { | 3538 | } else { |
3906 | cFYI(1, ("CIFS Session Established successfully")); | 3539 | cFYI(1, ("CIFS Session Established successfully")); |
3907 | spin_lock(&GlobalMid_Lock); | 3540 | spin_lock(&GlobalMid_Lock); |
3908 | pSesInfo->status = CifsGood; | 3541 | pSesInfo->status = CifsGood; |
3909 | pSesInfo->need_reconnect = false; | 3542 | pSesInfo->need_reconnect = false; |
3910 | spin_unlock(&GlobalMid_Lock); | 3543 | spin_unlock(&GlobalMid_Lock); |
3911 | } | 3544 | } |
3912 | 3545 | ||
3913 | ss_err_exit: | 3546 | ss_err_exit: |