aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/Kconfig3
-rw-r--r--fs/cifs/cifsencrypt.c113
-rw-r--r--fs/cifs/cifsglob.h26
-rw-r--r--fs/cifs/cifspdu.h6
-rw-r--r--fs/cifs/cifsproto.h4
-rw-r--r--fs/cifs/connect.c16
-rw-r--r--fs/cifs/sess.c26
7 files changed, 184 insertions, 10 deletions
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig
index 917b7d449bb2..0ed213970ced 100644
--- a/fs/cifs/Kconfig
+++ b/fs/cifs/Kconfig
@@ -2,6 +2,9 @@ config CIFS
2 tristate "CIFS support (advanced network filesystem, SMBFS successor)" 2 tristate "CIFS support (advanced network filesystem, SMBFS successor)"
3 depends on INET 3 depends on INET
4 select NLS 4 select NLS
5 select CRYPTO
6 select CRYPTO_MD5
7 select CRYPTO_ARC4
5 help 8 help
6 This is the client VFS module for the Common Internet File System 9 This is the client VFS module for the Common Internet File System
7 (CIFS) protocol which is the successor to the Server Message Block 10 (CIFS) protocol which is the successor to the Server Message Block
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 987b479d55dd..eaa2327ee7af 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -541,6 +541,119 @@ setup_ntlmv2_rsp_ret:
541 return rc; 541 return rc;
542} 542}
543 543
544int
545calc_seckey(struct cifsSesInfo *ses)
546{
547 int rc;
548 struct crypto_blkcipher *tfm_arc4;
549 struct scatterlist sgin, sgout;
550 struct blkcipher_desc desc;
551 unsigned char sec_key[CIFS_SESS_KEY_SIZE]; /* a nonce */
552
553 get_random_bytes(sec_key, CIFS_SESS_KEY_SIZE);
554
555 tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
556 if (!tfm_arc4 || IS_ERR(tfm_arc4)) {
557 cERROR(1, "could not allocate crypto API arc4\n");
558 return PTR_ERR(tfm_arc4);
559 }
560
561 desc.tfm = tfm_arc4;
562
563 crypto_blkcipher_setkey(tfm_arc4, ses->auth_key.response,
564 CIFS_SESS_KEY_SIZE);
565
566 sg_init_one(&sgin, sec_key, CIFS_SESS_KEY_SIZE);
567 sg_init_one(&sgout, ses->ntlmssp.ciphertext, CIFS_CPHTXT_SIZE);
568
569 rc = crypto_blkcipher_encrypt(&desc, &sgout, &sgin, CIFS_CPHTXT_SIZE);
570 if (rc) {
571 cERROR(1, "could not encrypt session key rc: %d\n", rc);
572 crypto_free_blkcipher(tfm_arc4);
573 return rc;
574 }
575
576 /* make secondary_key/nonce as session key */
577 memcpy(ses->auth_key.response, sec_key, CIFS_SESS_KEY_SIZE);
578 /* and make len as that of session key only */
579 ses->auth_key.len = CIFS_SESS_KEY_SIZE;
580
581 crypto_free_blkcipher(tfm_arc4);
582
583 return 0;
584}
585
586void
587cifs_crypto_shash_release(struct TCP_Server_Info *server)
588{
589 if (server->secmech.md5)
590 crypto_free_shash(server->secmech.md5);
591
592 if (server->secmech.hmacmd5)
593 crypto_free_shash(server->secmech.hmacmd5);
594
595 kfree(server->secmech.sdeschmacmd5);
596
597 kfree(server->secmech.sdescmd5);
598}
599
600int
601cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
602{
603 int rc;
604 unsigned int size;
605
606 server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0);
607 if (!server->secmech.hmacmd5 ||
608 IS_ERR(server->secmech.hmacmd5)) {
609 cERROR(1, "could not allocate crypto hmacmd5\n");
610 return PTR_ERR(server->secmech.hmacmd5);
611 }
612
613 server->secmech.md5 = crypto_alloc_shash("md5", 0, 0);
614 if (!server->secmech.md5 || IS_ERR(server->secmech.md5)) {
615 cERROR(1, "could not allocate crypto md5\n");
616 rc = PTR_ERR(server->secmech.md5);
617 goto crypto_allocate_md5_fail;
618 }
619
620 size = sizeof(struct shash_desc) +
621 crypto_shash_descsize(server->secmech.hmacmd5);
622 server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
623 if (!server->secmech.sdeschmacmd5) {
624 cERROR(1, "cifs_crypto_shash_allocate: can't alloc hmacmd5\n");
625 rc = -ENOMEM;
626 goto crypto_allocate_hmacmd5_sdesc_fail;
627 }
628 server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5;
629 server->secmech.sdeschmacmd5->shash.flags = 0x0;
630
631
632 size = sizeof(struct shash_desc) +
633 crypto_shash_descsize(server->secmech.md5);
634 server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL);
635 if (!server->secmech.sdescmd5) {
636 cERROR(1, "cifs_crypto_shash_allocate: can't alloc md5\n");
637 rc = -ENOMEM;
638 goto crypto_allocate_md5_sdesc_fail;
639 }
640 server->secmech.sdescmd5->shash.tfm = server->secmech.md5;
641 server->secmech.sdescmd5->shash.flags = 0x0;
642
643 return 0;
644
645crypto_allocate_md5_sdesc_fail:
646 kfree(server->secmech.sdeschmacmd5);
647
648crypto_allocate_hmacmd5_sdesc_fail:
649 crypto_free_shash(server->secmech.md5);
650
651crypto_allocate_md5_fail:
652 crypto_free_shash(server->secmech.hmacmd5);
653
654 return rc;
655}
656
544void CalcNTLMv2_response(const struct cifsSesInfo *ses) 657void CalcNTLMv2_response(const struct cifsSesInfo *ses)
545{ 658{
546 unsigned int offset = CIFS_SESS_KEY_SIZE + 8; 659 unsigned int offset = CIFS_SESS_KEY_SIZE + 8;
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 66f76b2d270b..7ca5f6d8ed80 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -25,6 +25,9 @@
25#include <linux/workqueue.h> 25#include <linux/workqueue.h>
26#include "cifs_fs_sb.h" 26#include "cifs_fs_sb.h"
27#include "cifsacl.h" 27#include "cifsacl.h"
28#include <crypto/internal/hash.h>
29#include <linux/scatterlist.h>
30
28/* 31/*
29 * The sizes of various internal tables and strings 32 * The sizes of various internal tables and strings
30 */ 33 */
@@ -102,6 +105,27 @@ struct session_key {
102 char *response; 105 char *response;
103}; 106};
104 107
108/* crypto security descriptor definition */
109struct sdesc {
110 struct shash_desc shash;
111 char ctx[];
112};
113
114/* crypto hashing related structure/fields, not speicific to a sec mech */
115struct cifs_secmech {
116 struct crypto_shash *hmacmd5; /* hmac-md5 hash function */
117 struct crypto_shash *md5; /* md5 hash function */
118 struct sdesc *sdeschmacmd5; /* ctxt to generate ntlmv2 hash, CR1 */
119 struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */
120};
121
122/* per smb connection structure/fields */
123struct ntlmssp_auth {
124 __u32 client_flags; /* sent by client in type 1 ntlmsssp exchange */
125 __u32 server_flags; /* sent by server in type 2 ntlmssp exchange */
126 unsigned char ciphertext[CIFS_CPHTXT_SIZE]; /* sent to server */
127};
128
105struct cifs_cred { 129struct cifs_cred {
106 int uid; 130 int uid;
107 int gid; 131 int gid;
@@ -178,6 +202,7 @@ struct TCP_Server_Info {
178 struct session_key session_key; 202 struct session_key session_key;
179 unsigned long lstrp; /* when we got last response from this server */ 203 unsigned long lstrp; /* when we got last response from this server */
180 u16 dialect; /* dialect index that server chose */ 204 u16 dialect; /* dialect index that server chose */
205 struct cifs_secmech secmech; /* crypto sec mech functs, descriptors */
181 /* extended security flavors that server supports */ 206 /* extended security flavors that server supports */
182 bool sec_kerberos; /* supports plain Kerberos */ 207 bool sec_kerberos; /* supports plain Kerberos */
183 bool sec_mskerberos; /* supports legacy MS Kerberos */ 208 bool sec_mskerberos; /* supports legacy MS Kerberos */
@@ -220,6 +245,7 @@ struct cifsSesInfo {
220 char ntlmv2_hash[16]; 245 char ntlmv2_hash[16];
221 unsigned int tilen; /* length of the target info blob */ 246 unsigned int tilen; /* length of the target info blob */
222 unsigned char *tiblob; /* target info blob in challenge response */ 247 unsigned char *tiblob; /* target info blob in challenge response */
248 struct ntlmssp_auth ntlmssp; /* ciphertext, flags */
223 bool need_reconnect:1; /* connection reset, uid now invalid */ 249 bool need_reconnect:1; /* connection reset, uid now invalid */
224}; 250};
225/* no more than one of the following three session flags may be set */ 251/* no more than one of the following three session flags may be set */
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index a152cd6db99b..de36b09763a8 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -140,6 +140,12 @@
140 */ 140 */
141#define CIFS_SESS_KEY_SIZE (16) 141#define CIFS_SESS_KEY_SIZE (16)
142 142
143#define CIFS_CLIENT_CHALLENGE_SIZE (8)
144#define CIFS_SERVER_CHALLENGE_SIZE (8)
145#define CIFS_HMAC_MD5_HASH_SIZE (16)
146#define CIFS_CPHTXT_SIZE (16)
147#define CIFS_NTHASH_SIZE (16)
148
143/* 149/*
144 * Maximum user name length 150 * Maximum user name length
145 */ 151 */
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 8c2d0cf1a62f..1e4728bcf065 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -368,6 +368,10 @@ extern void SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *);
368extern int setup_ntlm_response(struct cifsSesInfo *); 368extern int setup_ntlm_response(struct cifsSesInfo *);
369extern void CalcNTLMv2_response(const struct cifsSesInfo *); 369extern void CalcNTLMv2_response(const struct cifsSesInfo *);
370extern int setup_ntlmv2_rsp(struct cifsSesInfo *, const struct nls_table *); 370extern int setup_ntlmv2_rsp(struct cifsSesInfo *, const struct nls_table *);
371extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *);
372extern void cifs_crypto_shash_release(struct TCP_Server_Info *);
373extern int calc_seckey(struct cifsSesInfo *);
374
371#ifdef CONFIG_CIFS_WEAK_PW_HASH 375#ifdef CONFIG_CIFS_WEAK_PW_HASH
372extern void calc_lanman_hash(const char *password, const char *cryptkey, 376extern void calc_lanman_hash(const char *password, const char *cryptkey,
373 bool encrypt, char *lnm_session_key); 377 bool encrypt, char *lnm_session_key);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index dd9a4ae1d21d..04239a7ff320 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1563,6 +1563,7 @@ cifs_put_tcp_session(struct TCP_Server_Info *server)
1563 server->tcpStatus = CifsExiting; 1563 server->tcpStatus = CifsExiting;
1564 spin_unlock(&GlobalMid_Lock); 1564 spin_unlock(&GlobalMid_Lock);
1565 1565
1566 cifs_crypto_shash_release(server);
1566 cifs_fscache_release_client_cookie(server); 1567 cifs_fscache_release_client_cookie(server);
1567 1568
1568 kfree(server->session_key.response); 1569 kfree(server->session_key.response);
@@ -1621,10 +1622,16 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
1621 goto out_err; 1622 goto out_err;
1622 } 1623 }
1623 1624
1625 rc = cifs_crypto_shash_allocate(tcp_ses);
1626 if (rc) {
1627 cERROR(1, "could not setup hash structures rc %d", rc);
1628 goto out_err;
1629 }
1630
1624 tcp_ses->hostname = extract_hostname(volume_info->UNC); 1631 tcp_ses->hostname = extract_hostname(volume_info->UNC);
1625 if (IS_ERR(tcp_ses->hostname)) { 1632 if (IS_ERR(tcp_ses->hostname)) {
1626 rc = PTR_ERR(tcp_ses->hostname); 1633 rc = PTR_ERR(tcp_ses->hostname);
1627 goto out_err; 1634 goto out_err2;
1628 } 1635 }
1629 1636
1630 tcp_ses->noblocksnd = volume_info->noblocksnd; 1637 tcp_ses->noblocksnd = volume_info->noblocksnd;
@@ -1668,7 +1675,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
1668 } 1675 }
1669 if (rc < 0) { 1676 if (rc < 0) {
1670 cERROR(1, "Error connecting to socket. Aborting operation"); 1677 cERROR(1, "Error connecting to socket. Aborting operation");
1671 goto out_err; 1678 goto out_err2;
1672 } 1679 }
1673 1680
1674 /* 1681 /*
@@ -1682,7 +1689,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
1682 rc = PTR_ERR(tcp_ses->tsk); 1689 rc = PTR_ERR(tcp_ses->tsk);
1683 cERROR(1, "error %d create cifsd thread", rc); 1690 cERROR(1, "error %d create cifsd thread", rc);
1684 module_put(THIS_MODULE); 1691 module_put(THIS_MODULE);
1685 goto out_err; 1692 goto out_err2;
1686 } 1693 }
1687 1694
1688 /* thread spawned, put it on the list */ 1695 /* thread spawned, put it on the list */
@@ -1694,6 +1701,9 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
1694 1701
1695 return tcp_ses; 1702 return tcp_ses;
1696 1703
1704out_err2:
1705 cifs_crypto_shash_release(tcp_ses);
1706
1697out_err: 1707out_err:
1698 if (tcp_ses) { 1708 if (tcp_ses) {
1699 if (!IS_ERR(tcp_ses->hostname)) 1709 if (!IS_ERR(tcp_ses->hostname))
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index b2934683bd08..d998c4f7aae5 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -404,7 +404,7 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
404 /* In particular we can examine sign flags */ 404 /* In particular we can examine sign flags */
405 /* BB spec says that if AvId field of MsvAvTimestamp is populated then 405 /* BB spec says that if AvId field of MsvAvTimestamp is populated then
406 we must set the MIC field of the AUTHENTICATE_MESSAGE */ 406 we must set the MIC field of the AUTHENTICATE_MESSAGE */
407 407 ses->ntlmssp.server_flags = le32_to_cpu(pblob->NegotiateFlags);
408 tioffset = cpu_to_le16(pblob->TargetInfoArray.BufferOffset); 408 tioffset = cpu_to_le16(pblob->TargetInfoArray.BufferOffset);
409 tilen = cpu_to_le16(pblob->TargetInfoArray.Length); 409 tilen = cpu_to_le16(pblob->TargetInfoArray.Length);
410 ses->tilen = tilen; 410 ses->tilen = tilen;
@@ -440,10 +440,12 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
440 NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | 440 NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
441 NTLMSSP_NEGOTIATE_NTLM; 441 NTLMSSP_NEGOTIATE_NTLM;
442 if (ses->server->secMode & 442 if (ses->server->secMode &
443 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) 443 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
444 flags |= NTLMSSP_NEGOTIATE_SIGN; 444 flags |= NTLMSSP_NEGOTIATE_SIGN;
445 if (ses->server->secMode & SECMODE_SIGN_REQUIRED) 445 if (!ses->server->session_estab)
446 flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; 446 flags |= NTLMSSP_NEGOTIATE_KEY_XCH |
447 NTLMSSP_NEGOTIATE_EXTENDED_SEC;
448 }
447 449
448 sec_blob->NegotiateFlags |= cpu_to_le32(flags); 450 sec_blob->NegotiateFlags |= cpu_to_le32(flags);
449 451
@@ -543,9 +545,19 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
543 sec_blob->WorkstationName.MaximumLength = 0; 545 sec_blob->WorkstationName.MaximumLength = 0;
544 tmp += 2; 546 tmp += 2;
545 547
546 sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); 548 if ((ses->ntlmssp.server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) &&
547 sec_blob->SessionKey.Length = 0; 549 !calc_seckey(ses)) {
548 sec_blob->SessionKey.MaximumLength = 0; 550 memcpy(tmp, ses->ntlmssp.ciphertext, CIFS_CPHTXT_SIZE);
551 sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer);
552 sec_blob->SessionKey.Length = cpu_to_le16(CIFS_CPHTXT_SIZE);
553 sec_blob->SessionKey.MaximumLength =
554 cpu_to_le16(CIFS_CPHTXT_SIZE);
555 tmp += CIFS_CPHTXT_SIZE;
556 } else {
557 sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer);
558 sec_blob->SessionKey.Length = 0;
559 sec_blob->SessionKey.MaximumLength = 0;
560 }
549 561
550setup_ntlmv2_ret: 562setup_ntlmv2_ret:
551 *buflen = tmp - pbuffer; 563 *buflen = tmp - pbuffer;