The command "mount.cifs //servername/share /mnt -ocredentials=path/to/file" fails if the password contains a non-ASCII character. I tested this with a password containing the £ (British pound) sign and I got the following error: mount error 13 = Permission denied Refer to the mount.cifs(8) manual page (e.g.man mount.cifs) The credentials file appears to be UTF-8, with all the characters one byte wide except for the "£" sign which is encoded as "0xc2 0xa3". I am using samba-client-3.0.33-3.15.el5_4.1 with linux-2.6.27 and Windows 2003 Server to host the share.
It is a problem. I put a $ in the password and authentication fails.
I am also facing this issue. We are using french domain. Username and password contains ù character. I am able to map the share from windows with username and password which contains ù character. CalcNTLMv2_partial_mac_key() function is correctly printing password in logs(if /proc/fs/cifs/Debug and /proc/fs/cifs/cifsFYI are set to 1). But I don't know why mount is failing. Is it a problem because CIFS converts username to uppercase letters and then send it?
Or there could be issue with MD5 encryption of username and password where non-ascii characters are part of password.
There is no CalcNTLMv2_partial_mac_key in current cifs code. Did yo mean CalcNTLMv2_response() instead? What is the version of cifs module that you are using? NTLMv1, NTLMv2, and NTLMv2 within NTLMSSP make use of NTLM hash generated using MD4 algorithm on the Unicode password (the password you provide is converted to Unicode password). Have you tried mounts using -o sec=ntlm or -o sec=ntlmv2 or -o sec=ntlmssp options?
Reassigning this to Shirish since he is far more well versed in NTLM auth nuances than I am...
Now, that said, there's a patch that was sent to the mailing list a while back by Oskar Liljeblad. Subject: [PATCH] CIFS: Assume passwords are encoded according to iocharset ...I wonder if that might fix this. That _my_mbstowcs routine has always seemed quite suspect.
Yes. I think that patch needs to be tried/tested here. The only suspect is conversion of text password (pertaining to a locale) to unicode password and Oscar's fix is worth trying here.
Thanks for proving pointer. I have taken Oskar's changes and tried mount. <1> For ascii(normal) username, mount worked where password contains ù character <2> For username and password which contains ù character, mount failed. At least something is working now. Thanks.
Hi Rahul, We found that non-ascii usernames worked provided the credentials file (passed to "mount" with -ocredentials=<file>) was in UTF-8. In our python code we got non-ascii usernames working like this: -- snip -- f.write("username=%s\npassword=%s\n" % \ (username.encode("utf-8"),password.encode("utf-8"))) --/snip -- It sounds like the patch you tested fixes the other half of the problem, namely non-ascii passwords! Could you attach the patch to this ticket for reference? Thanks
Patch for reference: https://patchwork.kernel.org/patch/666551/ Patch ============================================================================== diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 5bb4b09..3c1306d 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -226,7 +226,7 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu, } /* first calculate 24 bytes ntlm response and then 16 byte session key */ -int setup_ntlm_response(struct cifs_ses *ses) +int setup_ntlm_response(struct cifs_ses *ses, const struct nls_table *nls_cp) { int rc = 0; unsigned int temp_len = CIFS_SESS_KEY_SIZE + CIFS_AUTH_RESP_SIZE; @@ -243,14 +243,14 @@ int setup_ntlm_response(struct cifs_ses *ses) ses->auth_key.len = temp_len; rc = SMBNTencrypt(ses->password, ses->server->cryptkey, - ses->auth_key.response + CIFS_SESS_KEY_SIZE); + ses->auth_key.response + CIFS_SESS_KEY_SIZE, nls_cp); if (rc) { cFYI(1, "%s Can't generate NTLM response, error: %d", __func__, rc); return rc; } - rc = E_md4hash(ses->password, temp_key); + rc = E_md4hash(ses->password, temp_key, nls_cp); if (rc) { cFYI(1, "%s Can't generate NT hash, error: %d", __func__, rc); return rc; @@ -458,7 +458,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, } /* calculate md4 hash of password */ - E_md4hash(ses->password, nt_hash); + E_md4hash(ses->password, nt_hash, nls_cp); crypto_shash_setkey(ses->server->secmech.hmacmd5, nt_hash, CIFS_NTHASH_SIZE); diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index e42dc82..fd6d873 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -376,8 +376,9 @@ extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *, extern int cifs_verify_signature(struct smb_hdr *, struct TCP_Server_Info *server, __u32 expected_sequence_number); -extern int SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *); -extern int setup_ntlm_response(struct cifs_ses *); +extern int SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *, + const struct nls_table *); +extern int setup_ntlm_response(struct cifs_ses *, const struct nls_table *); extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *); extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *); extern void cifs_crypto_shash_release(struct TCP_Server_Info *); @@ -429,7 +430,8 @@ extern int CIFSCheckMFSymlink(struct cifs_fattr *fattr, const unsigned char *path, struct cifs_sb_info *cifs_sb, int xid); extern int mdfour(unsigned char *, unsigned char *, int); -extern int E_md4hash(const unsigned char *passwd, unsigned char *p16); +extern int E_md4hash(const unsigned char *passwd, unsigned char *p16, + const struct nls_table *codepage); extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24); #endif /* _CIFSPROTO_H */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 96544a4..3c0190f 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3060,7 +3060,7 @@ CIFSTCon(unsigned int xid, struct cifs_ses *ses, else #endif /* CIFS_WEAK_PW_HASH */ rc = SMBNTencrypt(tcon->password, ses->server->cryptkey, - bcc_ptr); + bcc_ptr, nls_codepage); bcc_ptr += CIFS_AUTH_RESP_SIZE; if (ses->capabilities & CAP_UNICODE) { diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 6b140e1..17ae0db 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -694,7 +694,7 @@ ssetup_ntlmssp_authenticate: cpu_to_le16(CIFS_AUTH_RESP_SIZE); /* calculate ntlm response and session key */ - rc = setup_ntlm_response(ses); + rc = setup_ntlm_response(ses, nls_cp); if (rc) { cERROR(1, "Error %d during NTLM authentication", rc); goto ssetup_exit; diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c index 1525d5e..92291c1 100644 --- a/fs/cifs/smbencrypt.c +++ b/fs/cifs/smbencrypt.c @@ -195,46 +195,13 @@ SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24) return rc; } -/* Routines for Windows NT MD4 Hash functions. */ -static int -_my_wcslen(__u16 *str) -{ - int len = 0; - while (*str++ != 0) - len++; - return len; -} - -/* - * Convert a string into an NT UNICODE string. - * Note that regardless of processor type - * this must be in intel (little-endian) - * format. - */ - -static int -_my_mbstowcs(__u16 *dst, const unsigned char *src, int len) -{ /* BB not a very good conversion routine - change/fix */ - int i; - __u16 val; - - for (i = 0; i < len; i++) { - val = *src; - SSVAL(dst, 0, val); - dst++; - src++; - if (val == 0) - break; - } - return i; -} - /* * Creates the MD4 Hash of the users password in NT UNICODE. */ int -E_md4hash(const unsigned char *passwd, unsigned char *p16) +E_md4hash(const unsigned char *passwd, unsigned char *p16, + const struct nls_table *codepage) { int rc; int len; @@ -242,20 +209,14 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16) /* Password cannot be longer than 128 characters */ if (passwd) { - len = strlen((char *) passwd); - if (len > 128) - len = 128; - /* Password must be converted to NT unicode */ - _my_mbstowcs(wpwd, passwd, len); - } else + len = cifs_strtoUCS(wpwd, passwd, 128, codepage); + } else { len = 0; + *wpwd = 0; /* Ensure string is null terminated */ + } - wpwd[len] = 0; /* Ensure string is null terminated */ - /* Calculate length in bytes */ - len = _my_wcslen(wpwd) * sizeof(__u16); - - rc = mdfour(p16, (unsigned char *) wpwd, len); + rc = mdfour(p16, (unsigned char *) wpwd, len * sizeof(__u16)); memset(wpwd, 0, 129 * 2); return rc; @@ -275,7 +236,7 @@ nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]) memcpy(passwd, pwd, 512); /* Calculate the MD4 hash (NT compatible) of the password */ memset(nt_p16, '\0', 16); - E_md4hash(passwd, nt_p16); + E_md4hash(passwd, nt_p16, /* put nls codepage here */); /* Mangle the passwords into Lanman format */ passwd[14] = '\0'; @@ -348,7 +309,8 @@ NTLMSSPOWFencrypt(unsigned char passwd[8], /* Does the NT MD4 hash then des encryption. */ int -SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24) +SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24, + const struct nls_table *codepage) { int rc; unsigned char p16[16], p21[21]; @@ -356,7 +318,7 @@ SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24) memset(p16, '\0', 16); memset(p21, '\0', 21); - rc = E_md4hash(passwd, p16); + rc = E_md4hash(passwd, p16, codepage); if (rc) { cFYI(1, "%s Can't generate NT hash, error: %d", __func__, rc); return rc; ============================================================================== In my code, <1> I have removed functions _my_wcslen and _my_mbstowcs and replaced call for _my_mbstowcs() by cifs_strtoUCS(). <2> Added codepage argument to functions E_md4hash,SMBNTencrypt,nt_lm_owf_gen.
Now mount is working for username and password which contains ù character. toupper() was a problem for username. Instead used UniStrupr() after converting username to unicode. It worked.
So just to be clear... this can be fixed entirely in kernel code? If so, can we push a patch to the kernel maintainers?
(In reply to comment #11) Which function was changed to call Unistrupr instead of toupper, calc_lanman_hash()?
user name should not matter, lowercase or upper case. None of the auth mechs (lm, ntlm, and ntlmv2) use it so it should not matter. Only thing uppercase matters is 'uppercase Unicode target user database' (typically domain name or server name in some cases) which is used during response blob calculation for ntlmv2 auth mech.
I am using old version of CIFS 1.47 which comes with cent OS 5.2. It has function CalcNTLMv2_partial_mac_key() which was converting username by using function toupper(). For username ùùùùù, with normal(ascii) password, mount was failing. toupper was called before converting to UTF8. So after utf8 conversion, I called UniStrupr() [instead of calling toupper before conversion]. I need to check how it is with latest code.
(In reply to comment #15) I think with the latest kernel/cifs_code, Oskar' patch would suffice.
In the later cifs code, in function calc_ntlmv2_hash in file cifsencrypt.c, Unistrupr() is already used for user name. And I stated incorrect in comment #14, in ntlmv2 auth, uppercase unicode user name is used to generate Target String (along with uppercase unicoe target user database).
(In reply to comment #1) > It is a problem. I put a $ in the password and authentication fails. If there is a character like $ in password, password needs a single quotes around it. And just to reiterate, all we need i Oskar's patch and bug would be fixed.
I was wondering what the status of this bug was? Seems like it's been a bit since it was assigned, didn't notice if it had been fixed for a release. Thanks!
just checked that this is fixed. Shirish, Steve: please make sure to keep the status of your bugs up to date and close bugs accordingly when they had beed fixed.