Modify cifs to assume that the supplied password is encoded according to
iocharset.  Before this patch passwords would be treated as raw 8-bit data,
which made authentication with Unicode passwords impossible (at least
passwords with characters > 0xFF).

The previous code would as a side effect accept passwords encoded with ISO
8859-1, since Unicode < 0x100 basically is ISO 8859-1.  Software which
relies on that will no longer support password chars > 0x7F unless it also
uses iocharset=iso8859-1.  (mount.cifs does not care about the encoding so
it will work as expected.)

Signed-off-by: Oskar Liljeblad <[email protected]>
---
 fs/cifs/cifsencrypt.c |    8 +++---
 fs/cifs/cifsproto.h   |    8 ++++--
 fs/cifs/connect.c     |    2 +-
 fs/cifs/sess.c        |    2 +-
 fs/cifs/smbencrypt.c  |   60 +++++++++----------------------------------------
 5 files changed, 22 insertions(+), 58 deletions(-)

diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 5bb4b09..3c1306d 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -226,7 +226,7 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu,
 }
 
 /* first calculate 24 bytes ntlm response and then 16 byte session key */
-int setup_ntlm_response(struct cifs_ses *ses)
+int setup_ntlm_response(struct cifs_ses *ses, const struct nls_table *nls_cp)
 {
        int rc = 0;
        unsigned int temp_len = CIFS_SESS_KEY_SIZE + CIFS_AUTH_RESP_SIZE;
@@ -243,14 +243,14 @@ int setup_ntlm_response(struct cifs_ses *ses)
        ses->auth_key.len = temp_len;
 
        rc = SMBNTencrypt(ses->password, ses->server->cryptkey,
-                       ses->auth_key.response + CIFS_SESS_KEY_SIZE);
+                       ses->auth_key.response + CIFS_SESS_KEY_SIZE, nls_cp);
        if (rc) {
                cFYI(1, "%s Can't generate NTLM response, error: %d",
                        __func__, rc);
                return rc;
        }
 
-       rc = E_md4hash(ses->password, temp_key);
+       rc = E_md4hash(ses->password, temp_key, nls_cp);
        if (rc) {
                cFYI(1, "%s Can't generate NT hash, error: %d", __func__, rc);
                return rc;
@@ -458,7 +458,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char 
*ntlmv2_hash,
        }
 
        /* calculate md4 hash of password */
-       E_md4hash(ses->password, nt_hash);
+       E_md4hash(ses->password, nt_hash, nls_cp);
 
        crypto_shash_setkey(ses->server->secmech.hmacmd5, nt_hash,
                                CIFS_NTHASH_SIZE);
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index e42dc82..fd6d873 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -376,8 +376,9 @@ extern int cifs_sign_smb2(struct kvec *iov, int n_vec, 
struct TCP_Server_Info *,
 extern int cifs_verify_signature(struct smb_hdr *,
                                 struct TCP_Server_Info *server,
                                __u32 expected_sequence_number);
-extern int SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *);
-extern int setup_ntlm_response(struct cifs_ses *);
+extern int SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *,
+                       const struct nls_table *);
+extern int setup_ntlm_response(struct cifs_ses *, const struct nls_table *);
 extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *);
 extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *);
 extern void cifs_crypto_shash_release(struct TCP_Server_Info *);
@@ -429,7 +430,8 @@ extern int CIFSCheckMFSymlink(struct cifs_fattr *fattr,
                const unsigned char *path,
                struct cifs_sb_info *cifs_sb, int xid);
 extern int mdfour(unsigned char *, unsigned char *, int);
-extern int E_md4hash(const unsigned char *passwd, unsigned char *p16);
+extern int E_md4hash(const unsigned char *passwd, unsigned char *p16,
+                    const struct nls_table *codepage);
 extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8,
                        unsigned char *p24);
 #endif                 /* _CIFSPROTO_H */
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 96544a4..3c0190f 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -3060,7 +3060,7 @@ CIFSTCon(unsigned int xid, struct cifs_ses *ses,
                else
 #endif /* CIFS_WEAK_PW_HASH */
                rc = SMBNTencrypt(tcon->password, ses->server->cryptkey,
-                                       bcc_ptr);
+                                       bcc_ptr, nls_codepage);
 
                bcc_ptr += CIFS_AUTH_RESP_SIZE;
                if (ses->capabilities & CAP_UNICODE) {
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index 6b140e1..17ae0db 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -694,7 +694,7 @@ ssetup_ntlmssp_authenticate:
                        cpu_to_le16(CIFS_AUTH_RESP_SIZE);
 
                /* calculate ntlm response and session key */
-               rc = setup_ntlm_response(ses);
+               rc = setup_ntlm_response(ses, nls_cp);
                if (rc) {
                        cERROR(1, "Error %d during NTLM authentication", rc);
                        goto ssetup_exit;
diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c
index 1525d5e..92291c1 100644
--- a/fs/cifs/smbencrypt.c
+++ b/fs/cifs/smbencrypt.c
@@ -195,46 +195,13 @@ SMBencrypt(unsigned char *passwd, const unsigned char 
*c8, unsigned char *p24)
        return rc;
 }
 
-/* Routines for Windows NT MD4 Hash functions. */
-static int
-_my_wcslen(__u16 *str)
-{
-       int len = 0;
-       while (*str++ != 0)
-               len++;
-       return len;
-}
-
-/*
- * Convert a string into an NT UNICODE string.
- * Note that regardless of processor type
- * this must be in intel (little-endian)
- * format.
- */
-
-static int
-_my_mbstowcs(__u16 *dst, const unsigned char *src, int len)
-{      /* BB not a very good conversion routine - change/fix */
-       int i;
-       __u16 val;
-
-       for (i = 0; i < len; i++) {
-               val = *src;
-               SSVAL(dst, 0, val);
-               dst++;
-               src++;
-               if (val == 0)
-                       break;
-       }
-       return i;
-}
-
 /*
  * Creates the MD4 Hash of the users password in NT UNICODE.
  */
 
 int
-E_md4hash(const unsigned char *passwd, unsigned char *p16)
+E_md4hash(const unsigned char *passwd, unsigned char *p16,
+         const struct nls_table *codepage)
 {
        int rc;
        int len;
@@ -242,20 +209,14 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16)
 
        /* Password cannot be longer than 128 characters */
        if (passwd) {
-               len = strlen((char *) passwd);
-               if (len > 128)
-                       len = 128;
-
                /* Password must be converted to NT unicode */
-               _my_mbstowcs(wpwd, passwd, len);
-       } else
+               len = cifs_strtoUCS(wpwd, passwd, 128, codepage);
+       } else {
                len = 0;
+               *wpwd = 0; /* Ensure string is null terminated */
+       }
 
-       wpwd[len] = 0;  /* Ensure string is null terminated */
-       /* Calculate length in bytes */
-       len = _my_wcslen(wpwd) * sizeof(__u16);
-
-       rc = mdfour(p16, (unsigned char *) wpwd, len);
+       rc = mdfour(p16, (unsigned char *) wpwd, len * sizeof(__u16));
        memset(wpwd, 0, 129 * 2);
 
        return rc;
@@ -275,7 +236,7 @@ nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned 
char p16[16])
                memcpy(passwd, pwd, 512);
        /* Calculate the MD4 hash (NT compatible) of the password */
        memset(nt_p16, '\0', 16);
-       E_md4hash(passwd, nt_p16);
+       E_md4hash(passwd, nt_p16, /* put nls codepage here */);
 
        /* Mangle the passwords into Lanman format */
        passwd[14] = '\0';
@@ -348,7 +309,8 @@ NTLMSSPOWFencrypt(unsigned char passwd[8],
 
 /* Does the NT MD4 hash then des encryption. */
 int
-SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24)
+SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24,
+            const struct nls_table *codepage)
 {
        int rc;
        unsigned char p16[16], p21[21];
@@ -356,7 +318,7 @@ SMBNTencrypt(unsigned char *passwd, unsigned char *c8, 
unsigned char *p24)
        memset(p16, '\0', 16);
        memset(p21, '\0', 21);
 
-       rc = E_md4hash(passwd, p16);
+       rc = E_md4hash(passwd, p16, codepage);
        if (rc) {
                cFYI(1, "%s Can't generate NT hash, error: %d", __func__, rc);
                return rc;
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to