diff options
-rw-r--r-- | fs/cifs/Kconfig | 3 | ||||
-rw-r--r-- | fs/cifs/cifsencrypt.c | 113 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 26 | ||||
-rw-r--r-- | fs/cifs/cifspdu.h | 6 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 4 | ||||
-rw-r--r-- | fs/cifs/connect.c | 16 | ||||
-rw-r--r-- | fs/cifs/sess.c | 26 |
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 | ||
544 | int | ||
545 | calc_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 | |||
586 | void | ||
587 | cifs_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 | |||
600 | int | ||
601 | cifs_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 | |||
645 | crypto_allocate_md5_sdesc_fail: | ||
646 | kfree(server->secmech.sdeschmacmd5); | ||
647 | |||
648 | crypto_allocate_hmacmd5_sdesc_fail: | ||
649 | crypto_free_shash(server->secmech.md5); | ||
650 | |||
651 | crypto_allocate_md5_fail: | ||
652 | crypto_free_shash(server->secmech.hmacmd5); | ||
653 | |||
654 | return rc; | ||
655 | } | ||
656 | |||
544 | void CalcNTLMv2_response(const struct cifsSesInfo *ses) | 657 | void 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 */ | ||
109 | struct sdesc { | ||
110 | struct shash_desc shash; | ||
111 | char ctx[]; | ||
112 | }; | ||
113 | |||
114 | /* crypto hashing related structure/fields, not speicific to a sec mech */ | ||
115 | struct 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 */ | ||
123 | struct 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 | |||
105 | struct cifs_cred { | 129 | struct 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 *); | |||
368 | extern int setup_ntlm_response(struct cifsSesInfo *); | 368 | extern int setup_ntlm_response(struct cifsSesInfo *); |
369 | extern void CalcNTLMv2_response(const struct cifsSesInfo *); | 369 | extern void CalcNTLMv2_response(const struct cifsSesInfo *); |
370 | extern int setup_ntlmv2_rsp(struct cifsSesInfo *, const struct nls_table *); | 370 | extern int setup_ntlmv2_rsp(struct cifsSesInfo *, const struct nls_table *); |
371 | extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *); | ||
372 | extern void cifs_crypto_shash_release(struct TCP_Server_Info *); | ||
373 | extern int calc_seckey(struct cifsSesInfo *); | ||
374 | |||
371 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 375 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
372 | extern void calc_lanman_hash(const char *password, const char *cryptkey, | 376 | extern 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 | ||
1704 | out_err2: | ||
1705 | cifs_crypto_shash_release(tcp_ses); | ||
1706 | |||
1697 | out_err: | 1707 | out_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 | ||
550 | setup_ntlmv2_ret: | 562 | setup_ntlmv2_ret: |
551 | *buflen = tmp - pbuffer; | 563 | *buflen = tmp - pbuffer; |