Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 37822188 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6:
  Eliminate sparse warning - bad constant expression
  cifs: check for NULL session password
  missing changes during ntlmv2/ntlmssp auth and sign
  [CIFS] Fix ntlmv2 auth with ntlmssp
  cifs: correction of unicode header files
  cifs: fix NULL pointer dereference in cifs_find_smb_ses
  cifs: consolidate error handling in several functions
  cifs: clean up error handling in cifs_mknod
parents 5a559057 2d20ca83
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -2,6 +2,8 @@ config CIFS
	tristate "CIFS support (advanced network filesystem, SMBFS successor)"
	tristate "CIFS support (advanced network filesystem, SMBFS successor)"
	depends on INET
	depends on INET
	select NLS
	select NLS
	select CRYPTO_MD5
	select CRYPTO_ARC4
	help
	help
	  This is the client VFS module for the Common Internet File System
	  This is the client VFS module for the Common Internet File System
	  (CIFS) protocol which is the successor to the Server Message Block
	  (CIFS) protocol which is the successor to the Server Message Block
+3 −3
Original line number Original line Diff line number Diff line
@@ -597,13 +597,13 @@ decode_negTokenInit(unsigned char *security_blob, int length,
				if (compare_oid(oid, oidlen, MSKRB5_OID,
				if (compare_oid(oid, oidlen, MSKRB5_OID,
						MSKRB5_OID_LEN))
						MSKRB5_OID_LEN))
					server->sec_mskerberos = true;
					server->sec_mskerberos = true;
				else if (compare_oid(oid, oidlen, KRB5U2U_OID,
				if (compare_oid(oid, oidlen, KRB5U2U_OID,
						     KRB5U2U_OID_LEN))
						     KRB5U2U_OID_LEN))
					server->sec_kerberosu2u = true;
					server->sec_kerberosu2u = true;
				else if (compare_oid(oid, oidlen, KRB5_OID,
				if (compare_oid(oid, oidlen, KRB5_OID,
						     KRB5_OID_LEN))
						     KRB5_OID_LEN))
					server->sec_kerberos = true;
					server->sec_kerberos = true;
				else if (compare_oid(oid, oidlen, NTLMSSP_OID,
				if (compare_oid(oid, oidlen, NTLMSSP_OID,
						     NTLMSSP_OID_LEN))
						     NTLMSSP_OID_LEN))
					server->sec_ntlmssp = true;
					server->sec_ntlmssp = true;


+11 −7
Original line number Original line Diff line number Diff line
@@ -30,6 +30,8 @@
 *     This is a compressed table of upper and lower case conversion.
 *     This is a compressed table of upper and lower case conversion.
 *
 *
 */
 */
#ifndef _CIFS_UNICODE_H
#define _CIFS_UNICODE_H


#include <asm/byteorder.h>
#include <asm/byteorder.h>
#include <linux/types.h>
#include <linux/types.h>
@@ -67,8 +69,8 @@ extern const struct UniCaseRange CifsUniUpperRange[];
#endif				/* UNIUPR_NOUPPER */
#endif				/* UNIUPR_NOUPPER */


#ifndef UNIUPR_NOLOWER
#ifndef UNIUPR_NOLOWER
extern signed char UniLowerTable[512];
extern signed char CifsUniLowerTable[512];
extern struct UniCaseRange UniLowerRange[];
extern const struct UniCaseRange CifsUniLowerRange[];
#endif				/* UNIUPR_NOLOWER */
#endif				/* UNIUPR_NOLOWER */


#ifdef __KERNEL__
#ifdef __KERNEL__
@@ -337,15 +339,15 @@ UniStrupr(register wchar_t *upin)
 * UniTolower:  Convert a unicode character to lower case
 * UniTolower:  Convert a unicode character to lower case
 */
 */
static inline wchar_t
static inline wchar_t
UniTolower(wchar_t uc)
UniTolower(register wchar_t uc)
{
{
	register struct UniCaseRange *rp;
	register const struct UniCaseRange *rp;


	if (uc < sizeof(UniLowerTable)) {
	if (uc < sizeof(CifsUniLowerTable)) {
		/* Latin characters */
		/* Latin characters */
		return uc + UniLowerTable[uc];	/* Use base tables */
		return uc + CifsUniLowerTable[uc];	/* Use base tables */
	} else {
	} else {
		rp = UniLowerRange;	/* Use range tables */
		rp = CifsUniLowerRange;	/* Use range tables */
		while (rp->start) {
		while (rp->start) {
			if (uc < rp->start)	/* Before start of range */
			if (uc < rp->start)	/* Before start of range */
				return uc;	/* Uppercase = input */
				return uc;	/* Uppercase = input */
@@ -374,3 +376,5 @@ UniStrlwr(register wchar_t *upin)
}
}


#endif
#endif

#endif /* _CIFS_UNICODE_H */
+8 −8
Original line number Original line Diff line number Diff line
@@ -140,7 +140,7 @@ const struct UniCaseRange CifsUniUpperRange[] = {
/*
/*
 * Latin lower case
 * Latin lower case
 */
 */
static signed char CifsUniLowerTable[512] = {
signed char CifsUniLowerTable[512] = {
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 000-00f */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 000-00f */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 010-01f */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 010-01f */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 020-02f */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 020-02f */
@@ -242,12 +242,12 @@ static signed char UniCaseRangeLff20[27] = {
/*
/*
 * Lower Case Range
 * Lower Case Range
 */
 */
static const struct UniCaseRange CifsUniLowerRange[] = {
const struct UniCaseRange CifsUniLowerRange[] = {
	0x0380, 0x03ab, UniCaseRangeL0380,
	{0x0380, 0x03ab, UniCaseRangeL0380},
	0x0400, 0x042f, UniCaseRangeL0400,
	{0x0400, 0x042f, UniCaseRangeL0400},
	0x0490, 0x04cb, UniCaseRangeL0490,
	{0x0490, 0x04cb, UniCaseRangeL0490},
	0x1e00, 0x1ff7, UniCaseRangeL1e00,
	{0x1e00, 0x1ff7, UniCaseRangeL1e00},
	0xff20, 0xff3a, UniCaseRangeLff20,
	{0xff20, 0xff3a, UniCaseRangeLff20},
	0, 0, 0
	{0}
};
};
#endif
#endif
+349 −126
Original line number Original line Diff line number Diff line
@@ -27,6 +27,7 @@
#include "md5.h"
#include "md5.h"
#include "cifs_unicode.h"
#include "cifs_unicode.h"
#include "cifsproto.h"
#include "cifsproto.h"
#include "ntlmssp.h"
#include <linux/ctype.h>
#include <linux/ctype.h>
#include <linux/random.h>
#include <linux/random.h>


@@ -42,21 +43,43 @@ extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8,
		       unsigned char *p24);
		       unsigned char *p24);


static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu,
static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu,
				    const struct mac_key *key, char *signature)
			struct TCP_Server_Info *server, char *signature)
{
{
	struct	MD5Context context;
	int rc;


	if ((cifs_pdu == NULL) || (signature == NULL) || (key == NULL))
	if (cifs_pdu == NULL || server == NULL || signature == NULL)
		return -EINVAL;
		return -EINVAL;


	cifs_MD5_init(&context);
	if (!server->ntlmssp.sdescmd5) {
	cifs_MD5_update(&context, (char *)&key->data, key->len);
		cERROR(1,
	cifs_MD5_update(&context, cifs_pdu->Protocol, cifs_pdu->smb_buf_length);
			"cifs_calculate_signature: can't generate signature\n");
		return -1;
	}


	cifs_MD5_final(signature, &context);
	rc = crypto_shash_init(&server->ntlmssp.sdescmd5->shash);
	return 0;
	if (rc) {
		cERROR(1, "cifs_calculate_signature: oould not init md5\n");
		return rc;
	}
	}


	if (server->secType == RawNTLMSSP)
		crypto_shash_update(&server->ntlmssp.sdescmd5->shash,
			server->session_key.data.ntlmv2.key,
			CIFS_NTLMV2_SESSKEY_SIZE);
	else
		crypto_shash_update(&server->ntlmssp.sdescmd5->shash,
			(char *)&server->session_key.data,
			server->session_key.len);

	crypto_shash_update(&server->ntlmssp.sdescmd5->shash,
			cifs_pdu->Protocol, cifs_pdu->smb_buf_length);

	rc = crypto_shash_final(&server->ntlmssp.sdescmd5->shash, signature);

	return rc;
}


int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
		  __u32 *pexpected_response_sequence_number)
		  __u32 *pexpected_response_sequence_number)
{
{
@@ -78,8 +101,7 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
	server->sequence_number++;
	server->sequence_number++;
	spin_unlock(&GlobalMid_Lock);
	spin_unlock(&GlobalMid_Lock);


	rc = cifs_calculate_signature(cifs_pdu, &server->mac_signing_key,
	rc = cifs_calculate_signature(cifs_pdu, server, smb_signature);
				      smb_signature);
	if (rc)
	if (rc)
		memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
		memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
	else
	else
@@ -89,21 +111,39 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
}
}


static int cifs_calc_signature2(const struct kvec *iov, int n_vec,
static int cifs_calc_signature2(const struct kvec *iov, int n_vec,
				const struct mac_key *key, char *signature)
			struct TCP_Server_Info *server, char *signature)
{
{
	struct  MD5Context context;
	int i;
	int i;
	int rc;


	if ((iov == NULL) || (signature == NULL) || (key == NULL))
	if (iov == NULL || server == NULL || signature == NULL)
		return -EINVAL;
		return -EINVAL;


	cifs_MD5_init(&context);
	if (!server->ntlmssp.sdescmd5) {
	cifs_MD5_update(&context, (char *)&key->data, key->len);
		cERROR(1, "cifs_calc_signature2: can't generate signature\n");
		return -1;
	}

	rc = crypto_shash_init(&server->ntlmssp.sdescmd5->shash);
	if (rc) {
		cERROR(1, "cifs_calc_signature2: oould not init md5\n");
		return rc;
	}

	if (server->secType == RawNTLMSSP)
		crypto_shash_update(&server->ntlmssp.sdescmd5->shash,
			server->session_key.data.ntlmv2.key,
			CIFS_NTLMV2_SESSKEY_SIZE);
	else
		crypto_shash_update(&server->ntlmssp.sdescmd5->shash,
			(char *)&server->session_key.data,
			server->session_key.len);

	for (i = 0; i < n_vec; i++) {
	for (i = 0; i < n_vec; i++) {
		if (iov[i].iov_len == 0)
		if (iov[i].iov_len == 0)
			continue;
			continue;
		if (iov[i].iov_base == NULL) {
		if (iov[i].iov_base == NULL) {
			cERROR(1, "null iovec entry");
			cERROR(1, "cifs_calc_signature2: null iovec entry");
			return -EIO;
			return -EIO;
		}
		}
		/* The first entry includes a length field (which does not get
		/* The first entry includes a length field (which does not get
@@ -111,18 +151,18 @@ static int cifs_calc_signature2(const struct kvec *iov, int n_vec,
		if (i == 0) {
		if (i == 0) {
			if (iov[0].iov_len <= 8) /* cmd field at offset 9 */
			if (iov[0].iov_len <= 8) /* cmd field at offset 9 */
				break; /* nothing to sign or corrupt header */
				break; /* nothing to sign or corrupt header */
			cifs_MD5_update(&context, iov[0].iov_base+4,
			crypto_shash_update(&server->ntlmssp.sdescmd5->shash,
				  iov[0].iov_len-4);
				iov[i].iov_base + 4, iov[i].iov_len - 4);
		} else
		} else
			cifs_MD5_update(&context, iov[i].iov_base, iov[i].iov_len);
			crypto_shash_update(&server->ntlmssp.sdescmd5->shash,
				iov[i].iov_base, iov[i].iov_len);
	}
	}


	cifs_MD5_final(signature, &context);
	rc = crypto_shash_final(&server->ntlmssp.sdescmd5->shash, signature);


	return 0;
	return rc;
}
}



int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
		   __u32 *pexpected_response_sequence_number)
		   __u32 *pexpected_response_sequence_number)
{
{
@@ -145,8 +185,7 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
	server->sequence_number++;
	server->sequence_number++;
	spin_unlock(&GlobalMid_Lock);
	spin_unlock(&GlobalMid_Lock);


	rc = cifs_calc_signature2(iov, n_vec, &server->mac_signing_key,
	rc = cifs_calc_signature2(iov, n_vec, server, smb_signature);
				      smb_signature);
	if (rc)
	if (rc)
		memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
		memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
	else
	else
@@ -156,14 +195,14 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
}
}


int cifs_verify_signature(struct smb_hdr *cifs_pdu,
int cifs_verify_signature(struct smb_hdr *cifs_pdu,
			  const struct mac_key *mac_key,
			  struct TCP_Server_Info *server,
			  __u32 expected_sequence_number)
			  __u32 expected_sequence_number)
{
{
	unsigned int rc;
	int rc;
	char server_response_sig[8];
	char server_response_sig[8];
	char what_we_think_sig_should_be[20];
	char what_we_think_sig_should_be[20];


	if ((cifs_pdu == NULL) || (mac_key == NULL))
	if (cifs_pdu == NULL || server == NULL)
		return -EINVAL;
		return -EINVAL;


	if (cifs_pdu->Command == SMB_COM_NEGOTIATE)
	if (cifs_pdu->Command == SMB_COM_NEGOTIATE)
@@ -192,7 +231,7 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu,
					cpu_to_le32(expected_sequence_number);
					cpu_to_le32(expected_sequence_number);
	cifs_pdu->Signature.Sequence.Reserved = 0;
	cifs_pdu->Signature.Sequence.Reserved = 0;


	rc = cifs_calculate_signature(cifs_pdu, mac_key,
	rc = cifs_calculate_signature(cifs_pdu, server,
		what_we_think_sig_should_be);
		what_we_think_sig_should_be);


	if (rc)
	if (rc)
@@ -209,7 +248,7 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu,
}
}


/* We fill in key by putting in 40 byte array which was allocated by caller */
/* We fill in key by putting in 40 byte array which was allocated by caller */
int cifs_calculate_mac_key(struct mac_key *key, const char *rn,
int cifs_calculate_session_key(struct session_key *key, const char *rn,
			   const char *password)
			   const char *password)
{
{
	char temp_key[16];
	char temp_key[16];
@@ -223,63 +262,6 @@ int cifs_calculate_mac_key(struct mac_key *key, const char *rn,
	return 0;
	return 0;
}
}


int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *ses,
			       const struct nls_table *nls_info)
{
	char temp_hash[16];
	struct HMACMD5Context ctx;
	char *ucase_buf;
	__le16 *unicode_buf;
	unsigned int i, user_name_len, dom_name_len;

	if (ses == NULL)
		return -EINVAL;

	E_md4hash(ses->password, temp_hash);

	hmac_md5_init_limK_to_64(temp_hash, 16, &ctx);
	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;

	ucase_buf = kmalloc((MAX_USERNAME_SIZE+1), GFP_KERNEL);
	if (ucase_buf == NULL)
		return -ENOMEM;
	unicode_buf = kmalloc((MAX_USERNAME_SIZE+1)*4, GFP_KERNEL);
	if (unicode_buf == NULL) {
		kfree(ucase_buf);
		return -ENOMEM;
	}

	for (i = 0; i < user_name_len; i++)
		ucase_buf[i] = nls_info->charset2upper[(int)ses->userName[i]];
	ucase_buf[i] = 0;
	user_name_len = cifs_strtoUCS(unicode_buf, ucase_buf,
				      MAX_USERNAME_SIZE*2, nls_info);
	unicode_buf[user_name_len] = 0;
	user_name_len++;

	for (i = 0; i < dom_name_len; i++)
		ucase_buf[i] = nls_info->charset2upper[(int)ses->domainName[i]];
	ucase_buf[i] = 0;
	dom_name_len = cifs_strtoUCS(unicode_buf+user_name_len, ucase_buf,
				     MAX_USERNAME_SIZE*2, nls_info);

	unicode_buf[user_name_len + dom_name_len] = 0;
	hmac_md5_update((const unsigned char *) unicode_buf,
		(user_name_len+dom_name_len)*2, &ctx);

	hmac_md5_final(ses->server->ntlmv2_hash, &ctx);
	kfree(ucase_buf);
	kfree(unicode_buf);
	return 0;
}

#ifdef CONFIG_CIFS_WEAK_PW_HASH
#ifdef CONFIG_CIFS_WEAK_PW_HASH
void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt,
void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt,
			char *lnm_session_key)
			char *lnm_session_key)
@@ -324,38 +306,52 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses,
{
{
	int rc = 0;
	int rc = 0;
	int len;
	int len;
	char nt_hash[16];
	char nt_hash[CIFS_NTHASH_SIZE];
	struct HMACMD5Context *pctxt;
	wchar_t *user;
	wchar_t *user;
	wchar_t *domain;
	wchar_t *domain;
	wchar_t *server;


	pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL);
	if (!ses->server->ntlmssp.sdeschmacmd5) {

		cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n");
	if (pctxt == NULL)
		return -1;
		return -ENOMEM;
	}


	/* calculate md4 hash of password */
	/* calculate md4 hash of password */
	E_md4hash(ses->password, nt_hash);
	E_md4hash(ses->password, nt_hash);


	/* convert Domainname to unicode and uppercase */
	crypto_shash_setkey(ses->server->ntlmssp.hmacmd5, nt_hash,
	hmac_md5_init_limK_to_64(nt_hash, 16, pctxt);
				CIFS_NTHASH_SIZE);

	rc = crypto_shash_init(&ses->server->ntlmssp.sdeschmacmd5->shash);
	if (rc) {
		cERROR(1, "calc_ntlmv2_hash: could not init hmacmd5\n");
		return rc;
	}


	/* convert ses->userName to unicode and uppercase */
	/* convert ses->userName to unicode and uppercase */
	len = strlen(ses->userName);
	len = strlen(ses->userName);
	user = kmalloc(2 + (len * 2), GFP_KERNEL);
	user = kmalloc(2 + (len * 2), GFP_KERNEL);
	if (user == NULL)
	if (user == NULL) {
		cERROR(1, "calc_ntlmv2_hash: user mem alloc failure\n");
		rc = -ENOMEM;
		goto calc_exit_2;
		goto calc_exit_2;
	}
	len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp);
	len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp);
	UniStrupr(user);
	UniStrupr(user);
	hmac_md5_update((char *)user, 2*len, pctxt);

	crypto_shash_update(&ses->server->ntlmssp.sdeschmacmd5->shash,
				(char *)user, 2 * len);


	/* convert ses->domainName to unicode and uppercase */
	/* convert ses->domainName to unicode and uppercase */
	if (ses->domainName) {
	if (ses->domainName) {
		len = strlen(ses->domainName);
		len = strlen(ses->domainName);


		domain = kmalloc(2 + (len * 2), GFP_KERNEL);
		domain = kmalloc(2 + (len * 2), GFP_KERNEL);
		if (domain == NULL)
		if (domain == NULL) {
			cERROR(1, "calc_ntlmv2_hash: domain mem alloc failure");
			rc = -ENOMEM;
			goto calc_exit_1;
			goto calc_exit_1;
		}
		len = cifs_strtoUCS((__le16 *)domain, ses->domainName, len,
		len = cifs_strtoUCS((__le16 *)domain, ses->domainName, len,
					nls_cp);
					nls_cp);
		/* the following line was removed since it didn't work well
		/* the following line was removed since it didn't work well
@@ -363,65 +359,292 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses,
		   Maybe converting the domain name earlier makes sense */
		   Maybe converting the domain name earlier makes sense */
		/* UniStrupr(domain); */
		/* UniStrupr(domain); */


		hmac_md5_update((char *)domain, 2*len, pctxt);
		crypto_shash_update(&ses->server->ntlmssp.sdeschmacmd5->shash,
					(char *)domain, 2 * len);


		kfree(domain);
		kfree(domain);
	} else if (ses->serverName) {
		len = strlen(ses->serverName);

		server = kmalloc(2 + (len * 2), GFP_KERNEL);
		if (server == NULL) {
			cERROR(1, "calc_ntlmv2_hash: server mem alloc failure");
			rc = -ENOMEM;
			goto calc_exit_1;
		}
		len = cifs_strtoUCS((__le16 *)server, ses->serverName, len,
					nls_cp);
		/* the following line was removed since it didn't work well
		   with lower cased domain name that passed as an option.
		   Maybe converting the domain name earlier makes sense */
		/* UniStrupr(domain); */

		crypto_shash_update(&ses->server->ntlmssp.sdeschmacmd5->shash,
					(char *)server, 2 * len);

		kfree(server);
	}
	}

	rc = crypto_shash_final(&ses->server->ntlmssp.sdeschmacmd5->shash,
					ses->server->ntlmv2_hash);

calc_exit_1:
calc_exit_1:
	kfree(user);
	kfree(user);
calc_exit_2:
calc_exit_2:
	/* BB FIXME what about bytes 24 through 40 of the signing key?
	/* BB FIXME what about bytes 24 through 40 of the signing key?
	   compare with the NTLM example */
	   compare with the NTLM example */
	hmac_md5_final(ses->server->ntlmv2_hash, pctxt);


	kfree(pctxt);
	return rc;
	return rc;
}
}


void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
static int
		      const struct nls_table *nls_cp)
find_domain_name(struct cifsSesInfo *ses)
{
	int rc = 0;
	unsigned int attrsize;
	unsigned int type;
	unsigned char *blobptr;
	struct ntlmssp2_name *attrptr;

	if (ses->server->tiblob) {
		blobptr = ses->server->tiblob;
		attrptr = (struct ntlmssp2_name *) blobptr;

		while ((type = attrptr->type) != 0) {
			blobptr += 2; /* advance attr type */
			attrsize = attrptr->length;
			blobptr += 2; /* advance attr size */
			if (type == NTLMSSP_AV_NB_DOMAIN_NAME) {
				if (!ses->domainName) {
					ses->domainName =
						kmalloc(attrptr->length + 1,
								GFP_KERNEL);
					if (!ses->domainName)
							return -ENOMEM;
					cifs_from_ucs2(ses->domainName,
						(__le16 *)blobptr,
						attrptr->length,
						attrptr->length,
						load_nls_default(), false);
				}
			}
			blobptr += attrsize; /* advance attr  value */
			attrptr = (struct ntlmssp2_name *) blobptr;
		}
	} else {
		ses->server->tilen = 2 * sizeof(struct ntlmssp2_name);
		ses->server->tiblob = kmalloc(ses->server->tilen, GFP_KERNEL);
		if (!ses->server->tiblob) {
			ses->server->tilen = 0;
			cERROR(1, "Challenge target info allocation failure");
			return -ENOMEM;
		}
		memset(ses->server->tiblob, 0x0, ses->server->tilen);
		attrptr = (struct ntlmssp2_name *) ses->server->tiblob;
		attrptr->type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE);
	}

	return rc;
}

static int
CalcNTLMv2_response(const struct TCP_Server_Info *server,
			 char *v2_session_response)
{
{
	int rc;
	int rc;

	if (!server->ntlmssp.sdeschmacmd5) {
		cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n");
		return -1;
	}

	crypto_shash_setkey(server->ntlmssp.hmacmd5, server->ntlmv2_hash,
		CIFS_HMAC_MD5_HASH_SIZE);

	rc = crypto_shash_init(&server->ntlmssp.sdeschmacmd5->shash);
	if (rc) {
		cERROR(1, "CalcNTLMv2_response: could not init hmacmd5");
		return rc;
	}

	memcpy(v2_session_response + CIFS_SERVER_CHALLENGE_SIZE,
		server->cryptKey, CIFS_SERVER_CHALLENGE_SIZE);
	crypto_shash_update(&server->ntlmssp.sdeschmacmd5->shash,
		v2_session_response + CIFS_SERVER_CHALLENGE_SIZE,
		sizeof(struct ntlmv2_resp) - CIFS_SERVER_CHALLENGE_SIZE);

	if (server->tilen)
		crypto_shash_update(&server->ntlmssp.sdeschmacmd5->shash,
					server->tiblob, server->tilen);

	rc = crypto_shash_final(&server->ntlmssp.sdeschmacmd5->shash,
					v2_session_response);

	return rc;
}

int
setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
		      const struct nls_table *nls_cp)
{
	int rc = 0;
	struct ntlmv2_resp *buf = (struct ntlmv2_resp *)resp_buf;
	struct ntlmv2_resp *buf = (struct ntlmv2_resp *)resp_buf;
	struct HMACMD5Context context;


	buf->blob_signature = cpu_to_le32(0x00000101);
	buf->blob_signature = cpu_to_le32(0x00000101);
	buf->reserved = 0;
	buf->reserved = 0;
	buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
	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->reserved2 = 0;
	buf->names[0].type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE);

	buf->names[0].length = 0;
	if (!ses->domainName) {
	buf->names[1].type = 0;
		rc = find_domain_name(ses);
	buf->names[1].length = 0;
		if (rc) {
			cERROR(1, "could not get domain/server name rc %d", rc);
			return rc;
		}
	}


	/* calculate buf->ntlmv2_hash */
	/* calculate buf->ntlmv2_hash */
	rc = calc_ntlmv2_hash(ses, nls_cp);
	rc = calc_ntlmv2_hash(ses, nls_cp);
	if (rc)
	if (rc) {
		cERROR(1, "could not get v2 hash rc %d", rc);
		return rc;
	}
	rc = CalcNTLMv2_response(ses->server, resp_buf);
	if (rc) {
		cERROR(1, "could not get v2 hash rc %d", rc);
		cERROR(1, "could not get v2 hash rc %d", rc);
	CalcNTLMv2_response(ses, resp_buf);
		return rc;
	}

	if (!ses->server->ntlmssp.sdeschmacmd5) {
		cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n");
		return -1;
	}

	crypto_shash_setkey(ses->server->ntlmssp.hmacmd5,
			ses->server->ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);

	rc = crypto_shash_init(&ses->server->ntlmssp.sdeschmacmd5->shash);
	if (rc) {
		cERROR(1, "setup_ntlmv2_rsp: could not init hmacmd5\n");
		return rc;
	}


	/* now calculate the MAC key for NTLMv2 */
	crypto_shash_update(&ses->server->ntlmssp.sdeschmacmd5->shash,
	hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context);
				resp_buf, CIFS_HMAC_MD5_HASH_SIZE);
	hmac_md5_update(resp_buf, 16, &context);
	hmac_md5_final(ses->server->mac_signing_key.data.ntlmv2.key, &context);


	memcpy(&ses->server->mac_signing_key.data.ntlmv2.resp, resp_buf,
	rc = crypto_shash_final(&ses->server->ntlmssp.sdeschmacmd5->shash,
		ses->server->session_key.data.ntlmv2.key);

	memcpy(&ses->server->session_key.data.ntlmv2.resp, resp_buf,
			sizeof(struct ntlmv2_resp));
			sizeof(struct ntlmv2_resp));
	ses->server->mac_signing_key.len = 16 + sizeof(struct ntlmv2_resp);
	ses->server->session_key.len = 16 + sizeof(struct ntlmv2_resp);

	return rc;
}
}


void CalcNTLMv2_response(const struct cifsSesInfo *ses,
int
			 char *v2_session_response)
calc_seckey(struct TCP_Server_Info *server)
{
	int rc;
	unsigned char sec_key[CIFS_NTLMV2_SESSKEY_SIZE];
	struct crypto_blkcipher *tfm_arc4;
	struct scatterlist sgin, sgout;
	struct blkcipher_desc desc;

	get_random_bytes(sec_key, CIFS_NTLMV2_SESSKEY_SIZE);

	tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)",
						0, CRYPTO_ALG_ASYNC);
	if (!tfm_arc4 || IS_ERR(tfm_arc4)) {
		cERROR(1, "could not allocate " "master crypto API arc4\n");
		return 1;
	}

	desc.tfm = tfm_arc4;

	crypto_blkcipher_setkey(tfm_arc4,
		server->session_key.data.ntlmv2.key, CIFS_CPHTXT_SIZE);
	sg_init_one(&sgin, sec_key, CIFS_CPHTXT_SIZE);
	sg_init_one(&sgout, server->ntlmssp.ciphertext, CIFS_CPHTXT_SIZE);
	rc = crypto_blkcipher_encrypt(&desc, &sgout, &sgin, CIFS_CPHTXT_SIZE);

	if (!rc)
		memcpy(server->session_key.data.ntlmv2.key,
				sec_key, CIFS_NTLMV2_SESSKEY_SIZE);

	crypto_free_blkcipher(tfm_arc4);

	return 0;
}

void
cifs_crypto_shash_release(struct TCP_Server_Info *server)
{
	if (server->ntlmssp.md5)
		crypto_free_shash(server->ntlmssp.md5);

	if (server->ntlmssp.hmacmd5)
		crypto_free_shash(server->ntlmssp.hmacmd5);

	kfree(server->ntlmssp.sdeschmacmd5);

	kfree(server->ntlmssp.sdescmd5);
}

int
cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
{
{
	struct HMACMD5Context context;
	int rc;
	/* rest of v2 struct already generated */
	unsigned int size;
	memcpy(v2_session_response + 8, ses->server->cryptKey, 8);

	hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context);
	server->ntlmssp.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0);
	if (!server->ntlmssp.hmacmd5 ||
			IS_ERR(server->ntlmssp.hmacmd5)) {
		cERROR(1, "could not allocate crypto hmacmd5\n");
		return 1;
	}

	server->ntlmssp.md5 = crypto_alloc_shash("md5", 0, 0);
	if (!server->ntlmssp.md5 || IS_ERR(server->ntlmssp.md5)) {
		cERROR(1, "could not allocate crypto md5\n");
		rc = 1;
		goto cifs_crypto_shash_allocate_ret1;
	}

	size = sizeof(struct shash_desc) +
			crypto_shash_descsize(server->ntlmssp.hmacmd5);
	server->ntlmssp.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
	if (!server->ntlmssp.sdeschmacmd5) {
		cERROR(1, "cifs_crypto_shash_allocate: can't alloc hmacmd5\n");
		rc = -ENOMEM;
		goto cifs_crypto_shash_allocate_ret2;
	}
	server->ntlmssp.sdeschmacmd5->shash.tfm = server->ntlmssp.hmacmd5;
	server->ntlmssp.sdeschmacmd5->shash.flags = 0x0;



	hmac_md5_update(v2_session_response+8,
	size = sizeof(struct shash_desc) +
			sizeof(struct ntlmv2_resp) - 8, &context);
			crypto_shash_descsize(server->ntlmssp.md5);
	server->ntlmssp.sdescmd5 = kmalloc(size, GFP_KERNEL);
	if (!server->ntlmssp.sdescmd5) {
		cERROR(1, "cifs_crypto_shash_allocate: can't alloc md5\n");
		rc = -ENOMEM;
		goto cifs_crypto_shash_allocate_ret3;
	}
	server->ntlmssp.sdescmd5->shash.tfm = server->ntlmssp.md5;
	server->ntlmssp.sdescmd5->shash.flags = 0x0;

	return 0;


	hmac_md5_final(v2_session_response, &context);
cifs_crypto_shash_allocate_ret3:
/*	cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */
	kfree(server->ntlmssp.sdeschmacmd5);

cifs_crypto_shash_allocate_ret2:
	crypto_free_shash(server->ntlmssp.md5);

cifs_crypto_shash_allocate_ret1:
	crypto_free_shash(server->ntlmssp.hmacmd5);

	return rc;
}
}
Loading