Skip to contentSkip to conversation

CIFS: Assume passwords are encoded according to iocharset

PATCH In review Oskar Liljeblad 4 participants 13 messages Mar 27, 2011 – Sep 21, 2011 7 messages not in the archive

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 CIFS: Assume passwords are encoded according to iocharset

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.)

---
 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(-)
fs/cifs/cifsencrypt.c +4 -4
index 5bb4b09..3c1306d 100644
@@ -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);
fs/cifs/cifsproto.h +5 -3
index e42dc82..fd6d873 100644
@@ -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 */
fs/cifs/connect.c +1 -1
index 96544a4..3c0190f 100644
@@ -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) {
fs/cifs/sess.c +1 -1
index 6b140e1..17ae0db 100644
@@ -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;
fs/cifs/smbencrypt.c +11 -49

98 lines not on this page · raw message

A message that is not in the archive (sent off-list or not yet received): [email protected]

#2 lore raw
Quoted 143 lines · Oskar Liljeblad

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.)

---
 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(-)
fs/cifs/cifsencrypt.c +4 -4
index 5bb4b09..3c1306d 100644
@@ -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);
fs/cifs/cifsproto.h +5 -3
index e42dc82..fd6d873 100644
@@ -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 */
fs/cifs/connect.c +0 -0
index 96544a4..3c0190f 100644
@@ -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) {

fs/cifs/sess.c +1 -1
index 6b140e1..17ae0db 100644
@@ -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;
fs/cifs/smbencrypt.c +0 -24
index 1525d5e..92291c1 100644
@@ -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++) {

fs/cifs/smbencrypt.c SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24) · line 231

Quoted 10 lines
fs/cifs/smbencrypt.c +0 -10
-               val = *src;
-               SSVAL(dst, 0, val);
-               dst++;
-               src++;
-               if (val == 0)
-                       break;
-       }
-       return i;
-}
-

Good clean-up of these functions.

Quoted 16 lines
fs/cifs/smbencrypt.c +0 -0
  /*
  * Creates the MD4 Hash of the users password in NT UNICODE.
  */
 

 int

fs/cifs/smbencrypt.c +2 -1
-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;

fs/cifs/smbencrypt.c +0 -1
@@ -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);

fs/cifs/smbencrypt.c E_md4hash(const unsigned char *passwd, unsigned char *p16) · line 216

Quoted 10 lines
fs/cifs/smbencrypt.c +3 -5
-               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 */

Perhaps we can use some minor clean-up of this function! I think we should return an error if passwd is NULL. There is no point in doing further processing if password is NULL, auth will fail.

fs/cifs/smbencrypt.c E_md4hash(const unsigned char *passwd, unsigned char *p16) · line 220

Quoted 9 lines
fs/cifs/smbencrypt.c +2 -5
+       }
 
-       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 *  );
        memset(wpwd, 0, 129 * 2);

Perhaps we should use sizeof(__u16) instead of 2!

Quoted 31 lines
fs/cifs/smbencrypt.c +1 -1
        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

fs/cifs/smbencrypt.c +2 -1
-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];

fs/cifs/smbencrypt.c +1 -1
@@ -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;
Reviewed-by
#3 lore raw
In reply to a message not in the archive
Quoted 211 lines · Oskar Liljeblad

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.)

---
 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(-)
fs/cifs/cifsencrypt.c +4 -4
index 5bb4b09..3c1306d 100644
@@ -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);
fs/cifs/cifsproto.h +5 -3
index e42dc82..fd6d873 100644
@@ -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 */
fs/cifs/connect.c +0 -0
index 96544a4..3c0190f 100644
@@ -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) {

fs/cifs/sess.c +1 -1
index 6b140e1..17ae0db 100644
@@ -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;
fs/cifs/smbencrypt.c +0 -34
index 1525d5e..92291c1 100644
@@ -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

fs/cifs/smbencrypt.c +2 -1
-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;

fs/cifs/smbencrypt.c +6 -12
@@ -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

fs/cifs/smbencrypt.c +2 -1
-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];

fs/cifs/smbencrypt.c SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24) · line 324

Quoted 8 lines
fs/cifs/smbencrypt.c +1 -1
@@ -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;

But for really minor nits, looks correct.

#4 lore raw
In reply to a message not in the archive
Quoted 191 lines · On Sun, 27 Mar 2011 14:56:48 +0200 Oskar Liljeblad…

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.)

---
 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(-)
fs/cifs/cifsencrypt.c +4 -4
index 5bb4b09..3c1306d 100644
@@ -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);
fs/cifs/cifsproto.h +5 -3
index e42dc82..fd6d873 100644
@@ -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 */
fs/cifs/connect.c +1 -1
index 96544a4..3c0190f 100644
@@ -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) {
fs/cifs/sess.c +1 -1
index 6b140e1..17ae0db 100644
@@ -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;
fs/cifs/smbencrypt.c +7 -46
index 1525d5e..92291c1 100644
@@ -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;

fs/cifs/smbencrypt.c nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]) · line 239

Quoted 5 lines
fs/cifs/smbencrypt.c +1 -1
@@ -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 */);
			^^^^^^^^^^^^^
		Won't this fail to compile?
Quoted 26 lines
fs/cifs/smbencrypt.c +3 -3
 	/* 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

Signature · 1 line
Jeff Layton <[email protected]>

A message that is not in the archive (sent off-list or not yet received): 20110408093148.748eda25-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org

#6 lore raw
Quoted 218 lines · Jeff Layton
Quoted 191 lines · On Sun, 27 Mar 2011 14:56:48 +0200 Oskar Liljeblad…

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.)

---
 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(-)
fs/cifs/cifsencrypt.c +4 -4
index 5bb4b09..3c1306d 100644
@@ -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);
fs/cifs/cifsproto.h +5 -3
index e42dc82..fd6d873 100644
@@ -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 */
fs/cifs/connect.c +0 -0
index 96544a4..3c0190f 100644
@@ -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) {

fs/cifs/sess.c +1 -1
index 6b140e1..17ae0db 100644
@@ -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;
fs/cifs/smbencrypt.c +0 -34
index 1525d5e..92291c1 100644
@@ -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

fs/cifs/smbencrypt.c +2 -1
-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;

fs/cifs/smbencrypt.c +5 -11
@@ -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;

fs/cifs/smbencrypt.c nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]) · line 239

Quoted 5 lines
fs/cifs/smbencrypt.c +1 -1
@@ -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 */);

                       ^^^^^^^^^^^^^
               Won't this fail to compile?

Quoted 17 lines
fs/cifs/smbencrypt.c +0 -0
       /* 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

fs/cifs/smbencrypt.c +2 -1
-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];

fs/cifs/smbencrypt.c +0 -0
@@ -356,7 +318,7 @@ SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24)
       memset(p16, '\0', 16);
       memset(p21, '\0', 21);
 
Quoted 14 lines
Quoted 9 lines
fs/cifs/smbencrypt.c +1 -2
-     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

--
Jeff Layton <[email protected]>

Indeed, missed that.

#7 lore raw
In reply to a message not in the archive
Quoted 192 lines · Jeff Layton
Quoted 189 lines · On Sun, 27 Mar 2011 14:56:48 +0200 Oskar Liljeblad…

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.)

---
 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(-)
fs/cifs/cifsencrypt.c +4 -4
index 5bb4b09..3c1306d 100644
@@ -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);
fs/cifs/cifsproto.h +5 -3
index e42dc82..fd6d873 100644
@@ -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 */
fs/cifs/connect.c +1 -1
index 96544a4..3c0190f 100644
@@ -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) {
fs/cifs/sess.c +1 -1
index 6b140e1..17ae0db 100644
@@ -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;
fs/cifs/smbencrypt.c +7 -46
index 1525d5e..92291c1 100644
@@ -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);
 
Quoted 9 lines

fs/cifs/smbencrypt.c nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]) · line 239

Quoted 7 lines
fs/cifs/smbencrypt.c +1 -1
 	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 */);
			^^^^^^^^^^^^^
		Won't this fail to compile?

Yes, but it's inside a function which is commented out and not compiled. Instead of adding an extra parameter to the function (which would be required) I decided just to put a reminder there if that function is ever used in the future.

#if 0 /* currently unused */
/* Does both the NT and LM owfs of a user's password */ static void
nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16])

{
        char passwd[514];

        memset(passwd, '\0', 514);
        if (strlen(pwd) < 513)
                strcpy(passwd, pwd);
        else
                memcpy(passwd, pwd, 512);
        /* Calculate the MD4 hash (NT compatible) of the password */
        memset(nt_p16, '\0', 16);
        E_md4hash(passwd, nt_p16, /* put nls codepage here */);

        /* Mangle the passwords into Lanman format */
        passwd[14] = '\0';

/* strupper(passwd); */

        /* Calculate the SMB (lanman) hash functions of the password */

        memset(p16, '\0', 16);
        E_P16((unsigned char *) passwd, (unsigned char *) p16);

        /* clear out local copy of user's password (just being paranoid). */
        memset(passwd, '\0', sizeof(passwd));
}

#endif

A message that is not in the archive (sent off-list or not yet received): [email protected]

#9 lore raw
Quoted 236 lines · On Fri, 8 Apr 2011 16:11:12 +0200 Oskar Liljeblad…
Quoted 192 lines · Jeff Layton
Quoted 189 lines · On Sun, 27 Mar 2011 14:56:48 +0200 Oskar Liljeblad…

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.)

---
 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(-)
fs/cifs/cifsencrypt.c +4 -4
index 5bb4b09..3c1306d 100644
@@ -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);
fs/cifs/cifsproto.h +5 -3
index e42dc82..fd6d873 100644
@@ -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 */
fs/cifs/connect.c +1 -1
index 96544a4..3c0190f 100644
@@ -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) {
fs/cifs/sess.c +1 -1
index 6b140e1..17ae0db 100644
@@ -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;
fs/cifs/smbencrypt.c +7 -46
index 1525d5e..92291c1 100644
@@ -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);
 
Quoted 9 lines

fs/cifs/smbencrypt.c nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]) · line 239

Quoted 7 lines
fs/cifs/smbencrypt.c +1 -1
 	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 */);
			^^^^^^^^^^^^^
		Won't this fail to compile?

Yes, but it's inside a function which is commented out and not compiled. Instead of adding an extra parameter to the function (which would be required) I decided just to put a reminder there if that function is ever used in the future.

#if 0 /* currently unused */
/* Does both the NT and LM owfs of a user's password */ static void
nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16])

{
        char passwd[514];

        memset(passwd, '\0', 514);
        if (strlen(pwd) < 513)
                strcpy(passwd, pwd);
        else
                memcpy(passwd, pwd, 512);
        /* Calculate the MD4 hash (NT compatible) of the password */
        memset(nt_p16, '\0', 16);
        E_md4hash(passwd, nt_p16, /* put nls codepage here */);

        /* Mangle the passwords into Lanman format */
        passwd[14] = '\0';

/* strupper(passwd); */

        /* Calculate the SMB (lanman) hash functions of the password */

        memset(p16, '\0', 16);
        E_P16((unsigned char *) passwd, (unsigned char *) p16);

        /* clear out local copy of user's password (just being paranoid). */
        memset(passwd, '\0', sizeof(passwd));
}
Quoted 1 line

#endif

Ahh, ok. A perfect case to demonstrate why leaving unused crap lying around like this is a bad idea. Perhaps a better scheme would be a separate patch to just remove this function and then rebase your patch on top of that?

Signature · 1 line
Jeff Layton <[email protected]>

A message that is not in the archive (sent off-list or not yet received): 20110408103118.0f1b2e8b-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org

#11 lore raw
Quoted 241 lines · Jeff Layton
Quoted 230 lines · On Fri, 8 Apr 2011 16:11:12 +0200 Oskar Liljeblad…
Quoted 192 lines · Jeff Layton
Quoted 189 lines · On Sun, 27 Mar 2011 14:56:48 +0200 Oskar Liljeblad…

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.)

---
 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(-)
fs/cifs/cifsencrypt.c +4 -4
index 5bb4b09..3c1306d 100644
@@ -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);
fs/cifs/cifsproto.h +5 -3
index e42dc82..fd6d873 100644
@@ -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 */
fs/cifs/connect.c +0 -0
index 96544a4..3c0190f 100644
@@ -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) {

fs/cifs/sess.c +1 -1
index 6b140e1..17ae0db 100644
@@ -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;
fs/cifs/smbencrypt.c +0 -34
index 1525d5e..92291c1 100644
@@ -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

fs/cifs/smbencrypt.c +2 -1
-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;

fs/cifs/smbencrypt.c +5 -11
@@ -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);
 
Quoted 9 lines

fs/cifs/smbencrypt.c nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]) · line 239

Quoted 7 lines
fs/cifs/smbencrypt.c +1 -1
   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 */);

                    ^^^^^^^^^^^^^
            Won't this fail to compile?

Yes, but it's inside a function which is commented out and not compiled. Instead of adding an extra parameter to the function (which would be required) I decided just to put a reminder there if that function is ever used in the future.

#if 0 /* currently unused */
/* Does both the NT and LM owfs of a user's password */ static void
nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]) {
        char passwd[514];

        memset(passwd, '\0', 514);
        if (strlen(pwd) < 513)
                strcpy(passwd, pwd);
        else
                memcpy(passwd, pwd, 512);
        /* Calculate the MD4 hash (NT compatible) of the password */ memset(nt_p16, '\0', 16);
        E_md4hash(passwd, nt_p16, /* put nls codepage here */);

        /* Mangle the passwords into Lanman format */ passwd[14] = '\0';
/*      strupper(passwd); */

        /* Calculate the SMB (lanman) hash functions of the password */

Quoted 7 lines

        memset(p16, '\0', 16);
        E_P16((unsigned char *) passwd, (unsigned char *) p16);

        /* clear out local copy of user's password (just being paranoid). */ memset(passwd, '\0', sizeof(passwd));
}
#endif

Quoted 8 lines

Ahh, ok. A perfect case to demonstrate why leaving unused crap lying around like this is a bad idea. Perhaps a better scheme would be a separate patch to just remove this function and then rebase your patch on top of that?

--
Jeff Layton <[email protected]>

I will resubmit this patch in a day to two with Jeff's comments incorporated. It fixes bug 7386 on Samba bugzilla.

#12 lore raw
In reply to a message not in the archive
Quoted 211 lines · Oskar Liljeblad

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.)

---
 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(-)
fs/cifs/cifsencrypt.c +4 -4
index 5bb4b09..3c1306d 100644
@@ -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);
fs/cifs/cifsproto.h +5 -3
index e42dc82..fd6d873 100644
@@ -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 */
fs/cifs/connect.c +0 -0
index 96544a4..3c0190f 100644
@@ -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) {

fs/cifs/sess.c +1 -1
index 6b140e1..17ae0db 100644
@@ -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;
fs/cifs/smbencrypt.c +0 -34
index 1525d5e..92291c1 100644
@@ -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

fs/cifs/smbencrypt.c +2 -1
-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;

fs/cifs/smbencrypt.c +6 -12
@@ -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

fs/cifs/smbencrypt.c +2 -1
-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];

fs/cifs/smbencrypt.c SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24) · line 324

Quoted 8 lines
fs/cifs/smbencrypt.c +1 -1
@@ -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;

With this patch, I am unable to mount a share if user's password happens to contain characters like $ e.g. aa$a.
A Windows client can.

A message that is not in the archive (sent off-list or not yet received): BANLkTimEhsjo2vfSE1w-D888hWn72H7Y3A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org

#14 lore raw
Quoted 12 lines · Shirish Pargaonkar
Quoted 12 lines

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.)

[..]

Quoted 3 lines

With this patch, I am unable to mount a share if user's password happens to contain characters like $ e.g. aa$a.
A Windows client can.

Hmm, strange, I was not able to reproduce this problem with domain accounts on Windows 2008 R2. For me $ worked. (That is with locale utf-8 at least.)

REgards,

OSkar

A message that is not in the archive (sent off-list or not yet received): [email protected]

#16 lore raw
Quoted 12 lines · Oskar Liljeblad
Quoted 11 lines · Shirish Pargaonkar
Quoted 11 lines

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.)

Quoted 8 lines
Quoted 1 line
Quoted 1 line

[..]

Quoted 3 lines

With this patch, I am unable to mount a share if user's password happens to contain characters like $ e.g. aa$a.
A Windows client can.

Hmm, strange, I was not able to reproduce this problem with domain accounts on Windows 2008 R2. For me $ worked. (That is with locale utf-8 at least.)

I'm sorry, please disregard my comment. I tested with the wrong kernel. I will try again.

Regards,

Oskar

#17 lore raw
In reply to a message not in the archive
Quoted 214 lines · On Mon, 11 Apr 2011 12:21:59 -0500 Shirish Pargaonkar…
Quoted 213 lines · Oskar Liljeblad

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.)

---
 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(-)
fs/cifs/cifsencrypt.c +4 -4
index 5bb4b09..3c1306d 100644
@@ -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);
fs/cifs/cifsproto.h +5 -3
index e42dc82..fd6d873 100644
@@ -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 */
fs/cifs/connect.c +0 -0
index 96544a4..3c0190f 100644
@@ -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) {

fs/cifs/sess.c +1 -1
index 6b140e1..17ae0db 100644
@@ -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;
fs/cifs/smbencrypt.c +0 -34
index 1525d5e..92291c1 100644
@@ -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

fs/cifs/smbencrypt.c +2 -1
-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;

fs/cifs/smbencrypt.c +6 -12
@@ -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

fs/cifs/smbencrypt.c +2 -1
-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];

fs/cifs/smbencrypt.c +0 -0
@@ -356,7 +318,7 @@ SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24)
        memset(p16, '\0', 16);
        memset(p21, '\0', 21);
 
Quoted 10 lines

fs/cifs/smbencrypt.c SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24) · line 324

Quoted 6 lines
fs/cifs/smbencrypt.c +1 -1
-       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;

With this patch, I am unable to mount a share if user's password happens to contain characters like $ e.g. aa$a.
A Windows client can.

If you compare traces in wireshark, are there differences in how the username is encoded?

Signature · 1 line
Jeff Layton <[email protected]>

A message that is not in the archive (sent off-list or not yet received): 20110411151637.640495a5-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org

#19 lore raw
Quoted 228 lines · Jeff Layton
Quoted 214 lines · On Mon, 11 Apr 2011 12:21:59 -0500 Shirish Pargaonkar…
Quoted 213 lines · Oskar Liljeblad

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.)

---
 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(-)
fs/cifs/cifsencrypt.c +4 -4
index 5bb4b09..3c1306d 100644
@@ -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);
fs/cifs/cifsproto.h +5 -3
index e42dc82..fd6d873 100644
@@ -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 */
fs/cifs/connect.c +0 -0
index 96544a4..3c0190f 100644
@@ -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) {

fs/cifs/sess.c +1 -1
index 6b140e1..17ae0db 100644
@@ -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;
fs/cifs/smbencrypt.c +0 -34
index 1525d5e..92291c1 100644
@@ -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

fs/cifs/smbencrypt.c +2 -1
-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;

fs/cifs/smbencrypt.c +6 -12
@@ -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

fs/cifs/smbencrypt.c +2 -1
-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];

fs/cifs/smbencrypt.c +0 -0
@@ -356,7 +318,7 @@ SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24)
        memset(p16, '\0', 16);
        memset(p21, '\0', 21);
 
Quoted 10 lines

fs/cifs/smbencrypt.c SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24) · line 324

Quoted 6 lines
fs/cifs/smbencrypt.c +1 -1
-       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;

With this patch, I am unable to mount a share if user's password happens to contain characters like $ e.g. aa$a.
A Windows client can.

Quoted 5 lines

If you compare traces in wireshark, are there differences in how the username is encoded?
--
Jeff Layton <[email protected]>

No differences. It is purely password that is making the difference. I compared traces when both cifs and Windows clients were using ntlmssp auth mech.