usb: gadget: f_mass_storage: Use "bool" instead of "int" in fsg_module_parameters
[pandora-kernel.git] / fs / cifs / cifsencrypt.c
index 30acd22..12cce59 100644 (file)
  * the sequence number before this function is called. Also, this function
  * should be called with the server->srv_mutex held.
  */
-static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu,
-                               struct TCP_Server_Info *server, char *signature)
-{
-       int rc;
-
-       if (cifs_pdu == NULL || signature == NULL || server == NULL)
-               return -EINVAL;
-
-       if (!server->secmech.sdescmd5) {
-               cERROR(1, "%s: Can't generate signature\n", __func__);
-               return -1;
-       }
-
-       rc = crypto_shash_init(&server->secmech.sdescmd5->shash);
-       if (rc) {
-               cERROR(1, "%s: Could not init md5\n", __func__);
-               return rc;
-       }
-
-       rc = crypto_shash_update(&server->secmech.sdescmd5->shash,
-               server->session_key.response, server->session_key.len);
-       if (rc) {
-               cERROR(1, "%s: Could not update with response\n", __func__);
-               return rc;
-       }
-
-       rc = crypto_shash_update(&server->secmech.sdescmd5->shash,
-               cifs_pdu->Protocol, be32_to_cpu(cifs_pdu->smb_buf_length));
-       if (rc) {
-               cERROR(1, "%s: Could not update with payload\n", __func__);
-               return rc;
-       }
-
-       rc = crypto_shash_final(&server->secmech.sdescmd5->shash, signature);
-       if (rc)
-               cERROR(1, "%s: Could not generate md5 hash\n", __func__);
-
-       return rc;
-}
-
-/* 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)
-{
-       int rc = 0;
-       char smb_signature[20];
-
-       if ((cifs_pdu == NULL) || (server == NULL))
-               return -EINVAL;
-
-       if (!(cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) ||
-           server->tcpStatus == CifsNeedNegotiate)
-               return rc;
-
-       if (!server->session_estab) {
-               strncpy(cifs_pdu->Signature.SecuritySignature, "BSRSPYL", 8);
-               return rc;
-       }
-
-       cifs_pdu->Signature.Sequence.SequenceNumber =
-                       cpu_to_le32(server->sequence_number);
-       cifs_pdu->Signature.Sequence.Reserved = 0;
-
-       *pexpected_response_sequence_number = server->sequence_number++;
-       server->sequence_number++;
-
-       rc = cifs_calculate_signature(cifs_pdu, server, smb_signature);
-       if (rc)
-               memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
-       else
-               memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8);
-
-       return rc;
-}
-
-static int cifs_calc_signature2(const struct kvec *iov, int n_vec,
-                               struct TCP_Server_Info *server, char *signature)
+static int cifs_calc_signature(const struct kvec *iov, int n_vec,
+                       struct TCP_Server_Info *server, char *signature)
 {
        int i;
        int rc;
@@ -179,7 +104,7 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
 {
        int rc = 0;
        char smb_signature[20];
-       struct smb_hdr *cifs_pdu = iov[0].iov_base;
+       struct smb_hdr *cifs_pdu = (struct smb_hdr *)iov[0].iov_base;
 
        if ((cifs_pdu == NULL) || (server == NULL))
                return -EINVAL;
@@ -189,7 +114,7 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
                return rc;
 
        if (!server->session_estab) {
-               strncpy(cifs_pdu->Signature.SecuritySignature, "BSRSPYL", 8);
+               memcpy(cifs_pdu->Signature.SecuritySignature, "BSRSPYL", 8);
                return rc;
        }
 
@@ -200,7 +125,7 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
        *pexpected_response_sequence_number = server->sequence_number++;
        server->sequence_number++;
 
-       rc = cifs_calc_signature2(iov, n_vec, server, smb_signature);
+       rc = cifs_calc_signature(iov, n_vec, server, smb_signature);
        if (rc)
                memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
        else
@@ -209,13 +134,27 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
        return rc;
 }
 
-int cifs_verify_signature(struct smb_hdr *cifs_pdu,
+/* 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)
+{
+       struct kvec iov;
+
+       iov.iov_base = cifs_pdu;
+       iov.iov_len = be32_to_cpu(cifs_pdu->smb_buf_length) + 4;
+
+       return cifs_sign_smb2(&iov, 1, server,
+                             pexpected_response_sequence_number);
+}
+
+int cifs_verify_signature(struct kvec *iov, unsigned int nr_iov,
                          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;
 
        if (cifs_pdu == NULL || server == NULL)
                return -EINVAL;
@@ -247,8 +186,8 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu,
        cifs_pdu->Signature.Sequence.Reserved = 0;
 
        mutex_lock(&server->srv_mutex);
-       rc = cifs_calculate_signature(cifs_pdu, server,
-               what_we_think_sig_should_be);
+       rc = cifs_calc_signature(iov, nr_iov, server,
+                                what_we_think_sig_should_be);
        mutex_unlock(&server->srv_mutex);
 
        if (rc)
@@ -265,7 +204,7 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu,
 }
 
 /* first calculate 24 bytes ntlm response and then 16 byte session key */
-int setup_ntlm_response(struct cifs_ses *ses)
+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;
@@ -282,14 +221,14 @@ int setup_ntlm_response(struct cifs_ses *ses)
        ses->auth_key.len = temp_len;
 
        rc = SMBNTencrypt(ses->password, ses->server->cryptkey,
-                       ses->auth_key.response + CIFS_SESS_KEY_SIZE);
+                       ses->auth_key.response + CIFS_SESS_KEY_SIZE, nls_cp);
        if (rc) {
                cFYI(1, "%s Can't generate NTLM response, error: %d",
                        __func__, rc);
                return rc;
        }
 
-       rc = E_md4hash(ses->password, temp_key);
+       rc = E_md4hash(ses->password, temp_key, nls_cp);
        if (rc) {
                cFYI(1, "%s Can't generate NT hash, error: %d", __func__, rc);
                return rc;
@@ -430,7 +369,7 @@ find_domain_name(struct cifs_ses *ses, const struct nls_table *nls_cp)
                if (blobptr + attrsize > blobend)
                        break;
                if (type == NTLMSSP_AV_NB_DOMAIN_NAME) {
-                       if (!attrsize)
+                       if (!attrsize || attrsize >= CIFS_MAX_DOMAINNAME_LEN)
                                break;
                        if (!ses->domainName) {
                                ses->domainName =
@@ -449,13 +388,55 @@ find_domain_name(struct cifs_ses *ses, const struct nls_table *nls_cp)
        return 0;
 }
 
+/* Server has provided av pairs/target info in the type 2 challenge
+ * packet and we have plucked it and stored within smb session.
+ * We parse that blob here to find the server given timestamp
+ * as part of ntlmv2 authentication (or local current time as
+ * default in case of failure)
+ */
+static __le64
+find_timestamp(struct cifs_ses *ses)
+{
+       unsigned int attrsize;
+       unsigned int type;
+       unsigned int onesize = sizeof(struct ntlmssp2_name);
+       unsigned char *blobptr;
+       unsigned char *blobend;
+       struct ntlmssp2_name *attrptr;
+
+       if (!ses->auth_key.len || !ses->auth_key.response)
+               return 0;
+
+       blobptr = ses->auth_key.response;
+       blobend = blobptr + ses->auth_key.len;
+
+       while (blobptr + onesize < blobend) {
+               attrptr = (struct ntlmssp2_name *) blobptr;
+               type = le16_to_cpu(attrptr->type);
+               if (type == NTLMSSP_AV_EOL)
+                       break;
+               blobptr += 2; /* advance attr type */
+               attrsize = le16_to_cpu(attrptr->length);
+               blobptr += 2; /* advance attr size */
+               if (blobptr + attrsize > blobend)
+                       break;
+               if (type == NTLMSSP_AV_TIMESTAMP) {
+                       if (attrsize == sizeof(u64))
+                               return *((__le64 *)blobptr);
+               }
+               blobptr += attrsize; /* advance attr value */
+       }
+
+       return cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
+}
+
 static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
                            const struct nls_table *nls_cp)
 {
        int rc = 0;
        int len;
        char nt_hash[CIFS_NTHASH_SIZE];
-       wchar_t *user;
+       __le16 *user;
        wchar_t *domain;
        wchar_t *server;
 
@@ -465,7 +446,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
        }
 
        /* calculate md4 hash of password */
-       E_md4hash(ses->password, nt_hash);
+       E_md4hash(ses->password, nt_hash, nls_cp);
 
        rc = crypto_shash_setkey(ses->server->secmech.hmacmd5, nt_hash,
                                CIFS_NTHASH_SIZE);
@@ -480,7 +461,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
                return rc;
        }
 
-       /* convert ses->user_name to unicode and uppercase */
+       /* convert ses->user_name to unicode */
        len = strlen(ses->user_name);
        user = kmalloc(2 + (len * 2), GFP_KERNEL);
        if (user == NULL) {
@@ -488,7 +469,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
                rc = -ENOMEM;
                return rc;
        }
-       len = cifs_strtoUCS((__le16 *)user, ses->user_name, len, nls_cp);
+       len = cifs_strtoUCS(user, ses->user_name, len, nls_cp);
        UniStrupr(user);
 
        rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
@@ -605,6 +586,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
        struct ntlmv2_resp *buf;
        char ntlmv2_hash[16];
        unsigned char *tiblob = NULL; /* target info blob */
+       __le64 rsp_timestamp;
 
        if (ses->server->secType == RawNTLMSSP) {
                if (!ses->domainName) {
@@ -622,13 +604,19 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
                }
        }
 
+       /* Must be within 5 minutes of the server (or in range +/-2h
+        * in case of Mac OS X), so simply carry over server timestamp
+        * (as Windows 7 does)
+        */
+       rsp_timestamp = find_timestamp(ses);
+
        baselen = CIFS_SESS_KEY_SIZE + sizeof(struct ntlmv2_resp);
        tilen = ses->auth_key.len;
        tiblob = ses->auth_key.response;
 
        ses->auth_key.response = kmalloc(baselen + tilen, GFP_KERNEL);
        if (!ses->auth_key.response) {
-               rc = ENOMEM;
+               rc = -ENOMEM;
                ses->auth_key.len = 0;
                cERROR(1, "%s: Can't allocate auth blob", __func__);
                goto setup_ntlmv2_rsp_ret;
@@ -639,7 +627,8 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
                        (ses->auth_key.response + CIFS_SESS_KEY_SIZE);
        buf->blob_signature = cpu_to_le32(0x00000101);
        buf->reserved = 0;
-       buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
+       buf->time = rsp_timestamp;
+
        get_random_bytes(&buf->client_chal, sizeof(buf->client_chal));
        buf->reserved2 = 0;