Message ID | 20210817052436.1158186-3-lsahlber@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [1/3] cifs: only compile in smb1ops.c if we configure CIFS_ALLOW_INSECURE_LEGACY | expand |
Fixed minor typo in patch 1 (<ctype.h>) and tentatively pushed all 3 to cifs-2.6.git for-next pending more testing and review On Tue, Aug 17, 2021 at 12:25 AM Ronnie Sahlberg <lsahlber@redhat.com> wrote: > > Move all dependencies of DES into smb1ops.c > Make SMB1 support depend on CONFIG_LIB_DES > > Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com> > --- > fs/cifs/Kconfig | 3 +- > fs/cifs/cifsencrypt.c | 39 ------ > fs/cifs/cifsproto.h | 9 -- > fs/cifs/connect.c | 162 --------------------- > fs/cifs/ntlmssp.h | 1 + > fs/cifs/sess.c | 5 + > fs/cifs/smb1ops.c | 319 ++++++++++++++++++++++++++++++++++++++++++ > fs/cifs/smbencrypt.c | 114 --------------- > 8 files changed, 326 insertions(+), 326 deletions(-) > > diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig > index 7364950a9ef4..c01464476ba9 100644 > --- a/fs/cifs/Kconfig > +++ b/fs/cifs/Kconfig > @@ -16,7 +16,6 @@ config CIFS > select CRYPTO_GCM > select CRYPTO_ECB > select CRYPTO_AES > - select CRYPTO_LIB_DES > select KEYS > select DNS_RESOLVER > select ASN1 > @@ -72,7 +71,7 @@ config CIFS_STATS2 > > config CIFS_ALLOW_INSECURE_LEGACY > bool "Support legacy servers which use less secure dialects" > - depends on CIFS > + depends on CIFS && CRYPTO_LIB_DES > default y > help > Modern dialects, SMB2.1 and later (including SMB3 and 3.1.1), have > diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c > index 79572d18ad7a..7680e0a9bea3 100644 > --- a/fs/cifs/cifsencrypt.c > +++ b/fs/cifs/cifsencrypt.c > @@ -250,45 +250,6 @@ int cifs_verify_signature(struct smb_rqst *rqst, > > } > > -/* first calculate 24 bytes ntlm response and then 16 byte session key */ > -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; > - char temp_key[CIFS_SESS_KEY_SIZE]; > - > - if (!ses) > - return -EINVAL; > - > - ses->auth_key.response = kmalloc(temp_len, GFP_KERNEL); > - if (!ses->auth_key.response) > - return -ENOMEM; > - > - ses->auth_key.len = temp_len; > - > - rc = SMBNTencrypt(ses->password, ses->server->cryptkey, > - ses->auth_key.response + CIFS_SESS_KEY_SIZE, nls_cp); > - if (rc) { > - cifs_dbg(FYI, "%s Can't generate NTLM response, error: %d\n", > - __func__, rc); > - return rc; > - } > - > - rc = E_md4hash(ses->password, temp_key, nls_cp); > - if (rc) { > - cifs_dbg(FYI, "%s Can't generate NT hash, error: %d\n", > - __func__, rc); > - return rc; > - } > - > - rc = mdfour(ses->auth_key.response, temp_key, CIFS_SESS_KEY_SIZE); > - if (rc) > - cifs_dbg(FYI, "%s Can't generate NTLM session key, error: %d\n", > - __func__, rc); > - > - return rc; > -} > - > /* Build a proper attribute value/target info pairs blob. > * Fill in netbios and dns domain name and workstation name > * and client time (total five av pairs and + one end of fields indicator. > diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h > index e0def0f0714b..4a686048f1fa 100644 > --- a/fs/cifs/cifsproto.h > +++ b/fs/cifs/cifsproto.h > @@ -296,10 +296,6 @@ extern int cifs_setup_session(const unsigned int xid, struct cifs_ses *ses, > extern int cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required); > extern int CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses); > > -extern int CIFSTCon(const unsigned int xid, struct cifs_ses *ses, > - const char *tree, struct cifs_tcon *tcon, > - const struct nls_table *); > - > extern int CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon, > const char *searchName, struct cifs_sb_info *cifs_sb, > __u16 *searchHandle, __u16 search_flags, > @@ -498,9 +494,6 @@ extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *, __u32 *); > extern int cifs_verify_signature(struct smb_rqst *rqst, > struct TCP_Server_Info *server, > __u32 expected_sequence_number); > -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 void cifs_crypto_secmech_release(struct TCP_Server_Info *server); > extern int calc_seckey(struct cifs_ses *); > @@ -550,8 +543,6 @@ extern int check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, > extern int mdfour(unsigned char *, unsigned char *, int); > 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); > > extern int > cifs_setup_volume_info(struct smb3_fs_context *ctx, const char *mntopts, const char *devname); > diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c > index 3781eee9360a..7dba7b59dd51 100644 > --- a/fs/cifs/connect.c > +++ b/fs/cifs/connect.c > @@ -3642,168 +3642,6 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx) > } > #endif > > -/* > - * Issue a TREE_CONNECT request. > - */ > -int > -CIFSTCon(const unsigned int xid, struct cifs_ses *ses, > - const char *tree, struct cifs_tcon *tcon, > - const struct nls_table *nls_codepage) > -{ > - struct smb_hdr *smb_buffer; > - struct smb_hdr *smb_buffer_response; > - TCONX_REQ *pSMB; > - TCONX_RSP *pSMBr; > - unsigned char *bcc_ptr; > - int rc = 0; > - int length; > - __u16 bytes_left, count; > - > - if (ses == NULL) > - return -EIO; > - > - smb_buffer = cifs_buf_get(); > - if (smb_buffer == NULL) > - return -ENOMEM; > - > - smb_buffer_response = smb_buffer; > - > - header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX, > - NULL /*no tid */ , 4 /*wct */ ); > - > - smb_buffer->Mid = get_next_mid(ses->server); > - smb_buffer->Uid = ses->Suid; > - pSMB = (TCONX_REQ *) smb_buffer; > - pSMBr = (TCONX_RSP *) smb_buffer_response; > - > - pSMB->AndXCommand = 0xFF; > - pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO); > - bcc_ptr = &pSMB->Password[0]; > - if (tcon->pipe || (ses->server->sec_mode & 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_AUTH_RESP_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 by default) is accepted > - by Samba (not sure whether other servers allow > - NTLMv2 password here) */ > -#ifdef CONFIG_CIFS_WEAK_PW_HASH > - if ((global_secflags & CIFSSEC_MAY_LANMAN) && > - (ses->sectype == LANMAN)) > - calc_lanman_hash(tcon->password, ses->server->cryptkey, > - ses->server->sec_mode & > - SECMODE_PW_ENCRYPT ? true : false, > - bcc_ptr); > - else > -#endif /* CIFS_WEAK_PW_HASH */ > - rc = SMBNTencrypt(tcon->password, ses->server->cryptkey, > - bcc_ptr, nls_codepage); > - if (rc) { > - cifs_dbg(FYI, "%s Can't generate NTLM rsp. Error: %d\n", > - __func__, rc); > - cifs_buf_release(smb_buffer); > - return rc; > - } > - > - bcc_ptr += CIFS_AUTH_RESP_SIZE; > - if (ses->capabilities & CAP_UNICODE) { > - /* must align unicode strings */ > - *bcc_ptr = 0; /* null byte password */ > - bcc_ptr++; > - } > - } > - > - if (ses->server->sign) > - smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; > - > - if (ses->capabilities & CAP_STATUS32) { > - smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; > - } > - if (ses->capabilities & CAP_DFS) { > - smb_buffer->Flags2 |= SMBFLG2_DFS; > - } > - if (ses->capabilities & CAP_UNICODE) { > - smb_buffer->Flags2 |= SMBFLG2_UNICODE; > - length = > - cifs_strtoUTF16((__le16 *) bcc_ptr, tree, > - 6 /* max utf8 char length in bytes */ * > - (/* server len*/ + 256 /* share len */), nls_codepage); > - bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */ > - bcc_ptr += 2; /* skip trailing null */ > - } else { /* ASCII */ > - strcpy(bcc_ptr, tree); > - bcc_ptr += strlen(tree) + 1; > - } > - strcpy(bcc_ptr, "?????"); > - bcc_ptr += strlen("?????"); > - bcc_ptr += 1; > - count = bcc_ptr - &pSMB->Password[0]; > - be32_add_cpu(&pSMB->hdr.smb_buf_length, count); > - pSMB->ByteCount = cpu_to_le16(count); > - > - rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, > - 0); > - > - /* above now done in SendReceive */ > - if (rc == 0) { > - bool is_unicode; > - > - tcon->tidStatus = CifsGood; > - tcon->need_reconnect = false; > - tcon->tid = smb_buffer_response->Tid; > - bcc_ptr = pByteArea(smb_buffer_response); > - bytes_left = get_bcc(smb_buffer_response); > - length = strnlen(bcc_ptr, bytes_left - 2); > - if (smb_buffer->Flags2 & SMBFLG2_UNICODE) > - is_unicode = true; > - else > - is_unicode = false; > - > - > - /* skip service field (NB: this field is always ASCII) */ > - if (length == 3) { > - if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') && > - (bcc_ptr[2] == 'C')) { > - cifs_dbg(FYI, "IPC connection\n"); > - tcon->ipc = true; > - tcon->pipe = true; > - } > - } else if (length == 2) { > - if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) { > - /* the most common case */ > - cifs_dbg(FYI, "disk share connection\n"); > - } > - } > - bcc_ptr += length + 1; > - bytes_left -= (length + 1); > - strlcpy(tcon->treeName, tree, sizeof(tcon->treeName)); > - > - /* mostly informational -- no need to fail on error here */ > - kfree(tcon->nativeFileSystem); > - tcon->nativeFileSystem = cifs_strndup_from_utf16(bcc_ptr, > - bytes_left, is_unicode, > - nls_codepage); > - > - cifs_dbg(FYI, "nativeFileSystem=%s\n", tcon->nativeFileSystem); > - > - if ((smb_buffer_response->WordCount == 3) || > - (smb_buffer_response->WordCount == 7)) > - /* field is in same location */ > - tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport); > - else > - tcon->Flags = 0; > - cifs_dbg(FYI, "Tcon flags: 0x%x\n", tcon->Flags); > - } > - > - cifs_buf_release(smb_buffer); > - return rc; > -} > - > static void delayed_free(struct rcu_head *p) > { > struct cifs_sb_info *cifs_sb = container_of(p, struct cifs_sb_info, rcu); > diff --git a/fs/cifs/ntlmssp.h b/fs/cifs/ntlmssp.h > index 378133ce8869..54f740c75be6 100644 > --- a/fs/cifs/ntlmssp.h > +++ b/fs/cifs/ntlmssp.h > @@ -124,3 +124,4 @@ void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, struct cifs_ses *ses); > int build_ntlmssp_auth_blob(unsigned char **pbuffer, u16 *buflen, > struct cifs_ses *ses, > const struct nls_table *nls_cp); > +int setup_ntlm_response(struct cifs_ses *ses, const struct nls_table *nls_cp); > diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c > index c5785fd3f52e..34a990e1ae44 100644 > --- a/fs/cifs/sess.c > +++ b/fs/cifs/sess.c > @@ -1061,6 +1061,8 @@ sess_auth_lanman(struct sess_data *sess_data) > > #endif > > + > +#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY > static void > sess_auth_ntlm(struct sess_data *sess_data) > { > @@ -1170,6 +1172,7 @@ sess_auth_ntlm(struct sess_data *sess_data) > kfree(ses->auth_key.response); > ses->auth_key.response = NULL; > } > +#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ > > static void > sess_auth_ntlmv2(struct sess_data *sess_data) > @@ -1687,9 +1690,11 @@ static int select_sec(struct cifs_ses *ses, struct sess_data *sess_data) > #else > return -EOPNOTSUPP; > #endif > +#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY > case NTLM: > sess_data->func = sess_auth_ntlm; > break; > +#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ > case NTLMv2: > sess_data->func = sess_auth_ntlmv2; > break; > diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c > index 5444cbc42043..c79d5bb2440d 100644 > --- a/fs/cifs/smb1ops.c > +++ b/fs/cifs/smb1ops.c > @@ -6,6 +6,7 @@ > */ > > #include <ctype.h> > +#include <linux/fips.h> > #include <linux/pagemap.h> > #include <linux/vfs.h> > #include "cifsglob.h" > @@ -14,8 +15,103 @@ > #include "cifspdu.h" > #include "cifs_unicode.h" > #include "fs_context.h" > +#include "ntlmssp.h" > + > +#include <crypto/des.h> > + > +static void > +str_to_key(unsigned char *str, unsigned char *key) > +{ > + int i; > + > + key[0] = str[0] >> 1; > + key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2); > + key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3); > + key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4); > + key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5); > + key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6); > + key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7); > + key[7] = str[6] & 0x7F; > + for (i = 0; i < 8; i++) > + key[i] = (key[i] << 1); > +} > + > +static int > +smbhash(unsigned char *out, const unsigned char *in, unsigned char *key) > +{ > + unsigned char key2[8]; > + struct des_ctx ctx; > + > + str_to_key(key, key2); > + > + if (fips_enabled) { > + cifs_dbg(VFS, "FIPS compliance enabled: DES not permitted\n"); > + return -ENOENT; > + } > + > + des_expand_key(&ctx, key2, DES_KEY_SIZE); > + des_encrypt(&ctx, out, in); > + memzero_explicit(&ctx, sizeof(ctx)); > + > + return 0; > +} > + > +static int > +E_P24(unsigned char *p21, const unsigned char *c8, unsigned char *p24) > +{ > + int rc; > + > + rc = smbhash(p24, c8, p21); > + if (rc) > + return rc; > + rc = smbhash(p24 + 8, c8, p21 + 7); > + if (rc) > + return rc; > + rc = smbhash(p24 + 16, c8, p21 + 14); > + return rc; > +} > > #ifdef CONFIG_CIFS_WEAK_PW_HASH > +static int > +E_P16(unsigned char *p14, unsigned char *p16) > +{ > + int rc; > + unsigned char sp8[8] = > + { 0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 }; > + > + rc = smbhash(p16, sp8, p14); > + if (rc) > + return rc; > + rc = smbhash(p16 + 8, sp8, p14 + 7); > + return rc; > +} > + > +/* > + This implements the X/Open SMB password encryption > + It takes a password, a 8 byte "crypt key" and puts 24 bytes of > + encrypted password into p24 */ > +/* Note that password must be uppercased and null terminated */ > +static int > +SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24) > +{ > + int rc; > + unsigned char p14[14], p16[16], p21[21]; > + > + memset(p14, '\0', 14); > + memset(p16, '\0', 16); > + memset(p21, '\0', 21); > + > + memcpy(p14, passwd, 14); > + rc = E_P16(p14, p16); > + if (rc) > + return rc; > + > + memcpy(p21, p16, 16); > + rc = E_P24(p21, c8, p24); > + > + return rc; > +} > + > int calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, > char *lnm_session_key) > { > @@ -57,6 +153,229 @@ int calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, > } > #endif /* CIFS_WEAK_PW_HASH */ > > +/* Does the NT MD4 hash then des encryption. */ > +static int > +SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24, > + const struct nls_table *codepage) > +{ > + int rc; > + unsigned char p16[16], p21[21]; > + > + memset(p16, '\0', 16); > + memset(p21, '\0', 21); > + > + rc = E_md4hash(passwd, p16, codepage); > + if (rc) { > + cifs_dbg(FYI, "%s Can't generate NT hash, error: %d\n", > + __func__, rc); > + return rc; > + } > + memcpy(p21, p16, 16); > + rc = E_P24(p21, c8, p24); > + return rc; > +} > + > +/* > + * Issue a TREE_CONNECT request. > + */ > +static int > +CIFSTCon(const unsigned int xid, struct cifs_ses *ses, > + const char *tree, struct cifs_tcon *tcon, > + const struct nls_table *nls_codepage) > +{ > + struct smb_hdr *smb_buffer; > + struct smb_hdr *smb_buffer_response; > + TCONX_REQ *pSMB; > + TCONX_RSP *pSMBr; > + unsigned char *bcc_ptr; > + int rc = 0; > + int length; > + __u16 bytes_left, count; > + > + if (ses == NULL) > + return -EIO; > + > + smb_buffer = cifs_buf_get(); > + if (smb_buffer == NULL) > + return -ENOMEM; > + > + smb_buffer_response = smb_buffer; > + > + header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX, > + NULL /*no tid */ , 4 /*wct */ ); > + > + smb_buffer->Mid = get_next_mid(ses->server); > + smb_buffer->Uid = ses->Suid; > + pSMB = (TCONX_REQ *) smb_buffer; > + pSMBr = (TCONX_RSP *) smb_buffer_response; > + > + pSMB->AndXCommand = 0xFF; > + pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO); > + bcc_ptr = &pSMB->Password[0]; > + if (tcon->pipe || (ses->server->sec_mode & 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_AUTH_RESP_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 by default) is accepted > + by Samba (not sure whether other servers allow > + NTLMv2 password here) */ > +#ifdef CONFIG_CIFS_WEAK_PW_HASH > + if ((global_secflags & CIFSSEC_MAY_LANMAN) && > + (ses->sectype == LANMAN)) > + calc_lanman_hash(tcon->password, ses->server->cryptkey, > + ses->server->sec_mode & > + SECMODE_PW_ENCRYPT ? true : false, > + bcc_ptr); > + else > +#endif /* CIFS_WEAK_PW_HASH */ > + rc = SMBNTencrypt(tcon->password, ses->server->cryptkey, > + bcc_ptr, nls_codepage); > + if (rc) { > + cifs_dbg(FYI, "%s Can't generate NTLM rsp. Error: %d\n", > + __func__, rc); > + cifs_buf_release(smb_buffer); > + return rc; > + } > + > + bcc_ptr += CIFS_AUTH_RESP_SIZE; > + if (ses->capabilities & CAP_UNICODE) { > + /* must align unicode strings */ > + *bcc_ptr = 0; /* null byte password */ > + bcc_ptr++; > + } > + } > + > + if (ses->server->sign) > + smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; > + > + if (ses->capabilities & CAP_STATUS32) { > + smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; > + } > + if (ses->capabilities & CAP_DFS) { > + smb_buffer->Flags2 |= SMBFLG2_DFS; > + } > + if (ses->capabilities & CAP_UNICODE) { > + smb_buffer->Flags2 |= SMBFLG2_UNICODE; > + length = > + cifs_strtoUTF16((__le16 *) bcc_ptr, tree, > + 6 /* max utf8 char length in bytes */ * > + (/* server len*/ + 256 /* share len */), nls_codepage); > + bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */ > + bcc_ptr += 2; /* skip trailing null */ > + } else { /* ASCII */ > + strcpy(bcc_ptr, tree); > + bcc_ptr += strlen(tree) + 1; > + } > + strcpy(bcc_ptr, "?????"); > + bcc_ptr += strlen("?????"); > + bcc_ptr += 1; > + count = bcc_ptr - &pSMB->Password[0]; > + be32_add_cpu(&pSMB->hdr.smb_buf_length, count); > + pSMB->ByteCount = cpu_to_le16(count); > + > + rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, > + 0); > + > + /* above now done in SendReceive */ > + if (rc == 0) { > + bool is_unicode; > + > + tcon->tidStatus = CifsGood; > + tcon->need_reconnect = false; > + tcon->tid = smb_buffer_response->Tid; > + bcc_ptr = pByteArea(smb_buffer_response); > + bytes_left = get_bcc(smb_buffer_response); > + length = strnlen(bcc_ptr, bytes_left - 2); > + if (smb_buffer->Flags2 & SMBFLG2_UNICODE) > + is_unicode = true; > + else > + is_unicode = false; > + > + > + /* skip service field (NB: this field is always ASCII) */ > + if (length == 3) { > + if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') && > + (bcc_ptr[2] == 'C')) { > + cifs_dbg(FYI, "IPC connection\n"); > + tcon->ipc = true; > + tcon->pipe = true; > + } > + } else if (length == 2) { > + if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) { > + /* the most common case */ > + cifs_dbg(FYI, "disk share connection\n"); > + } > + } > + bcc_ptr += length + 1; > + bytes_left -= (length + 1); > + strlcpy(tcon->treeName, tree, sizeof(tcon->treeName)); > + > + /* mostly informational -- no need to fail on error here */ > + kfree(tcon->nativeFileSystem); > + tcon->nativeFileSystem = cifs_strndup_from_utf16(bcc_ptr, > + bytes_left, is_unicode, > + nls_codepage); > + > + cifs_dbg(FYI, "nativeFileSystem=%s\n", tcon->nativeFileSystem); > + > + if ((smb_buffer_response->WordCount == 3) || > + (smb_buffer_response->WordCount == 7)) > + /* field is in same location */ > + tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport); > + else > + tcon->Flags = 0; > + cifs_dbg(FYI, "Tcon flags: 0x%x\n", tcon->Flags); > + } > + > + cifs_buf_release(smb_buffer); > + return rc; > +} > + > +/* first calculate 24 bytes ntlm response and then 16 byte session key */ > +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; > + char temp_key[CIFS_SESS_KEY_SIZE]; > + > + if (!ses) > + return -EINVAL; > + > + ses->auth_key.response = kmalloc(temp_len, GFP_KERNEL); > + if (!ses->auth_key.response) > + return -ENOMEM; > + > + ses->auth_key.len = temp_len; > + > + rc = SMBNTencrypt(ses->password, ses->server->cryptkey, > + ses->auth_key.response + CIFS_SESS_KEY_SIZE, nls_cp); > + if (rc) { > + cifs_dbg(FYI, "%s Can't generate NTLM response, error: %d\n", > + __func__, rc); > + return rc; > + } > + > + rc = E_md4hash(ses->password, temp_key, nls_cp); > + if (rc) { > + cifs_dbg(FYI, "%s Can't generate NT hash, error: %d\n", > + __func__, rc); > + return rc; > + } > + > + rc = mdfour(ses->auth_key.response, temp_key, CIFS_SESS_KEY_SIZE); > + if (rc) > + cifs_dbg(FYI, "%s Can't generate NTLM session key, error: %d\n", > + __func__, rc); > + > + return rc; > +} > + > /* > * An NT cancel request header looks just like the original request except: > * > diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c > index 39a938443e3e..0c5617427be9 100644 > --- a/fs/cifs/smbencrypt.c > +++ b/fs/cifs/smbencrypt.c > @@ -18,7 +18,6 @@ > #include <linux/string.h> > #include <linux/kernel.h> > #include <linux/random.h> > -#include <crypto/des.h> > #include "cifs_fs_sb.h" > #include "cifs_unicode.h" > #include "cifspdu.h" > @@ -38,72 +37,6 @@ > #define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8) > #define SSVAL(buf,pos,val) SSVALX((buf),(pos),((__u16)(val))) > > -static void > -str_to_key(unsigned char *str, unsigned char *key) > -{ > - int i; > - > - key[0] = str[0] >> 1; > - key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2); > - key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3); > - key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4); > - key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5); > - key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6); > - key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7); > - key[7] = str[6] & 0x7F; > - for (i = 0; i < 8; i++) > - key[i] = (key[i] << 1); > -} > - > -static int > -smbhash(unsigned char *out, const unsigned char *in, unsigned char *key) > -{ > - unsigned char key2[8]; > - struct des_ctx ctx; > - > - str_to_key(key, key2); > - > - if (fips_enabled) { > - cifs_dbg(VFS, "FIPS compliance enabled: DES not permitted\n"); > - return -ENOENT; > - } > - > - des_expand_key(&ctx, key2, DES_KEY_SIZE); > - des_encrypt(&ctx, out, in); > - memzero_explicit(&ctx, sizeof(ctx)); > - > - return 0; > -} > - > -static int > -E_P16(unsigned char *p14, unsigned char *p16) > -{ > - int rc; > - unsigned char sp8[8] = > - { 0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 }; > - > - rc = smbhash(p16, sp8, p14); > - if (rc) > - return rc; > - rc = smbhash(p16 + 8, sp8, p14 + 7); > - return rc; > -} > - > -static int > -E_P24(unsigned char *p21, const unsigned char *c8, unsigned char *p24) > -{ > - int rc; > - > - rc = smbhash(p24, c8, p21); > - if (rc) > - return rc; > - rc = smbhash(p24 + 8, c8, p21 + 7); > - if (rc) > - return rc; > - rc = smbhash(p24 + 16, c8, p21 + 14); > - return rc; > -} > - > /* produce a md4 message digest from data of length n bytes */ > int > mdfour(unsigned char *md4_hash, unsigned char *link_str, int link_len) > @@ -135,32 +68,6 @@ mdfour(unsigned char *md4_hash, unsigned char *link_str, int link_len) > return rc; > } > > -/* > - This implements the X/Open SMB password encryption > - It takes a password, a 8 byte "crypt key" and puts 24 bytes of > - encrypted password into p24 */ > -/* Note that password must be uppercased and null terminated */ > -int > -SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24) > -{ > - int rc; > - unsigned char p14[14], p16[16], p21[21]; > - > - memset(p14, '\0', 14); > - memset(p16, '\0', 16); > - memset(p21, '\0', 21); > - > - memcpy(p14, passwd, 14); > - rc = E_P16(p14, p16); > - if (rc) > - return rc; > - > - memcpy(p21, p16, 16); > - rc = E_P24(p21, c8, p24); > - > - return rc; > -} > - > /* > * Creates the MD4 Hash of the users password in NT UNICODE. > */ > @@ -187,24 +94,3 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16, > return rc; > } > > -/* Does the NT MD4 hash then des encryption. */ > -int > -SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24, > - const struct nls_table *codepage) > -{ > - int rc; > - unsigned char p16[16], p21[21]; > - > - memset(p16, '\0', 16); > - memset(p21, '\0', 21); > - > - rc = E_md4hash(passwd, p16, codepage); > - if (rc) { > - cifs_dbg(FYI, "%s Can't generate NT hash, error: %d\n", > - __func__, rc); > - return rc; > - } > - memcpy(p21, p16, 16); > - rc = E_P24(p21, c8, p24); > - return rc; > -} > -- > 2.30.2 >
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 7364950a9ef4..c01464476ba9 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig @@ -16,7 +16,6 @@ config CIFS select CRYPTO_GCM select CRYPTO_ECB select CRYPTO_AES - select CRYPTO_LIB_DES select KEYS select DNS_RESOLVER select ASN1 @@ -72,7 +71,7 @@ config CIFS_STATS2 config CIFS_ALLOW_INSECURE_LEGACY bool "Support legacy servers which use less secure dialects" - depends on CIFS + depends on CIFS && CRYPTO_LIB_DES default y help Modern dialects, SMB2.1 and later (including SMB3 and 3.1.1), have diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 79572d18ad7a..7680e0a9bea3 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -250,45 +250,6 @@ int cifs_verify_signature(struct smb_rqst *rqst, } -/* first calculate 24 bytes ntlm response and then 16 byte session key */ -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; - char temp_key[CIFS_SESS_KEY_SIZE]; - - if (!ses) - return -EINVAL; - - ses->auth_key.response = kmalloc(temp_len, GFP_KERNEL); - if (!ses->auth_key.response) - return -ENOMEM; - - ses->auth_key.len = temp_len; - - rc = SMBNTencrypt(ses->password, ses->server->cryptkey, - ses->auth_key.response + CIFS_SESS_KEY_SIZE, nls_cp); - if (rc) { - cifs_dbg(FYI, "%s Can't generate NTLM response, error: %d\n", - __func__, rc); - return rc; - } - - rc = E_md4hash(ses->password, temp_key, nls_cp); - if (rc) { - cifs_dbg(FYI, "%s Can't generate NT hash, error: %d\n", - __func__, rc); - return rc; - } - - rc = mdfour(ses->auth_key.response, temp_key, CIFS_SESS_KEY_SIZE); - if (rc) - cifs_dbg(FYI, "%s Can't generate NTLM session key, error: %d\n", - __func__, rc); - - return rc; -} - /* Build a proper attribute value/target info pairs blob. * Fill in netbios and dns domain name and workstation name * and client time (total five av pairs and + one end of fields indicator. diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index e0def0f0714b..4a686048f1fa 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -296,10 +296,6 @@ extern int cifs_setup_session(const unsigned int xid, struct cifs_ses *ses, extern int cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required); extern int CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses); -extern int CIFSTCon(const unsigned int xid, struct cifs_ses *ses, - const char *tree, struct cifs_tcon *tcon, - const struct nls_table *); - extern int CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon, const char *searchName, struct cifs_sb_info *cifs_sb, __u16 *searchHandle, __u16 search_flags, @@ -498,9 +494,6 @@ extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *, __u32 *); extern int cifs_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, __u32 expected_sequence_number); -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 void cifs_crypto_secmech_release(struct TCP_Server_Info *server); extern int calc_seckey(struct cifs_ses *); @@ -550,8 +543,6 @@ extern int check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, extern int mdfour(unsigned char *, unsigned char *, int); 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); extern int cifs_setup_volume_info(struct smb3_fs_context *ctx, const char *mntopts, const char *devname); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 3781eee9360a..7dba7b59dd51 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3642,168 +3642,6 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx) } #endif -/* - * Issue a TREE_CONNECT request. - */ -int -CIFSTCon(const unsigned int xid, struct cifs_ses *ses, - const char *tree, struct cifs_tcon *tcon, - const struct nls_table *nls_codepage) -{ - struct smb_hdr *smb_buffer; - struct smb_hdr *smb_buffer_response; - TCONX_REQ *pSMB; - TCONX_RSP *pSMBr; - unsigned char *bcc_ptr; - int rc = 0; - int length; - __u16 bytes_left, count; - - if (ses == NULL) - return -EIO; - - smb_buffer = cifs_buf_get(); - if (smb_buffer == NULL) - return -ENOMEM; - - smb_buffer_response = smb_buffer; - - header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX, - NULL /*no tid */ , 4 /*wct */ ); - - smb_buffer->Mid = get_next_mid(ses->server); - smb_buffer->Uid = ses->Suid; - pSMB = (TCONX_REQ *) smb_buffer; - pSMBr = (TCONX_RSP *) smb_buffer_response; - - pSMB->AndXCommand = 0xFF; - pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO); - bcc_ptr = &pSMB->Password[0]; - if (tcon->pipe || (ses->server->sec_mode & 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_AUTH_RESP_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 by default) is accepted - by Samba (not sure whether other servers allow - NTLMv2 password here) */ -#ifdef CONFIG_CIFS_WEAK_PW_HASH - if ((global_secflags & CIFSSEC_MAY_LANMAN) && - (ses->sectype == LANMAN)) - calc_lanman_hash(tcon->password, ses->server->cryptkey, - ses->server->sec_mode & - SECMODE_PW_ENCRYPT ? true : false, - bcc_ptr); - else -#endif /* CIFS_WEAK_PW_HASH */ - rc = SMBNTencrypt(tcon->password, ses->server->cryptkey, - bcc_ptr, nls_codepage); - if (rc) { - cifs_dbg(FYI, "%s Can't generate NTLM rsp. Error: %d\n", - __func__, rc); - cifs_buf_release(smb_buffer); - return rc; - } - - bcc_ptr += CIFS_AUTH_RESP_SIZE; - if (ses->capabilities & CAP_UNICODE) { - /* must align unicode strings */ - *bcc_ptr = 0; /* null byte password */ - bcc_ptr++; - } - } - - if (ses->server->sign) - smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; - - if (ses->capabilities & CAP_STATUS32) { - smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; - } - if (ses->capabilities & CAP_DFS) { - smb_buffer->Flags2 |= SMBFLG2_DFS; - } - if (ses->capabilities & CAP_UNICODE) { - smb_buffer->Flags2 |= SMBFLG2_UNICODE; - length = - cifs_strtoUTF16((__le16 *) bcc_ptr, tree, - 6 /* max utf8 char length in bytes */ * - (/* server len*/ + 256 /* share len */), nls_codepage); - bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */ - bcc_ptr += 2; /* skip trailing null */ - } else { /* ASCII */ - strcpy(bcc_ptr, tree); - bcc_ptr += strlen(tree) + 1; - } - strcpy(bcc_ptr, "?????"); - bcc_ptr += strlen("?????"); - bcc_ptr += 1; - count = bcc_ptr - &pSMB->Password[0]; - be32_add_cpu(&pSMB->hdr.smb_buf_length, count); - pSMB->ByteCount = cpu_to_le16(count); - - rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, - 0); - - /* above now done in SendReceive */ - if (rc == 0) { - bool is_unicode; - - tcon->tidStatus = CifsGood; - tcon->need_reconnect = false; - tcon->tid = smb_buffer_response->Tid; - bcc_ptr = pByteArea(smb_buffer_response); - bytes_left = get_bcc(smb_buffer_response); - length = strnlen(bcc_ptr, bytes_left - 2); - if (smb_buffer->Flags2 & SMBFLG2_UNICODE) - is_unicode = true; - else - is_unicode = false; - - - /* skip service field (NB: this field is always ASCII) */ - if (length == 3) { - if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') && - (bcc_ptr[2] == 'C')) { - cifs_dbg(FYI, "IPC connection\n"); - tcon->ipc = true; - tcon->pipe = true; - } - } else if (length == 2) { - if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) { - /* the most common case */ - cifs_dbg(FYI, "disk share connection\n"); - } - } - bcc_ptr += length + 1; - bytes_left -= (length + 1); - strlcpy(tcon->treeName, tree, sizeof(tcon->treeName)); - - /* mostly informational -- no need to fail on error here */ - kfree(tcon->nativeFileSystem); - tcon->nativeFileSystem = cifs_strndup_from_utf16(bcc_ptr, - bytes_left, is_unicode, - nls_codepage); - - cifs_dbg(FYI, "nativeFileSystem=%s\n", tcon->nativeFileSystem); - - if ((smb_buffer_response->WordCount == 3) || - (smb_buffer_response->WordCount == 7)) - /* field is in same location */ - tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport); - else - tcon->Flags = 0; - cifs_dbg(FYI, "Tcon flags: 0x%x\n", tcon->Flags); - } - - cifs_buf_release(smb_buffer); - return rc; -} - static void delayed_free(struct rcu_head *p) { struct cifs_sb_info *cifs_sb = container_of(p, struct cifs_sb_info, rcu); diff --git a/fs/cifs/ntlmssp.h b/fs/cifs/ntlmssp.h index 378133ce8869..54f740c75be6 100644 --- a/fs/cifs/ntlmssp.h +++ b/fs/cifs/ntlmssp.h @@ -124,3 +124,4 @@ void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, struct cifs_ses *ses); int build_ntlmssp_auth_blob(unsigned char **pbuffer, u16 *buflen, struct cifs_ses *ses, const struct nls_table *nls_cp); +int setup_ntlm_response(struct cifs_ses *ses, const struct nls_table *nls_cp); diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index c5785fd3f52e..34a990e1ae44 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -1061,6 +1061,8 @@ sess_auth_lanman(struct sess_data *sess_data) #endif + +#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY static void sess_auth_ntlm(struct sess_data *sess_data) { @@ -1170,6 +1172,7 @@ sess_auth_ntlm(struct sess_data *sess_data) kfree(ses->auth_key.response); ses->auth_key.response = NULL; } +#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ static void sess_auth_ntlmv2(struct sess_data *sess_data) @@ -1687,9 +1690,11 @@ static int select_sec(struct cifs_ses *ses, struct sess_data *sess_data) #else return -EOPNOTSUPP; #endif +#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY case NTLM: sess_data->func = sess_auth_ntlm; break; +#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ case NTLMv2: sess_data->func = sess_auth_ntlmv2; break; diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index 5444cbc42043..c79d5bb2440d 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c @@ -6,6 +6,7 @@ */ #include <ctype.h> +#include <linux/fips.h> #include <linux/pagemap.h> #include <linux/vfs.h> #include "cifsglob.h" @@ -14,8 +15,103 @@ #include "cifspdu.h" #include "cifs_unicode.h" #include "fs_context.h" +#include "ntlmssp.h" + +#include <crypto/des.h> + +static void +str_to_key(unsigned char *str, unsigned char *key) +{ + int i; + + key[0] = str[0] >> 1; + key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2); + key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3); + key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4); + key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5); + key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6); + key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7); + key[7] = str[6] & 0x7F; + for (i = 0; i < 8; i++) + key[i] = (key[i] << 1); +} + +static int +smbhash(unsigned char *out, const unsigned char *in, unsigned char *key) +{ + unsigned char key2[8]; + struct des_ctx ctx; + + str_to_key(key, key2); + + if (fips_enabled) { + cifs_dbg(VFS, "FIPS compliance enabled: DES not permitted\n"); + return -ENOENT; + } + + des_expand_key(&ctx, key2, DES_KEY_SIZE); + des_encrypt(&ctx, out, in); + memzero_explicit(&ctx, sizeof(ctx)); + + return 0; +} + +static int +E_P24(unsigned char *p21, const unsigned char *c8, unsigned char *p24) +{ + int rc; + + rc = smbhash(p24, c8, p21); + if (rc) + return rc; + rc = smbhash(p24 + 8, c8, p21 + 7); + if (rc) + return rc; + rc = smbhash(p24 + 16, c8, p21 + 14); + return rc; +} #ifdef CONFIG_CIFS_WEAK_PW_HASH +static int +E_P16(unsigned char *p14, unsigned char *p16) +{ + int rc; + unsigned char sp8[8] = + { 0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 }; + + rc = smbhash(p16, sp8, p14); + if (rc) + return rc; + rc = smbhash(p16 + 8, sp8, p14 + 7); + return rc; +} + +/* + This implements the X/Open SMB password encryption + It takes a password, a 8 byte "crypt key" and puts 24 bytes of + encrypted password into p24 */ +/* Note that password must be uppercased and null terminated */ +static int +SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24) +{ + int rc; + unsigned char p14[14], p16[16], p21[21]; + + memset(p14, '\0', 14); + memset(p16, '\0', 16); + memset(p21, '\0', 21); + + memcpy(p14, passwd, 14); + rc = E_P16(p14, p16); + if (rc) + return rc; + + memcpy(p21, p16, 16); + rc = E_P24(p21, c8, p24); + + return rc; +} + int calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, char *lnm_session_key) { @@ -57,6 +153,229 @@ int calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, } #endif /* CIFS_WEAK_PW_HASH */ +/* Does the NT MD4 hash then des encryption. */ +static int +SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24, + const struct nls_table *codepage) +{ + int rc; + unsigned char p16[16], p21[21]; + + memset(p16, '\0', 16); + memset(p21, '\0', 21); + + rc = E_md4hash(passwd, p16, codepage); + if (rc) { + cifs_dbg(FYI, "%s Can't generate NT hash, error: %d\n", + __func__, rc); + return rc; + } + memcpy(p21, p16, 16); + rc = E_P24(p21, c8, p24); + return rc; +} + +/* + * Issue a TREE_CONNECT request. + */ +static int +CIFSTCon(const unsigned int xid, struct cifs_ses *ses, + const char *tree, struct cifs_tcon *tcon, + const struct nls_table *nls_codepage) +{ + struct smb_hdr *smb_buffer; + struct smb_hdr *smb_buffer_response; + TCONX_REQ *pSMB; + TCONX_RSP *pSMBr; + unsigned char *bcc_ptr; + int rc = 0; + int length; + __u16 bytes_left, count; + + if (ses == NULL) + return -EIO; + + smb_buffer = cifs_buf_get(); + if (smb_buffer == NULL) + return -ENOMEM; + + smb_buffer_response = smb_buffer; + + header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX, + NULL /*no tid */ , 4 /*wct */ ); + + smb_buffer->Mid = get_next_mid(ses->server); + smb_buffer->Uid = ses->Suid; + pSMB = (TCONX_REQ *) smb_buffer; + pSMBr = (TCONX_RSP *) smb_buffer_response; + + pSMB->AndXCommand = 0xFF; + pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO); + bcc_ptr = &pSMB->Password[0]; + if (tcon->pipe || (ses->server->sec_mode & 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_AUTH_RESP_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 by default) is accepted + by Samba (not sure whether other servers allow + NTLMv2 password here) */ +#ifdef CONFIG_CIFS_WEAK_PW_HASH + if ((global_secflags & CIFSSEC_MAY_LANMAN) && + (ses->sectype == LANMAN)) + calc_lanman_hash(tcon->password, ses->server->cryptkey, + ses->server->sec_mode & + SECMODE_PW_ENCRYPT ? true : false, + bcc_ptr); + else +#endif /* CIFS_WEAK_PW_HASH */ + rc = SMBNTencrypt(tcon->password, ses->server->cryptkey, + bcc_ptr, nls_codepage); + if (rc) { + cifs_dbg(FYI, "%s Can't generate NTLM rsp. Error: %d\n", + __func__, rc); + cifs_buf_release(smb_buffer); + return rc; + } + + bcc_ptr += CIFS_AUTH_RESP_SIZE; + if (ses->capabilities & CAP_UNICODE) { + /* must align unicode strings */ + *bcc_ptr = 0; /* null byte password */ + bcc_ptr++; + } + } + + if (ses->server->sign) + smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + + if (ses->capabilities & CAP_STATUS32) { + smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; + } + if (ses->capabilities & CAP_DFS) { + smb_buffer->Flags2 |= SMBFLG2_DFS; + } + if (ses->capabilities & CAP_UNICODE) { + smb_buffer->Flags2 |= SMBFLG2_UNICODE; + length = + cifs_strtoUTF16((__le16 *) bcc_ptr, tree, + 6 /* max utf8 char length in bytes */ * + (/* server len*/ + 256 /* share len */), nls_codepage); + bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */ + bcc_ptr += 2; /* skip trailing null */ + } else { /* ASCII */ + strcpy(bcc_ptr, tree); + bcc_ptr += strlen(tree) + 1; + } + strcpy(bcc_ptr, "?????"); + bcc_ptr += strlen("?????"); + bcc_ptr += 1; + count = bcc_ptr - &pSMB->Password[0]; + be32_add_cpu(&pSMB->hdr.smb_buf_length, count); + pSMB->ByteCount = cpu_to_le16(count); + + rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, + 0); + + /* above now done in SendReceive */ + if (rc == 0) { + bool is_unicode; + + tcon->tidStatus = CifsGood; + tcon->need_reconnect = false; + tcon->tid = smb_buffer_response->Tid; + bcc_ptr = pByteArea(smb_buffer_response); + bytes_left = get_bcc(smb_buffer_response); + length = strnlen(bcc_ptr, bytes_left - 2); + if (smb_buffer->Flags2 & SMBFLG2_UNICODE) + is_unicode = true; + else + is_unicode = false; + + + /* skip service field (NB: this field is always ASCII) */ + if (length == 3) { + if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') && + (bcc_ptr[2] == 'C')) { + cifs_dbg(FYI, "IPC connection\n"); + tcon->ipc = true; + tcon->pipe = true; + } + } else if (length == 2) { + if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) { + /* the most common case */ + cifs_dbg(FYI, "disk share connection\n"); + } + } + bcc_ptr += length + 1; + bytes_left -= (length + 1); + strlcpy(tcon->treeName, tree, sizeof(tcon->treeName)); + + /* mostly informational -- no need to fail on error here */ + kfree(tcon->nativeFileSystem); + tcon->nativeFileSystem = cifs_strndup_from_utf16(bcc_ptr, + bytes_left, is_unicode, + nls_codepage); + + cifs_dbg(FYI, "nativeFileSystem=%s\n", tcon->nativeFileSystem); + + if ((smb_buffer_response->WordCount == 3) || + (smb_buffer_response->WordCount == 7)) + /* field is in same location */ + tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport); + else + tcon->Flags = 0; + cifs_dbg(FYI, "Tcon flags: 0x%x\n", tcon->Flags); + } + + cifs_buf_release(smb_buffer); + return rc; +} + +/* first calculate 24 bytes ntlm response and then 16 byte session key */ +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; + char temp_key[CIFS_SESS_KEY_SIZE]; + + if (!ses) + return -EINVAL; + + ses->auth_key.response = kmalloc(temp_len, GFP_KERNEL); + if (!ses->auth_key.response) + return -ENOMEM; + + ses->auth_key.len = temp_len; + + rc = SMBNTencrypt(ses->password, ses->server->cryptkey, + ses->auth_key.response + CIFS_SESS_KEY_SIZE, nls_cp); + if (rc) { + cifs_dbg(FYI, "%s Can't generate NTLM response, error: %d\n", + __func__, rc); + return rc; + } + + rc = E_md4hash(ses->password, temp_key, nls_cp); + if (rc) { + cifs_dbg(FYI, "%s Can't generate NT hash, error: %d\n", + __func__, rc); + return rc; + } + + rc = mdfour(ses->auth_key.response, temp_key, CIFS_SESS_KEY_SIZE); + if (rc) + cifs_dbg(FYI, "%s Can't generate NTLM session key, error: %d\n", + __func__, rc); + + return rc; +} + /* * An NT cancel request header looks just like the original request except: * diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c index 39a938443e3e..0c5617427be9 100644 --- a/fs/cifs/smbencrypt.c +++ b/fs/cifs/smbencrypt.c @@ -18,7 +18,6 @@ #include <linux/string.h> #include <linux/kernel.h> #include <linux/random.h> -#include <crypto/des.h> #include "cifs_fs_sb.h" #include "cifs_unicode.h" #include "cifspdu.h" @@ -38,72 +37,6 @@ #define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8) #define SSVAL(buf,pos,val) SSVALX((buf),(pos),((__u16)(val))) -static void -str_to_key(unsigned char *str, unsigned char *key) -{ - int i; - - key[0] = str[0] >> 1; - key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2); - key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3); - key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4); - key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5); - key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6); - key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7); - key[7] = str[6] & 0x7F; - for (i = 0; i < 8; i++) - key[i] = (key[i] << 1); -} - -static int -smbhash(unsigned char *out, const unsigned char *in, unsigned char *key) -{ - unsigned char key2[8]; - struct des_ctx ctx; - - str_to_key(key, key2); - - if (fips_enabled) { - cifs_dbg(VFS, "FIPS compliance enabled: DES not permitted\n"); - return -ENOENT; - } - - des_expand_key(&ctx, key2, DES_KEY_SIZE); - des_encrypt(&ctx, out, in); - memzero_explicit(&ctx, sizeof(ctx)); - - return 0; -} - -static int -E_P16(unsigned char *p14, unsigned char *p16) -{ - int rc; - unsigned char sp8[8] = - { 0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 }; - - rc = smbhash(p16, sp8, p14); - if (rc) - return rc; - rc = smbhash(p16 + 8, sp8, p14 + 7); - return rc; -} - -static int -E_P24(unsigned char *p21, const unsigned char *c8, unsigned char *p24) -{ - int rc; - - rc = smbhash(p24, c8, p21); - if (rc) - return rc; - rc = smbhash(p24 + 8, c8, p21 + 7); - if (rc) - return rc; - rc = smbhash(p24 + 16, c8, p21 + 14); - return rc; -} - /* produce a md4 message digest from data of length n bytes */ int mdfour(unsigned char *md4_hash, unsigned char *link_str, int link_len) @@ -135,32 +68,6 @@ mdfour(unsigned char *md4_hash, unsigned char *link_str, int link_len) return rc; } -/* - This implements the X/Open SMB password encryption - It takes a password, a 8 byte "crypt key" and puts 24 bytes of - encrypted password into p24 */ -/* Note that password must be uppercased and null terminated */ -int -SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24) -{ - int rc; - unsigned char p14[14], p16[16], p21[21]; - - memset(p14, '\0', 14); - memset(p16, '\0', 16); - memset(p21, '\0', 21); - - memcpy(p14, passwd, 14); - rc = E_P16(p14, p16); - if (rc) - return rc; - - memcpy(p21, p16, 16); - rc = E_P24(p21, c8, p24); - - return rc; -} - /* * Creates the MD4 Hash of the users password in NT UNICODE. */ @@ -187,24 +94,3 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16, return rc; } -/* Does the NT MD4 hash then des encryption. */ -int -SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24, - const struct nls_table *codepage) -{ - int rc; - unsigned char p16[16], p21[21]; - - memset(p16, '\0', 16); - memset(p21, '\0', 21); - - rc = E_md4hash(passwd, p16, codepage); - if (rc) { - cifs_dbg(FYI, "%s Can't generate NT hash, error: %d\n", - __func__, rc); - return rc; - } - memcpy(p21, p16, 16); - rc = E_P24(p21, c8, p24); - return rc; -}
Move all dependencies of DES into smb1ops.c Make SMB1 support depend on CONFIG_LIB_DES Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com> --- fs/cifs/Kconfig | 3 +- fs/cifs/cifsencrypt.c | 39 ------ fs/cifs/cifsproto.h | 9 -- fs/cifs/connect.c | 162 --------------------- fs/cifs/ntlmssp.h | 1 + fs/cifs/sess.c | 5 + fs/cifs/smb1ops.c | 319 ++++++++++++++++++++++++++++++++++++++++++ fs/cifs/smbencrypt.c | 114 --------------- 8 files changed, 326 insertions(+), 326 deletions(-)