[CIFS] Support for setting up SMB sessions to legacy lanman servers part 2
authorSteve French <sfrench@us.ibm.com>
Thu, 1 Jun 2006 19:20:10 +0000 (19:20 +0000)
committerSteve French <sfrench@us.ibm.com>
Thu, 1 Jun 2006 19:20:10 +0000 (19:20 +0000)
fs/cifs/cifs_debug.c
fs/cifs/cifsencrypt.c
fs/cifs/cifsglob.h
fs/cifs/cifspdu.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/netmisc.c
fs/cifs/sess.c

index 7f4013a..4e10e21 100644 (file)
@@ -508,7 +508,7 @@ cifs_proc_init(void)
                pde->write_proc = multiuser_mount_write;
 
        pde =
-           create_proc_read_entry("ExtendedSecurity", 0, proc_fs_cifs,
+           create_proc_read_entry("SecurityFlags", 0, proc_fs_cifs,
                                extended_security_read, NULL);
        if (pde)
                pde->write_proc = extended_security_write;
@@ -547,7 +547,7 @@ cifs_proc_clean(void)
        remove_proc_entry("MultiuserMount", proc_fs_cifs);
        remove_proc_entry("OplockEnabled", proc_fs_cifs);
 /*     remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); */
-       remove_proc_entry("ExtendedSecurity",proc_fs_cifs);
+       remove_proc_entry("SecurityFlags",proc_fs_cifs);
 /*     remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); */
        remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs);
        remove_proc_entry("Experimental",proc_fs_cifs);
index 08781a4..e11d8c6 100644 (file)
@@ -26,6 +26,7 @@
 #include "md5.h"
 #include "cifs_unicode.h"
 #include "cifsproto.h"
+#include <linux/ctype.h>
 
 /* Calculate and return the CIFS signature based on the mac key and the smb pdu */
 /* the 16 byte signature must be allocated by the caller  */
@@ -35,6 +36,8 @@
 
 extern void mdfour(unsigned char *out, unsigned char *in, int n);
 extern void E_md4hash(const unsigned char *passwd, unsigned char *p16);
+extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
+                       unsigned char *p24);
        
 static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, 
                                    const char * key, char * signature)
@@ -45,7 +48,7 @@ static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu,
                return -EINVAL;
 
        MD5Init(&context);
-       MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16);
+       MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16);
        MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length);
        MD5Final(signature,&context);
        return 0;
@@ -90,7 +93,7 @@ static int cifs_calc_signature2(const struct kvec * iov, int n_vec,
                return -EINVAL;
 
        MD5Init(&context);
-       MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16);
+       MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16);
        for(i=0;i<n_vec;i++) {
                if(iov[i].iov_base == NULL) {
                        cERROR(1,("null iovec entry"));
@@ -204,7 +207,7 @@ int cifs_calculate_mac_key(char * key, const char * rn, const char * password)
 
        E_md4hash(password, temp_key);
        mdfour(key,temp_key,16);
-       memcpy(key+16,rn, CIFS_SESSION_KEY_SIZE);
+       memcpy(key+16,rn, CIFS_SESS_KEY_SIZE);
        return 0;
 }
 
@@ -261,6 +264,37 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_
        kfree(unicode_buf);
        return 0;
 }
+
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key)
+{
+       int i;
+       char password_with_pad[CIFS_ENCPWD_SIZE];
+
+       memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
+       strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE);
+
+       /* calculate old style session key */
+       /* calling toupper is less broken than repeatedly
+       calling nls_toupper would be since that will never
+       work for UTF8, but neither handles multibyte code pages
+       but the only alternative would be converting to UCS-16 (Unicode)
+       (using a routine something like UniStrupr) then
+       uppercasing and then converting back from Unicode - which
+       would only worth doing it if we knew it were utf8. Basically
+       utf8 and other multibyte codepages each need their own strupper
+       function since a byte at a time will ont work. */
+
+       for(i = 0; i < CIFS_ENCPWD_SIZE; i++) {
+               password_with_pad[i] = toupper(password_with_pad[i]);
+       }
+
+       SMBencrypt(password_with_pad, ses->server->cryptKey, lnm_session_key);
+       /* clear password before we return/free memory */
+       memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
+}
+#endif /* CIFS_WEAK_PW_HASH */
+
 void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response)
 {
        struct HMACMD5Context context;
index 7a04204..975e69a 100644 (file)
@@ -158,7 +158,7 @@ struct TCP_Server_Info {
        /* 16th byte of RFC1001 workstation name is always null */
        char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
        __u32 sequence_number; /* needed for CIFS PDU signature */
-       char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; 
+       char mac_signing_key[CIFS_SESS_KEY_SIZE + 16]; 
 };
 
 /*
index e0ff9b5..1359417 100644 (file)
 /*
  * Size of the session key (crypto key encrypted with the password
  */
-#define CIFS_SESSION_KEY_SIZE (24)
+#define CIFS_SESS_KEY_SIZE (24)
+#define V2_SESS_KEY_SIZE (86)
 
 /*
  * Maximum user name length
index ff78cf7..59b037f 100644 (file)
@@ -287,6 +287,9 @@ extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key,
 extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass);
 extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, struct nls_table *);
 extern void CalcNTLMv2_response(const struct cifsSesInfo *,char * );
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+extern void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key);
+#endif /* CIFS_WEAK_PW_HASH */
 extern int CIFSSMBCopy(int xid,
                        struct cifsTconInfo *source_tcon,
                        const char *fromName,
index da3154f..6b5be6d 100644 (file)
@@ -438,12 +438,19 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                        goto neg_err_exit;
                } else if((pSMBr->hdr.WordCount == 13) && 
                        (pSMBr->DialectIndex == LANMAN_PROT)) {
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
                        struct lanman_neg_rsp * rsp = 
                                (struct lanman_neg_rsp *)pSMBr;
 
-
-                       /* BB Mark ses struct as negotiated lanman level BB */
-                       server->secType = LANMAN;
+                       if((extended_security & CIFSSEC_MAY_LANMAN) || 
+                               (extended_security & CIFSSEC_MAY_PLNTXT))
+                               server->secType = LANMAN;
+                       else {
+                               cERROR(1, ("mount failed weak security disabled"
+                                       " in /proc/fs/cifs/SecurityFlags"));
+                               rc = -EOPNOTSUPP;
+                               goto neg_err_exit;
+                       }       
                        server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
                        server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
                        server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
@@ -469,6 +476,11 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                        }
 
                        cFYI(1,("LANMAN negotiated")); /* BB removeme BB */
+#else /* weak security disabled */
+                       cERROR(1,("mount failed, cifs module not built with "
+                               "CIFS_WEAK_PW_HASH support"));
+                       rc = -EOPNOTSUPP;
+#endif /* WEAK_PW_HASH */
                        goto neg_err_exit;
                } else if(pSMBr->hdr.WordCount != 17) {
                        /* unknown wct */
@@ -479,8 +491,13 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                server->secMode = pSMBr->SecurityMode;
                if((server->secMode & SECMODE_USER) == 0)
                        cFYI(1,("share mode security"));
-               server->secType = NTLM; /* BB override default for
-                                          NTLMv2 or kerberos v5 */
+               
+               if(extended_security & CIFSSEC_MUST_NTLMV2)
+                       server->secType = NTLMv2;
+               else
+                       server->secType = NTLM;
+               /* else krb5 ... */
+
                /* one byte - no need to convert this or EncryptionKeyLen
                   from little endian */
                server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
index 7ffb8f2..e6f3d2f 100644 (file)
@@ -1990,7 +1990,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 
 static int
 CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
-             char session_key[CIFS_SESSION_KEY_SIZE],
+             char session_key[CIFS_SESS_KEY_SIZE],
              const struct nls_table *nls_codepage)
 {
        struct smb_hdr *smb_buffer;
@@ -2048,15 +2048,15 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
 
        pSMB->req_no_secext.CaseInsensitivePasswordLength = 
-               cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+               cpu_to_le16(CIFS_SESS_KEY_SIZE);
 
        pSMB->req_no_secext.CaseSensitivePasswordLength =
-           cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+           cpu_to_le16(CIFS_SESS_KEY_SIZE);
        bcc_ptr = pByteArea(smb_buffer);
-       memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
-       bcc_ptr += CIFS_SESSION_KEY_SIZE;
-       memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
-       bcc_ptr += CIFS_SESSION_KEY_SIZE;
+       memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
+       bcc_ptr += CIFS_SESS_KEY_SIZE;
+       memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
+       bcc_ptr += CIFS_SESS_KEY_SIZE;
 
        if (ses->capabilities & CAP_UNICODE) {
                if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
@@ -3004,14 +3004,14 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        SecurityBlob->LmChallengeResponse.Buffer = 0;
 
        SecurityBlob->NtChallengeResponse.Length =
-           cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+           cpu_to_le16(CIFS_SESS_KEY_SIZE);
        SecurityBlob->NtChallengeResponse.MaximumLength =
-           cpu_to_le16(CIFS_SESSION_KEY_SIZE);
-       memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
+           cpu_to_le16(CIFS_SESS_KEY_SIZE);
+       memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
        SecurityBlob->NtChallengeResponse.Buffer =
            cpu_to_le32(SecurityBlobLength);
-       SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
-       bcc_ptr += CIFS_SESSION_KEY_SIZE;
+       SecurityBlobLength += CIFS_SESS_KEY_SIZE;
+       bcc_ptr += CIFS_SESS_KEY_SIZE;
 
        if (ses->capabilities & CAP_UNICODE) {
                if (domain == NULL) {
@@ -3350,22 +3350,33 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
        bcc_ptr = &pSMB->Password[0];
        if((ses->server->secMode) & SECMODE_USER) {
                pSMB->PasswordLength = cpu_to_le16(1);  /* minimum */
+               *bcc_ptr = 0; /* password is null byte */
                bcc_ptr++;              /* skip password */
+               /* already aligned so no need to do it below */
        } else {
-               pSMB->PasswordLength = cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+               pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
                /* BB FIXME add code to fail this if NTLMv2 or Kerberos
                   specified as required (when that support is added to
                   the vfs in the future) as only NTLM or the much
-                  weaker LANMAN (which we do not send) is accepted
+                  weaker LANMAN (which we do not send by default) is accepted
                   by Samba (not sure whether other servers allow
                   NTLMv2 password here) */
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+               if((extended_security & CIFSSEC_MAY_LANMAN) && 
+                       (ses->server->secType == LANMAN))
+                       calc_lanman_hash(ses, bcc_ptr);
+               else
+#endif /* CIFS_WEAK_PW_HASH */
                SMBNTencrypt(ses->password,
                             ses->server->cryptKey,
                             bcc_ptr);
 
-               bcc_ptr += CIFS_SESSION_KEY_SIZE;
-               *bcc_ptr = 0;
-               bcc_ptr++; /* align */
+               bcc_ptr += CIFS_SESS_KEY_SIZE;
+               if(ses->capabilities & CAP_UNICODE) {
+                       /* must align unicode strings */
+                       *bcc_ptr = 0; /* null byte password */
+                       bcc_ptr++;
+               }
        }
 
        if(ses->server->secMode & 
@@ -3507,7 +3518,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                                           struct nls_table * nls_info)
 {
        int rc = 0;
-       char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
+       char ntlm_session_key[CIFS_SESS_KEY_SIZE];
        int ntlmv2_flag = FALSE;
        int first_time = 0;
 
index 5de74d2..a0bcdd6 100644 (file)
@@ -84,7 +84,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = {
 
 static const struct smb_to_posix_error mapping_table_ERRSRV[] = {
        {ERRerror, -EIO},
-       {ERRbadpw, -EPERM},
+       {ERRbadpw, -EACCES},  /* was EPERM */
        {ERRbadtype, -EREMOTE},
        {ERRaccess, -EACCES},
        {ERRinvtid, -ENXIO},
diff --cc fs/cifs/sess.c
Simple merge