diff options
Diffstat (limited to 'fs/cifs/cifsencrypt.c')
| -rw-r--r-- | fs/cifs/cifsencrypt.c | 67 | 
1 files changed, 58 insertions, 9 deletions
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 6a0d741159f..652f5051be0 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -29,6 +29,7 @@  #include "ntlmssp.h"  #include <linux/ctype.h>  #include <linux/random.h> +#include <linux/highmem.h>  /*   * Calculate and return the CIFS signature based on the mac key and SMB PDU. @@ -37,11 +38,13 @@   * the sequence number before this function is called. Also, this function   * should be called with the server->srv_mutex held.   */ -static int cifs_calc_signature(const struct kvec *iov, int n_vec, +static int cifs_calc_signature(struct smb_rqst *rqst,  			struct TCP_Server_Info *server, char *signature)  {  	int i;  	int rc; +	struct kvec *iov = rqst->rq_iov; +	int n_vec = rqst->rq_nvec;  	if (iov == NULL || signature == NULL || server == NULL)  		return -EINVAL; @@ -91,6 +94,16 @@ static int cifs_calc_signature(const struct kvec *iov, int n_vec,  		}  	} +	/* now hash over the rq_pages array */ +	for (i = 0; i < rqst->rq_npages; i++) { +		struct kvec p_iov; + +		cifs_rqst_page_to_kvec(rqst, i, &p_iov); +		crypto_shash_update(&server->secmech.sdescmd5->shash, +					p_iov.iov_base, p_iov.iov_len); +		kunmap(rqst->rq_pages[i]); +	} +  	rc = crypto_shash_final(&server->secmech.sdescmd5->shash, signature);  	if (rc)  		cERROR(1, "%s: Could not generate md5 hash", __func__); @@ -99,12 +112,12 @@ static int cifs_calc_signature(const struct kvec *iov, int n_vec,  }  /* must be called with server->srv_mutex held */ -int cifs_sign_smbv(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, +int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,  		   __u32 *pexpected_response_sequence_number)  {  	int rc = 0;  	char smb_signature[20]; -	struct smb_hdr *cifs_pdu = (struct smb_hdr *)iov[0].iov_base; +	struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;  	if ((cifs_pdu == NULL) || (server == NULL))  		return -EINVAL; @@ -125,7 +138,7 @@ int cifs_sign_smbv(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,  	*pexpected_response_sequence_number = server->sequence_number++;  	server->sequence_number++; -	rc = cifs_calc_signature(iov, n_vec, server, smb_signature); +	rc = cifs_calc_signature(rqst, server, smb_signature);  	if (rc)  		memset(cifs_pdu->Signature.SecuritySignature, 0, 8);  	else @@ -134,6 +147,15 @@ int cifs_sign_smbv(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,  	return rc;  } +int cifs_sign_smbv(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, +		   __u32 *pexpected_response_sequence) +{ +	struct smb_rqst rqst = { .rq_iov = iov, +				 .rq_nvec = n_vec }; + +	return cifs_sign_rqst(&rqst, server, pexpected_response_sequence); +} +  /* must be called with server->srv_mutex held */  int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,  		  __u32 *pexpected_response_sequence_number) @@ -147,14 +169,14 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,  			      pexpected_response_sequence_number);  } -int cifs_verify_signature(struct kvec *iov, unsigned int nr_iov, +int cifs_verify_signature(struct smb_rqst *rqst,  			  struct TCP_Server_Info *server,  			  __u32 expected_sequence_number)  {  	unsigned int rc;  	char server_response_sig[8];  	char what_we_think_sig_should_be[20]; -	struct smb_hdr *cifs_pdu = (struct smb_hdr *)iov[0].iov_base; +	struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;  	if (cifs_pdu == NULL || server == NULL)  		return -EINVAL; @@ -186,8 +208,7 @@ int cifs_verify_signature(struct kvec *iov, unsigned int nr_iov,  	cifs_pdu->Signature.Sequence.Reserved = 0;  	mutex_lock(&server->srv_mutex); -	rc = cifs_calc_signature(iov, nr_iov, server, -				 what_we_think_sig_should_be); +	rc = cifs_calc_signature(rqst, server, what_we_think_sig_should_be);  	mutex_unlock(&server->srv_mutex);  	if (rc) @@ -686,12 +707,17 @@ calc_seckey(struct cifs_ses *ses)  void  cifs_crypto_shash_release(struct TCP_Server_Info *server)  { +	if (server->secmech.hmacsha256) +		crypto_free_shash(server->secmech.hmacsha256); +  	if (server->secmech.md5)  		crypto_free_shash(server->secmech.md5);  	if (server->secmech.hmacmd5)  		crypto_free_shash(server->secmech.hmacmd5); +	kfree(server->secmech.sdeschmacsha256); +  	kfree(server->secmech.sdeschmacmd5);  	kfree(server->secmech.sdescmd5); @@ -716,6 +742,13 @@ cifs_crypto_shash_allocate(struct TCP_Server_Info *server)  		goto crypto_allocate_md5_fail;  	} +	server->secmech.hmacsha256 = crypto_alloc_shash("hmac(sha256)", 0, 0); +	if (IS_ERR(server->secmech.hmacsha256)) { +		cERROR(1, "could not allocate crypto hmacsha256\n"); +		rc = PTR_ERR(server->secmech.hmacsha256); +		goto crypto_allocate_hmacsha256_fail; +	} +  	size = sizeof(struct shash_desc) +  			crypto_shash_descsize(server->secmech.hmacmd5);  	server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL); @@ -727,7 +760,6 @@ cifs_crypto_shash_allocate(struct TCP_Server_Info *server)  	server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5;  	server->secmech.sdeschmacmd5->shash.flags = 0x0; -  	size = sizeof(struct shash_desc) +  			crypto_shash_descsize(server->secmech.md5);  	server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL); @@ -739,12 +771,29 @@ cifs_crypto_shash_allocate(struct TCP_Server_Info *server)  	server->secmech.sdescmd5->shash.tfm = server->secmech.md5;  	server->secmech.sdescmd5->shash.flags = 0x0; +	size = sizeof(struct shash_desc) + +			crypto_shash_descsize(server->secmech.hmacsha256); +	server->secmech.sdeschmacsha256 = kmalloc(size, GFP_KERNEL); +	if (!server->secmech.sdeschmacsha256) { +		cERROR(1, "%s: Can't alloc hmacsha256\n", __func__); +		rc = -ENOMEM; +		goto crypto_allocate_hmacsha256_sdesc_fail; +	} +	server->secmech.sdeschmacsha256->shash.tfm = server->secmech.hmacsha256; +	server->secmech.sdeschmacsha256->shash.flags = 0x0; +  	return 0; +crypto_allocate_hmacsha256_sdesc_fail: +	kfree(server->secmech.sdescmd5); +  crypto_allocate_md5_sdesc_fail:  	kfree(server->secmech.sdeschmacmd5);  crypto_allocate_hmacmd5_sdesc_fail: +	crypto_free_shash(server->secmech.hmacsha256); + +crypto_allocate_hmacsha256_fail:  	crypto_free_shash(server->secmech.md5);  crypto_allocate_md5_fail:  |