From 3979877e5606ecc58c5a31bd0078c6d80ba9cbe7 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 31 May 2006 22:40:51 +0000 Subject: [CIFS] Support for setting up SMB sessions to legacy lanman servers --- fs/cifs/cifsencrypt.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'fs/cifs/cifsencrypt.c') diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index e7d63737e651..08781a4698b4 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -225,6 +225,8 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_ user_name_len = strlen(ses->userName); if(user_name_len > MAX_USERNAME_SIZE) return -EINVAL; + if(ses->domainName == NULL) + return -EINVAL; /* BB should we use CIFS_LINUX_DOM */ dom_name_len = strlen(ses->domainName); if(dom_name_len > MAX_USERNAME_SIZE) return -EINVAL; -- cgit v1.2.3 From 7c7b25bc8e392aea781324efa771bc191377b876 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 1 Jun 2006 19:20:10 +0000 Subject: [CIFS] Support for setting up SMB sessions to legacy lanman servers part 2 --- fs/cifs/cifs_debug.c | 4 +-- fs/cifs/cifsencrypt.c | 40 +++++++++++++++++++-- fs/cifs/cifsglob.h | 2 +- fs/cifs/cifspdu.h | 3 +- fs/cifs/cifsproto.h | 3 ++ fs/cifs/cifssmb.c | 27 +++++++++++--- fs/cifs/connect.c | 47 +++++++++++++++---------- fs/cifs/netmisc.c | 2 +- fs/cifs/sess.c | 97 ++++++++++++++++++++++++++++----------------------- 9 files changed, 150 insertions(+), 75 deletions(-) (limited to 'fs/cifs/cifsencrypt.c') diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 7f4013a8607f..4e10e21c54fd 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -508,7 +508,7 @@ cifs_proc_init(void) pde->write_proc = multiuser_mount_write; pde = - create_proc_read_entry("ExtendedSecurity", 0, proc_fs_cifs, + create_proc_read_entry("SecurityFlags", 0, proc_fs_cifs, extended_security_read, NULL); if (pde) pde->write_proc = extended_security_write; @@ -547,7 +547,7 @@ cifs_proc_clean(void) remove_proc_entry("MultiuserMount", proc_fs_cifs); remove_proc_entry("OplockEnabled", proc_fs_cifs); /* remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); */ - remove_proc_entry("ExtendedSecurity",proc_fs_cifs); + remove_proc_entry("SecurityFlags",proc_fs_cifs); /* remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); */ remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs); remove_proc_entry("Experimental",proc_fs_cifs); diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 08781a4698b4..e11d8c6bb227 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -26,6 +26,7 @@ #include "md5.h" #include "cifs_unicode.h" #include "cifsproto.h" +#include /* Calculate and return the CIFS signature based on the mac key and the smb pdu */ /* the 16 byte signature must be allocated by the caller */ @@ -35,6 +36,8 @@ extern void mdfour(unsigned char *out, unsigned char *in, int n); extern void E_md4hash(const unsigned char *passwd, unsigned char *p16); +extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, + unsigned char *p24); static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, const char * key, char * signature) @@ -45,7 +48,7 @@ static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, return -EINVAL; MD5Init(&context); - MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16); + MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16); MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length); MD5Final(signature,&context); return 0; @@ -90,7 +93,7 @@ static int cifs_calc_signature2(const struct kvec * iov, int n_vec, return -EINVAL; MD5Init(&context); - MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16); + MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16); for(i=0;ipassword, CIFS_ENCPWD_SIZE); + + /* calculate old style session key */ + /* calling toupper is less broken than repeatedly + calling nls_toupper would be since that will never + work for UTF8, but neither handles multibyte code pages + but the only alternative would be converting to UCS-16 (Unicode) + (using a routine something like UniStrupr) then + uppercasing and then converting back from Unicode - which + would only worth doing it if we knew it were utf8. Basically + utf8 and other multibyte codepages each need their own strupper + function since a byte at a time will ont work. */ + + for(i = 0; i < CIFS_ENCPWD_SIZE; i++) { + password_with_pad[i] = toupper(password_with_pad[i]); + } + + SMBencrypt(password_with_pad, ses->server->cryptKey, lnm_session_key); + /* clear password before we return/free memory */ + memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); +} +#endif /* CIFS_WEAK_PW_HASH */ + void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response) { struct HMACMD5Context context; diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 7a042041a16a..975e69a2e1c4 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -158,7 +158,7 @@ struct TCP_Server_Info { /* 16th byte of RFC1001 workstation name is always null */ char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL]; __u32 sequence_number; /* needed for CIFS PDU signature */ - char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; + char mac_signing_key[CIFS_SESS_KEY_SIZE + 16]; }; /* diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index e0ff9b56cc4c..135941738d9d 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -116,7 +116,8 @@ /* * Size of the session key (crypto key encrypted with the password */ -#define CIFS_SESSION_KEY_SIZE (24) +#define CIFS_SESS_KEY_SIZE (24) +#define V2_SESS_KEY_SIZE (86) /* * Maximum user name length diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index ff78cf7b0d1b..59b037f14511 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -287,6 +287,9 @@ extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key, extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, struct nls_table *); extern void CalcNTLMv2_response(const struct cifsSesInfo *,char * ); +#ifdef CONFIG_CIFS_WEAK_PW_HASH +extern void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key); +#endif /* CIFS_WEAK_PW_HASH */ extern int CIFSSMBCopy(int xid, struct cifsTconInfo *source_tcon, const char *fromName, diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index da3154fa9c8a..6b5be6d59f07 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -438,12 +438,19 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) goto neg_err_exit; } else if((pSMBr->hdr.WordCount == 13) && (pSMBr->DialectIndex == LANMAN_PROT)) { +#ifdef CONFIG_CIFS_WEAK_PW_HASH struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr; - - /* BB Mark ses struct as negotiated lanman level BB */ - server->secType = LANMAN; + if((extended_security & CIFSSEC_MAY_LANMAN) || + (extended_security & CIFSSEC_MAY_PLNTXT)) + server->secType = LANMAN; + else { + cERROR(1, ("mount failed weak security disabled" + " in /proc/fs/cifs/SecurityFlags")); + rc = -EOPNOTSUPP; + goto neg_err_exit; + } server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode); server->maxReq = le16_to_cpu(rsp->MaxMpxCount); server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize), @@ -469,6 +476,11 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) } cFYI(1,("LANMAN negotiated")); /* BB removeme BB */ +#else /* weak security disabled */ + cERROR(1,("mount failed, cifs module not built with " + "CIFS_WEAK_PW_HASH support")); + rc = -EOPNOTSUPP; +#endif /* WEAK_PW_HASH */ goto neg_err_exit; } else if(pSMBr->hdr.WordCount != 17) { /* unknown wct */ @@ -479,8 +491,13 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) server->secMode = pSMBr->SecurityMode; if((server->secMode & SECMODE_USER) == 0) cFYI(1,("share mode security")); - server->secType = NTLM; /* BB override default for - NTLMv2 or kerberos v5 */ + + if(extended_security & CIFSSEC_MUST_NTLMV2) + server->secType = NTLMv2; + else + server->secType = NTLM; + /* else krb5 ... */ + /* one byte - no need to convert this or EncryptionKeyLen from little endian */ server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 7ffb8f244f6a..e6f3d2fff6c0 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1990,7 +1990,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, static int CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, - char session_key[CIFS_SESSION_KEY_SIZE], + char session_key[CIFS_SESS_KEY_SIZE], const struct nls_table *nls_codepage) { struct smb_hdr *smb_buffer; @@ -2048,15 +2048,15 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); pSMB->req_no_secext.CaseInsensitivePasswordLength = - cpu_to_le16(CIFS_SESSION_KEY_SIZE); + cpu_to_le16(CIFS_SESS_KEY_SIZE); pSMB->req_no_secext.CaseSensitivePasswordLength = - cpu_to_le16(CIFS_SESSION_KEY_SIZE); + cpu_to_le16(CIFS_SESS_KEY_SIZE); bcc_ptr = pByteArea(smb_buffer); - memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE); - bcc_ptr += CIFS_SESSION_KEY_SIZE; - memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE); - bcc_ptr += CIFS_SESSION_KEY_SIZE; + memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE); + bcc_ptr += CIFS_SESS_KEY_SIZE; + memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE); + bcc_ptr += CIFS_SESS_KEY_SIZE; if (ses->capabilities & CAP_UNICODE) { if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */ @@ -3004,14 +3004,14 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, SecurityBlob->LmChallengeResponse.Buffer = 0; SecurityBlob->NtChallengeResponse.Length = - cpu_to_le16(CIFS_SESSION_KEY_SIZE); + cpu_to_le16(CIFS_SESS_KEY_SIZE); SecurityBlob->NtChallengeResponse.MaximumLength = - cpu_to_le16(CIFS_SESSION_KEY_SIZE); - memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE); + cpu_to_le16(CIFS_SESS_KEY_SIZE); + memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE); SecurityBlob->NtChallengeResponse.Buffer = cpu_to_le32(SecurityBlobLength); - SecurityBlobLength += CIFS_SESSION_KEY_SIZE; - bcc_ptr += CIFS_SESSION_KEY_SIZE; + SecurityBlobLength += CIFS_SESS_KEY_SIZE; + bcc_ptr += CIFS_SESS_KEY_SIZE; if (ses->capabilities & CAP_UNICODE) { if (domain == NULL) { @@ -3350,22 +3350,33 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr = &pSMB->Password[0]; if((ses->server->secMode) & SECMODE_USER) { pSMB->PasswordLength = cpu_to_le16(1); /* minimum */ + *bcc_ptr = 0; /* password is null byte */ bcc_ptr++; /* skip password */ + /* already aligned so no need to do it below */ } else { - pSMB->PasswordLength = cpu_to_le16(CIFS_SESSION_KEY_SIZE); + pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE); /* BB FIXME add code to fail this if NTLMv2 or Kerberos specified as required (when that support is added to the vfs in the future) as only NTLM or the much - weaker LANMAN (which we do not send) is accepted + weaker LANMAN (which we do not send by default) is accepted by Samba (not sure whether other servers allow NTLMv2 password here) */ +#ifdef CONFIG_CIFS_WEAK_PW_HASH + if((extended_security & CIFSSEC_MAY_LANMAN) && + (ses->server->secType == LANMAN)) + calc_lanman_hash(ses, bcc_ptr); + else +#endif /* CIFS_WEAK_PW_HASH */ SMBNTencrypt(ses->password, ses->server->cryptKey, bcc_ptr); - bcc_ptr += CIFS_SESSION_KEY_SIZE; - *bcc_ptr = 0; - bcc_ptr++; /* align */ + bcc_ptr += CIFS_SESS_KEY_SIZE; + if(ses->capabilities & CAP_UNICODE) { + /* must align unicode strings */ + *bcc_ptr = 0; /* null byte password */ + bcc_ptr++; + } } if(ses->server->secMode & @@ -3507,7 +3518,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, struct nls_table * nls_info) { int rc = 0; - char ntlm_session_key[CIFS_SESSION_KEY_SIZE]; + char ntlm_session_key[CIFS_SESS_KEY_SIZE]; int ntlmv2_flag = FALSE; int first_time = 0; diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index 5de74d216fdd..a0bcdd6f4a67 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -84,7 +84,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = { static const struct smb_to_posix_error mapping_table_ERRSRV[] = { {ERRerror, -EIO}, - {ERRbadpw, -EPERM}, + {ERRbadpw, -EACCES}, /* was EPERM */ {ERRbadtype, -EREMOTE}, {ERRaccess, -EACCES}, {ERRinvtid, -ENXIO}, diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index fdc248fffa0a..a52aacb3feff 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -28,12 +28,8 @@ #include "cifs_debug.h" #include "ntlmssp.h" #include "nterr.h" -#include #include -extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, - unsigned char *p24); - extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); @@ -80,7 +76,7 @@ static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) return capabilities; } -void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, +static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, const struct nls_table * nls_cp) { char * bcc_ptr = *pbcc_area; @@ -130,7 +126,7 @@ void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, *pbcc_area = bcc_ptr; } -void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, +static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, const struct nls_table * nls_cp) { char * bcc_ptr = *pbcc_area; @@ -173,7 +169,7 @@ void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, *pbcc_area = bcc_ptr; } -int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses, +static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses, const struct nls_table * nls_cp) { int rc = 0; @@ -255,7 +251,7 @@ int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses, return rc; } -int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses, +static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses, const struct nls_table * nls_cp) { int rc = 0; @@ -317,7 +313,6 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, { int rc = 0; int wct; - int i; struct smb_hdr *smb_buf; char *bcc_ptr; SESSION_SETUP_ANDX *pSMB; @@ -343,7 +338,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, return -EOPNOTSUPP; #endif wct = 10; /* lanman 2 style sessionsetup */ - } else if(type == NTLM) /* NTLMv2 may retry NTLM */ + } else if((type == NTLM) || (type == NTLMv2)) /* NTLMv2 may retry NTLM */ wct = 13; /* old style NTLM sessionsetup */ else /* same size for negotiate or auth, NTLMSSP or extended security */ wct = 12; @@ -360,41 +355,22 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, if(type == LANMAN) { #ifdef CONFIG_CIFS_WEAK_PW_HASH - char lnm_session_key[CIFS_SESSION_KEY_SIZE]; - char password_with_pad[CIFS_ENCPWD_SIZE]; + char lnm_session_key[CIFS_SESS_KEY_SIZE]; /* no capabilities flags in old lanman negotiation */ - pSMB->old_req.PasswordLength = CIFS_SESSION_KEY_SIZE; + pSMB->old_req.PasswordLength = CIFS_SESS_KEY_SIZE; /* BB calculate hash with password */ /* and copy into bcc */ - memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); - strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE); - - /* calculate old style session key */ - /* toupper may be less broken then repeatedly calling - nls_toupper would be, but neither handles multibyte code pages - but the only alternative would be converting to UCS-16 (Unicode) - uppercasing and converting back which is only worth doing if - we knew it were utf8. utf8 code page needs its own - toupper and tolower and strnicmp functions */ - - for(i = 0; i< CIFS_ENCPWD_SIZE; i++) { - password_with_pad[i] = toupper(password_with_pad[i]); - } - - SMBencrypt(password_with_pad, ses->server->cryptKey, - lnm_session_key); + calc_lanman_hash(ses, lnm_session_key); #ifdef CONFIG_CIFS_DEBUG2 cifs_dump_mem("cryptkey: ",ses->server->cryptKey, - CIFS_SESSION_KEY_SIZE); + CIFS_SESS_KEY_SIZE); #endif - /* clear password before we return/free memory */ - memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); - memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESSION_KEY_SIZE); - bcc_ptr += CIFS_SESSION_KEY_SIZE; + memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESS_KEY_SIZE); + bcc_ptr += CIFS_SESS_KEY_SIZE; /* can not sign if LANMAN negotiated so no need to calculate signing key? but what if server @@ -406,13 +382,13 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); #endif } else if (type == NTLM) { - char ntlm_session_key[CIFS_SESSION_KEY_SIZE]; + char ntlm_session_key[CIFS_SESS_KEY_SIZE]; pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); pSMB->req_no_secext.CaseInsensitivePasswordLength = - cpu_to_le16(CIFS_SESSION_KEY_SIZE); + cpu_to_le16(CIFS_SESS_KEY_SIZE); pSMB->req_no_secext.CaseSensitivePasswordLength = - cpu_to_le16(CIFS_SESSION_KEY_SIZE); + cpu_to_le16(CIFS_SESS_KEY_SIZE); /* calculate session key */ SMBNTencrypt(ses->password, ses->server->cryptKey, @@ -420,15 +396,48 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, if(first_time) /* should this be moved into common code with similar ntlmv2 path? */ - cifs_calculate_mac_key( - ses->server->mac_signing_key, + cifs_calculate_mac_key( ses->server->mac_signing_key, ntlm_session_key, ses->password); /* copy session key */ - memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESSION_KEY_SIZE); - bcc_ptr += CIFS_SESSION_KEY_SIZE; - memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESSION_KEY_SIZE); - bcc_ptr += CIFS_SESSION_KEY_SIZE; + memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESS_KEY_SIZE); + bcc_ptr += CIFS_SESS_KEY_SIZE; + memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESS_KEY_SIZE); + bcc_ptr += CIFS_SESS_KEY_SIZE; + if(ses->capabilities & CAP_UNICODE) + unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); + else + ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); + } else if (type == NTLMv2) { + char * v2_sess_key = kmalloc(V2_SESS_KEY_SIZE, GFP_KERNEL); + + if(v2_sess_key == NULL) { + cifs_small_buf_release(smb_buf); + return -ENOMEM; + } + + pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); + + /* LM2 password would be here if we supported it */ + pSMB->req_no_secext.CaseInsensitivePasswordLength = 0; + /* cpu_to_le16(LM2_SESS_KEY_SIZE); */ + + pSMB->req_no_secext.CaseSensitivePasswordLength = + cpu_to_le16(V2_SESS_KEY_SIZE); + + /* calculate session key */ + CalcNTLMv2_response(ses, v2_sess_key); + if(first_time) /* should this be moved into common code + with similar ntlmv2 path? */ + /* cifs_calculate_ntlmv2_mac_key(ses->server->mac_signing_key, + response BB FIXME, v2_sess_key); */ + + /* copy session key */ + + /* memcpy(bcc_ptr, (char *)ntlm_session_key,LM2_SESS_KEY_SIZE); + bcc_ptr += LM2_SESS_KEY_SIZE; */ + memcpy(bcc_ptr, (char *)v2_sess_key, V2_SESS_KEY_SIZE); + bcc_ptr += V2_SESS_KEY_SIZE; if(ses->capabilities & CAP_UNICODE) unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); else -- cgit v1.2.3 From bdc4bf6e8ac8cc29c61c2f0dc61d9776ef9a8ed4 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 2 Jun 2006 22:57:13 +0000 Subject: [CIFS] Support for older servers which require plaintext passwords disabled by default, but can be enabled via proc for servers which require such support. Also includes support for setting security flags for cifs. See fs/cifs/README Signed-off-by: Steve French --- fs/cifs/cifs_debug.c | 56 ++++++++++++++++++++++++++++++++++++--------------- fs/cifs/cifsencrypt.c | 9 +++++++++ fs/cifs/cifssmb.c | 7 +++++++ 3 files changed, 56 insertions(+), 16 deletions(-) (limited to 'fs/cifs/cifsencrypt.c') diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 4e10e21c54fd..7c0015a96959 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -445,8 +445,8 @@ static read_proc_t traceSMB_read; static write_proc_t traceSMB_write; static read_proc_t multiuser_mount_read; static write_proc_t multiuser_mount_write; -static read_proc_t extended_security_read; -static write_proc_t extended_security_write; +static read_proc_t security_flags_read; +static write_proc_t security_flags_write; /* static read_proc_t ntlmv2_enabled_read; static write_proc_t ntlmv2_enabled_write; static read_proc_t packet_signing_enabled_read; @@ -509,9 +509,9 @@ cifs_proc_init(void) pde = create_proc_read_entry("SecurityFlags", 0, proc_fs_cifs, - extended_security_read, NULL); + security_flags_read, NULL); if (pde) - pde->write_proc = extended_security_write; + pde->write_proc = security_flags_write; pde = create_proc_read_entry("LookupCacheEnabled", 0, proc_fs_cifs, @@ -832,7 +832,7 @@ multiuser_mount_write(struct file *file, const char __user *buffer, } static int -extended_security_read(char *page, char **start, off_t off, +security_flags_read(char *page, char **start, off_t off, int count, int *eof, void *data) { int len; @@ -853,26 +853,50 @@ extended_security_read(char *page, char **start, off_t off, return len; } static int -extended_security_write(struct file *file, const char __user *buffer, +security_flags_write(struct file *file, const char __user *buffer, unsigned long count, void *data) { + unsigned int flags; + char flags_string[12]; char c; - int rc; + cERROR(1,("size %ld",count)); /* BB removeme BB */ - if((count < 2) || (count > 8)) + + if((count < 1) || (count > 11)) return -EINVAL; - rc = get_user(c, buffer); + memset(flags_string, 0, 12); -/* BB fixme need to parse more characters in order to handle CIFSSEC flags */ + if(copy_from_user(flags_string, buffer, count)) + return -EFAULT; - if (rc) - return rc; - if (c == '0' || c == 'n' || c == 'N') - extended_security = CIFSSEC_DEF; /* default */ - else if (c == '1' || c == 'y' || c == 'Y') - extended_security = CIFSSEC_MAX; + if(count < 3) { + /* single char or single char followed by null */ + c = flags_string[0]; + if (c == '0' || c == 'n' || c == 'N') + extended_security = CIFSSEC_DEF; /* default */ + else if (c == '1' || c == 'y' || c == 'Y') + extended_security = CIFSSEC_MAX; + return count; + } + /* else we have a number */ + + flags = simple_strtoul(flags_string, NULL, 0); + + cERROR(1,("sec flags 0x%x", flags)); /* BB FIXME make cFYI */ + + if(flags <= 0) { + cERROR(1,("invalid security flags %s",flags_string)); + return -EINVAL; + } + if((flags & CIFSSEC_MASK) != CIFSSEC_MASK) { + cERROR(1,("attempt to set unsupported security flags 0x%d", + flags & ~CIFSSEC_MASK)); + return -EINVAL; + } + /* flags look ok - update the global security flags for cifs module */ + extended_security = flags; return count; } diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index e11d8c6bb227..3ae964bbfdc3 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -271,9 +271,18 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key) int i; char password_with_pad[CIFS_ENCPWD_SIZE]; + if(ses->server == NULL) + return; + memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE); + if((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0) + if(extended_security & CIFSSEC_MAY_PLNTXT) { + memcpy(lnm_session_key, password_with_pad, CIFS_ENCPWD_SIZE); + return; + } + /* calculate old style session key */ /* calling toupper is less broken than repeatedly calling nls_toupper would be since that will never diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index b8c236be4d85..77cca3809467 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -492,6 +492,13 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) server->secMode = pSMBr->SecurityMode; if((server->secMode & SECMODE_USER) == 0) cFYI(1,("share mode security")); + + if((server->secMode & SECMODE_PW_ENCRYPT) == 0) +#ifdef CONFIG_CIFS_WEAK_PW_HASH + if ((extended_security & CIFSSEC_MAY_PLNTXT) == 0) +#endif /* CIFS_WEAK_PW_HASH */ + cERROR(1,("Server requests plain text password" + " but client support disabled")); if(extended_security & CIFSSEC_MUST_NTLMV2) server->secType = NTLMv2; -- cgit v1.2.3 From f64b23ae4aef9f69d71ea41529a188acd5ab4930 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 5 Jun 2006 05:27:37 +0000 Subject: [CIFS] NTLMv2 support part 2 Still need to fill in response structure and check that hash works Signed-off-by: Steve French --- fs/cifs/cifsencrypt.c | 2 ++ fs/cifs/cifspdu.h | 27 ++++++++++++++++++++++++--- fs/cifs/sess.c | 13 +++++++++---- 3 files changed, 35 insertions(+), 7 deletions(-) (limited to 'fs/cifs/cifsencrypt.c') diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 3ae964bbfdc3..24ab770f60dc 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -306,6 +306,8 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key) void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response) { + /* BB FIXME - update struct ntlmv2_response and change calling convention + of this function */ struct HMACMD5Context context; memcpy(v2_session_response + 8, ses->server->cryptKey,8); /* gen_blob(v2_session_response + 16); */ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index e714803a52dc..503b7e32ede3 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -117,7 +117,6 @@ * Size of the session key (crypto key encrypted with the password */ #define CIFS_SESS_KEY_SIZE (24) -#define V2_SESS_KEY_SIZE (86) /* * Maximum user name length @@ -539,7 +538,7 @@ typedef union smb_com_session_setup_andx { /* unsigned char * NativeOS; */ /* unsigned char * NativeLanMan; */ /* unsigned char * PrimaryDomain; */ - } __attribute__((packed)) resp; /* NTLM response format (with or without extended security */ + } __attribute__((packed)) resp; /* NTLM response with or without extended sec*/ struct { /* request format */ struct smb_hdr hdr; /* wct = 10 */ @@ -573,6 +572,26 @@ typedef union smb_com_session_setup_andx { } __attribute__((packed)) old_resp; /* pre-NTLM (LANMAN2.1) response */ } __attribute__((packed)) SESSION_SETUP_ANDX; +/* format of NLTMv2 Response ie "case sensitive password" hash when NTLMv2 */ + +struct ntlmssp2_name { + __le16 type; + __le16 length; +/* char name[length]; */ +} __attribute__((packed)); + +struct ntlmv2_resp { + char ntlmv2_hash[CIFS_ENCPWD_SIZE]; + __le32 blob_sign; + __u32 reserved; + __le64 time; + __u64 client_chal; /* random */ + __u32 reserved2; + struct ntlmssp2_name names[1]; + /* array of name entries could follow ending in minimum 4 byte struct */ +} __attribute__((packed)); + + #define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux" /* Capabilities bits (for NTLM SessSetup request) */ @@ -603,7 +622,9 @@ typedef struct smb_com_tconx_req { } __attribute__((packed)) TCONX_REQ; typedef struct smb_com_tconx_rsp { - struct smb_hdr hdr; /* wct = 3 *//* note that Win2000 has sent wct=7 in some cases on responses. Four unspecified words followed OptionalSupport */ + struct smb_hdr hdr; /* wct = 3 note that Win2000 has sent wct = 7 + in some cases on responses. Four unspecified + words followed OptionalSupport */ __u8 AndXCommand; __u8 AndXReserved; __le16 AndXOffset; diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 1fe9461c6dca..9ce628df29b4 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -411,7 +411,11 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, else ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); } else if (type == NTLMv2) { - char * v2_sess_key = kmalloc(V2_SESS_KEY_SIZE, GFP_KERNEL); + char * v2_sess_key = kmalloc(sizeof(struct ntlmv2_resp), + GFP_KERNEL); + + /* BB FIXME change all users of v2_sess_key to + struct ntlmv2_resp */ if(v2_sess_key == NULL) { cifs_small_buf_release(smb_buf); @@ -425,7 +429,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, /* cpu_to_le16(LM2_SESS_KEY_SIZE); */ pSMB->req_no_secext.CaseSensitivePasswordLength = - cpu_to_le16(V2_SESS_KEY_SIZE); + cpu_to_le16(sizeof(struct ntlmv2_resp)); /* calculate session key */ CalcNTLMv2_response(ses, v2_sess_key); @@ -438,8 +442,9 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, /* memcpy(bcc_ptr, (char *)ntlm_session_key,LM2_SESS_KEY_SIZE); bcc_ptr += LM2_SESS_KEY_SIZE; */ - memcpy(bcc_ptr, (char *)v2_sess_key, V2_SESS_KEY_SIZE); - bcc_ptr += V2_SESS_KEY_SIZE; + memcpy(bcc_ptr, (char *)v2_sess_key, sizeof(struct ntlmv2_resp)); + bcc_ptr += sizeof(struct ntlmv2_resp); + kfree(v2_sess_key); if(ses->capabilities & CAP_UNICODE) unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); else -- cgit v1.2.3 From 6d027cfdb19c26df3151a519ed55acfe2c4cb7c3 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 5 Jun 2006 16:26:05 +0000 Subject: [CIFS] NTLMv2 support part 3 Response struct filled in exacty for 16 byte hash which we need to check more to make sure it works. Signed-off-by: Steve French --- fs/cifs/cifsencrypt.c | 17 +++++++++++++++-- fs/cifs/cifspdu.h | 2 +- fs/cifs/cifsproto.h | 1 + fs/cifs/sess.c | 6 +++--- 4 files changed, 20 insertions(+), 6 deletions(-) (limited to 'fs/cifs/cifsencrypt.c') diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 24ab770f60dc..09f94617e534 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -27,6 +27,7 @@ #include "cifs_unicode.h" #include "cifsproto.h" #include +#include /* Calculate and return the CIFS signature based on the mac key and the smb pdu */ /* the 16 byte signature must be allocated by the caller */ @@ -304,10 +305,22 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key) } #endif /* CIFS_WEAK_PW_HASH */ +void setup_ntlmv2_rsp(const struct cifsSesInfo * ses, char * resp_buf) +{ + struct ntlmv2_resp * buf = (struct ntlmv2_resp *)resp_buf; + + buf->blob_signature = cpu_to_le32(0x00000101); + buf->reserved = 0; + buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); + get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); + buf->reserved2 = 0; + buf->names[0].type = 0; + buf->names[0].length = 0; + /* calculate buf->ntlmv2_hash */ +} + void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response) { - /* BB FIXME - update struct ntlmv2_response and change calling convention - of this function */ struct HMACMD5Context context; memcpy(v2_session_response + 8, ses->server->cryptKey,8); /* gen_blob(v2_session_response + 16); */ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 503b7e32ede3..5250b93d3098 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -582,7 +582,7 @@ struct ntlmssp2_name { struct ntlmv2_resp { char ntlmv2_hash[CIFS_ENCPWD_SIZE]; - __le32 blob_sign; + __le32 blob_signature; __u32 reserved; __le64 time; __u64 client_chal; /* random */ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 59b037f14511..824afb937a6f 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -287,6 +287,7 @@ extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key, extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, struct nls_table *); extern void CalcNTLMv2_response(const struct cifsSesInfo *,char * ); +extern void setup_ntlmv2_rsp(const struct cifsSesInfo *, char *); #ifdef CONFIG_CIFS_WEAK_PW_HASH extern void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key); #endif /* CIFS_WEAK_PW_HASH */ diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 9ce628df29b4..c6fd01f55e90 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -411,8 +411,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, else ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); } else if (type == NTLMv2) { - char * v2_sess_key = kmalloc(sizeof(struct ntlmv2_resp), - GFP_KERNEL); + char * v2_sess_key = + kmalloc(sizeof(struct ntlmv2_resp), GFP_KERNEL); /* BB FIXME change all users of v2_sess_key to struct ntlmv2_resp */ @@ -432,7 +432,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, cpu_to_le16(sizeof(struct ntlmv2_resp)); /* calculate session key */ - CalcNTLMv2_response(ses, v2_sess_key); + setup_ntlmv2_rsp(ses, v2_sess_key); if(first_time) /* should this be moved into common code with similar ntlmv2 path? */ /* cifs_calculate_ntlmv2_mac_key(ses->server->mac_signing_key, -- cgit v1.2.3 From a8ee03441f66e0674e641c0cbe1a9534cdee968f Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 5 Jun 2006 23:34:19 +0000 Subject: [CIFS] NTLMv2 support part 4 Signed-off-by: Steve French --- fs/cifs/cifs_debug.c | 2 +- fs/cifs/cifsencrypt.c | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) (limited to 'fs/cifs/cifsencrypt.c') diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 2f55edf2eeea..96abeb738978 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -889,7 +889,7 @@ security_flags_write(struct file *file, const char __user *buffer, } if(flags & ~CIFSSEC_MASK) { - cERROR(1,("attempt to set unsupported security flags 0x%d", + cERROR(1,("attempt to set unsupported security flags 0x%x", flags & ~CIFSSEC_MASK)); return -EINVAL; } diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 09f94617e534..8bcb1da3270e 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -305,8 +305,44 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key) } #endif /* CIFS_WEAK_PW_HASH */ +static int calc_ntlmv2_hash(const struct cifsSesInfo *ses, + char * ntv2_hash) +{ + int rc = 0; + int len; + char nt_hash[16]; + struct HMACMD5Context * pctxt; + + pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL); + + if(pctxt == NULL) + return -ENOMEM; + + /* calculate md4 hash of password */ + E_md4hash(ses->password, nt_hash); + + /* convERT Domainname to unicode and uppercase */ + hmac_md5_init_limK_to_64(nt_hash, 16, pctxt); + + /* convert ses->userName to unicode and uppercase */ + + /* len = ... */ /* BB FIXME BB */ + + /* hmac_md5_update(user, len, pctxt); */ + + /* convert ses->domainName to unicode and uppercase */ + + /* len = ... */ /* BB FIXME BB */ + /* hmac_md5_update(domain, len, pctxt); */ + + hmac_md5_final(ntv2_hash, pctxt); + + return rc; +} + void setup_ntlmv2_rsp(const struct cifsSesInfo * ses, char * resp_buf) { + int rc; struct ntlmv2_resp * buf = (struct ntlmv2_resp *)resp_buf; buf->blob_signature = cpu_to_le32(0x00000101); @@ -316,7 +352,11 @@ void setup_ntlmv2_rsp(const struct cifsSesInfo * ses, char * resp_buf) buf->reserved2 = 0; buf->names[0].type = 0; buf->names[0].length = 0; + /* calculate buf->ntlmv2_hash */ + rc = calc_ntlmv2_hash(ses,buf->ntlmv2_hash); + if(rc) + cERROR(1,("could not get v2 hash rc %d",rc)); } void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response) -- cgit v1.2.3 From 1717ffc58850dfa9e08b4977f8d0323cb3336863 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 8 Jun 2006 05:41:32 +0000 Subject: [CIFS] NTLMv2 support part 5 NTLMv2 authentication (stronger authentication than default NTLM) which many servers support now works. There was a problem with the construction of the security blob in the older code. Currently requires /proc/fs/cifs/Experimental to be set to 2 and /proc/fs/cifs/SecurityFlags to be set to 0x4004 (to require using NTLMv2 instead of default of NTLM) Next we will check signing to make sure optional NTLMv2 packet signing also works. Signed-off-by: Steve French --- fs/cifs/CHANGES | 4 +++- fs/cifs/cifsencrypt.c | 60 +++++++++++++++++++++++++++++++++++---------------- fs/cifs/cifsproto.h | 8 ++++--- fs/cifs/sess.c | 2 +- 4 files changed, 50 insertions(+), 24 deletions(-) (limited to 'fs/cifs/cifsencrypt.c') diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 7e0058bc3dd9..79a202b8f66a 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -5,7 +5,9 @@ session setup needed for OS/2 and older servers such as Windows 95 and 98. Fix oops on ls to OS/2 servers. Add support for level 1 FindFirst so we can do search (ls etc.) to OS/2. Do not send NTCreateX or recent levels of FindFirst unless server says it supports NT SMBs -(instead use legacy equivalents from LANMAN dialect). +(instead use legacy equivalents from LANMAN dialect). Fix to allow +NTLMv2 authentication support (now can use stronger password hashing +on mount if corresponding /proc/fs/cifs/SecurityFlags is set (0x4004) Version 1.43 ------------ diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 8bcb1da3270e..a89efaf78a26 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -212,7 +212,8 @@ int cifs_calculate_mac_key(char * key, const char * rn, const char * password) return 0; } -int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_info) +int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, + const struct nls_table * nls_info) { char temp_hash[16]; struct HMACMD5Context ctx; @@ -305,13 +306,15 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key) } #endif /* CIFS_WEAK_PW_HASH */ -static int calc_ntlmv2_hash(const struct cifsSesInfo *ses, - char * ntv2_hash) +static int calc_ntlmv2_hash(struct cifsSesInfo *ses, + const struct nls_table * nls_cp) { int rc = 0; int len; char nt_hash[16]; struct HMACMD5Context * pctxt; + wchar_t * user; + wchar_t * domain; pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL); @@ -321,26 +324,44 @@ static int calc_ntlmv2_hash(const struct cifsSesInfo *ses, /* calculate md4 hash of password */ E_md4hash(ses->password, nt_hash); - /* convERT Domainname to unicode and uppercase */ + /* convert Domainname to unicode and uppercase */ hmac_md5_init_limK_to_64(nt_hash, 16, pctxt); /* convert ses->userName to unicode and uppercase */ - - /* len = ... */ /* BB FIXME BB */ - - /* hmac_md5_update(user, len, pctxt); */ + len = strlen(ses->userName); + user = kmalloc(2 + (len * 2), GFP_KERNEL); + if(user == NULL) + goto calc_exit_2; + len = cifs_strtoUCS(user, ses->userName, len, nls_cp); + UniStrupr(user); + hmac_md5_update((char *)user, 2*len, pctxt); /* convert ses->domainName to unicode and uppercase */ + if(ses->domainName) { + len = strlen(ses->domainName); - /* len = ... */ /* BB FIXME BB */ - /* hmac_md5_update(domain, len, pctxt); */ + domain = kmalloc(2 + (len * 2), GFP_KERNEL); + if(domain == NULL) + goto calc_exit_1; + len = cifs_strtoUCS(domain, ses->domainName, len, nls_cp); + UniStrupr(domain); - hmac_md5_final(ntv2_hash, pctxt); + hmac_md5_update((char *)domain, 2*len, pctxt); + + kfree(domain); + } +calc_exit_1: + kfree(user); +calc_exit_2: + /* BB FIXME what about bytes 24 through 40 of the signing key? + compare with the NTLM example */ + hmac_md5_final(ses->server->mac_signing_key, pctxt); return rc; } -void setup_ntlmv2_rsp(const struct cifsSesInfo * ses, char * resp_buf) +void setup_ntlmv2_rsp(struct cifsSesInfo * ses, char * resp_buf, + const struct nls_table * nls_cp) { int rc; struct ntlmv2_resp * buf = (struct ntlmv2_resp *)resp_buf; @@ -348,27 +369,28 @@ void setup_ntlmv2_rsp(const struct cifsSesInfo * ses, char * resp_buf) buf->blob_signature = cpu_to_le32(0x00000101); buf->reserved = 0; buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); - get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); + get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); buf->reserved2 = 0; buf->names[0].type = 0; buf->names[0].length = 0; /* calculate buf->ntlmv2_hash */ - rc = calc_ntlmv2_hash(ses,buf->ntlmv2_hash); + rc = calc_ntlmv2_hash(ses, nls_cp); if(rc) cERROR(1,("could not get v2 hash rc %d",rc)); + CalcNTLMv2_response(ses, resp_buf); } -void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response) +void CalcNTLMv2_response(const struct cifsSesInfo * ses, char * v2_session_response) { struct HMACMD5Context context; + /* rest of v2 struct already generated */ memcpy(v2_session_response + 8, ses->server->cryptKey,8); - /* gen_blob(v2_session_response + 16); */ hmac_md5_init_limK_to_64(ses->server->mac_signing_key, 16, &context); - hmac_md5_update(ses->server->cryptKey,8,&context); -/* hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */ + hmac_md5_update(v2_session_response+8, + sizeof(struct ntlmv2_resp) - 8, &context); hmac_md5_final(v2_session_response,&context); - cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); /* BB removeme BB */ +/* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */ } diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 824afb937a6f..7ffd5b0d63cf 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -285,9 +285,11 @@ extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *, extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key, __u32 expected_sequence_number); extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); -extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, struct nls_table *); -extern void CalcNTLMv2_response(const struct cifsSesInfo *,char * ); -extern void setup_ntlmv2_rsp(const struct cifsSesInfo *, char *); +extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, + const struct nls_table *); +extern void CalcNTLMv2_response(const struct cifsSesInfo *, char * ); +extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *, + const struct nls_table *); #ifdef CONFIG_CIFS_WEAK_PW_HASH extern void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key); #endif /* CIFS_WEAK_PW_HASH */ diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index c6fd01f55e90..c039b54206aa 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -432,7 +432,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, cpu_to_le16(sizeof(struct ntlmv2_resp)); /* calculate session key */ - setup_ntlmv2_rsp(ses, v2_sess_key); + setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp); if(first_time) /* should this be moved into common code with similar ntlmv2 path? */ /* cifs_calculate_ntlmv2_mac_key(ses->server->mac_signing_key, -- cgit v1.2.3