Merge tag 'soc-late' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
[cascardo/linux.git] / fs / cifs / cifsencrypt.c
index 6a0d741..652f505 100644 (file)
@@ -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.
  * 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: