Commit 2bfe01ef authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6

Pull CIFS/SMB3 updates from Steve French:
 "Includes support for a critical SMB3 security feature: per-share
  encryption from Pavel, and a cleanup from Jean Delvare.

  Will have another cifs/smb3 merge next week"

* 'for-next' of git://git.samba.org/sfrench/cifs-2.6:
  CIFS: Allow to switch on encryption with seal mount option
  CIFS: Add capability to decrypt big read responses
  CIFS: Decrypt and process small encrypted packets
  CIFS: Add copy into pages callback for a read operation
  CIFS: Add mid handle callback
  CIFS: Add transform header handling callbacks
  CIFS: Encrypt SMB3 requests before sending
  CIFS: Enable encryption during session setup phase
  CIFS: Add capability to transform requests before sending
  CIFS: Separate RFC1001 length processing for SMB2 read
  CIFS: Separate SMB2 sync header processing
  CIFS: Send RFC1001 length in a separate iov
  CIFS: Make send_cancel take rqst as argument
  CIFS: Make SendReceive2() takes resp iov
  CIFS: Separate SMB2 header structure
  CIFS: Fix splice read for non-cached files
  cifs: Add soft dependencies
  cifs: Only select the required crypto modules
  cifs: Simplify SMB2 and SMB311 dependencies
parents cab7076a ae6f8dd4
...@@ -9,8 +9,6 @@ config CIFS ...@@ -9,8 +9,6 @@ config CIFS
select CRYPTO_ARC4 select CRYPTO_ARC4
select CRYPTO_ECB select CRYPTO_ECB
select CRYPTO_DES select CRYPTO_DES
select CRYPTO_SHA256
select CRYPTO_CMAC
help help
This is the client VFS module for the Common Internet File System This is the client VFS module for the Common Internet File System
(CIFS) protocol which is the successor to the Server Message Block (CIFS) protocol which is the successor to the Server Message Block
...@@ -169,11 +167,15 @@ config CIFS_NFSD_EXPORT ...@@ -169,11 +167,15 @@ config CIFS_NFSD_EXPORT
config CIFS_SMB2 config CIFS_SMB2
bool "SMB2 and SMB3 network file system support" bool "SMB2 and SMB3 network file system support"
depends on CIFS && INET depends on CIFS
select NLS
select KEYS select KEYS
select FSCACHE select FSCACHE
select DNS_RESOLVER select DNS_RESOLVER
select CRYPTO_AES
select CRYPTO_SHA256
select CRYPTO_CMAC
select CRYPTO_AEAD2
select CRYPTO_CCM
help help
This enables support for the Server Message Block version 2 This enables support for the Server Message Block version 2
...@@ -194,7 +196,7 @@ config CIFS_SMB2 ...@@ -194,7 +196,7 @@ config CIFS_SMB2
config CIFS_SMB311 config CIFS_SMB311
bool "SMB3.1.1 network file system support (Experimental)" bool "SMB3.1.1 network file system support (Experimental)"
depends on CIFS_SMB2 && INET depends on CIFS_SMB2
help help
This enables experimental support for the newest, SMB3.1.1, dialect. This enables experimental support for the newest, SMB3.1.1, dialect.
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <linux/random.h> #include <linux/random.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#include <crypto/skcipher.h> #include <crypto/skcipher.h>
#include <crypto/aead.h>
static int static int
cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server) cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server)
...@@ -75,24 +76,20 @@ int __cifs_calc_signature(struct smb_rqst *rqst, ...@@ -75,24 +76,20 @@ int __cifs_calc_signature(struct smb_rqst *rqst,
struct kvec *iov = rqst->rq_iov; struct kvec *iov = rqst->rq_iov;
int n_vec = rqst->rq_nvec; int n_vec = rqst->rq_nvec;
for (i = 0; i < n_vec; i++) { if (n_vec < 2 || iov[0].iov_len != 4)
return -EIO;
for (i = 1; i < n_vec; i++) {
if (iov[i].iov_len == 0) if (iov[i].iov_len == 0)
continue; continue;
if (iov[i].iov_base == NULL) { if (iov[i].iov_base == NULL) {
cifs_dbg(VFS, "null iovec entry\n"); cifs_dbg(VFS, "null iovec entry\n");
return -EIO; return -EIO;
} }
/* The first entry includes a length field (which does not get if (i == 1 && iov[1].iov_len <= 4)
signed that occupies the first 4 bytes before the header */ break; /* nothing to sign or corrupt header */
if (i == 0) { rc = crypto_shash_update(shash,
if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ iov[i].iov_base, iov[i].iov_len);
break; /* nothing to sign or corrupt header */
rc = crypto_shash_update(shash,
iov[i].iov_base + 4, iov[i].iov_len - 4);
} else {
rc = crypto_shash_update(shash,
iov[i].iov_base, iov[i].iov_len);
}
if (rc) { if (rc) {
cifs_dbg(VFS, "%s: Could not update with payload\n", cifs_dbg(VFS, "%s: Could not update with payload\n",
__func__); __func__);
...@@ -168,6 +165,10 @@ int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server, ...@@ -168,6 +165,10 @@ int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
char smb_signature[20]; char smb_signature[20];
struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base; struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
if (rqst->rq_iov[0].iov_len != 4 ||
rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
return -EIO;
if ((cifs_pdu == NULL) || (server == NULL)) if ((cifs_pdu == NULL) || (server == NULL))
return -EINVAL; return -EINVAL;
...@@ -209,12 +210,14 @@ int cifs_sign_smbv(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, ...@@ -209,12 +210,14 @@ int cifs_sign_smbv(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
__u32 *pexpected_response_sequence_number) __u32 *pexpected_response_sequence_number)
{ {
struct kvec iov; struct kvec iov[2];
iov.iov_base = cifs_pdu; iov[0].iov_base = cifs_pdu;
iov.iov_len = be32_to_cpu(cifs_pdu->smb_buf_length) + 4; iov[0].iov_len = 4;
iov[1].iov_base = (char *)cifs_pdu + 4;
iov[1].iov_len = be32_to_cpu(cifs_pdu->smb_buf_length);
return cifs_sign_smbv(&iov, 1, server, return cifs_sign_smbv(iov, 2, server,
pexpected_response_sequence_number); pexpected_response_sequence_number);
} }
...@@ -227,6 +230,10 @@ int cifs_verify_signature(struct smb_rqst *rqst, ...@@ -227,6 +230,10 @@ int cifs_verify_signature(struct smb_rqst *rqst,
char what_we_think_sig_should_be[20]; char what_we_think_sig_should_be[20];
struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base; struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
if (rqst->rq_iov[0].iov_len != 4 ||
rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
return -EIO;
if (cifs_pdu == NULL || server == NULL) if (cifs_pdu == NULL || server == NULL)
return -EINVAL; return -EINVAL;
...@@ -868,7 +875,7 @@ calc_seckey(struct cifs_ses *ses) ...@@ -868,7 +875,7 @@ calc_seckey(struct cifs_ses *ses)
} }
void void
cifs_crypto_shash_release(struct TCP_Server_Info *server) cifs_crypto_secmech_release(struct TCP_Server_Info *server)
{ {
if (server->secmech.cmacaes) { if (server->secmech.cmacaes) {
crypto_free_shash(server->secmech.cmacaes); crypto_free_shash(server->secmech.cmacaes);
...@@ -890,6 +897,16 @@ cifs_crypto_shash_release(struct TCP_Server_Info *server) ...@@ -890,6 +897,16 @@ cifs_crypto_shash_release(struct TCP_Server_Info *server)
server->secmech.hmacmd5 = NULL; server->secmech.hmacmd5 = NULL;
} }
if (server->secmech.ccmaesencrypt) {
crypto_free_aead(server->secmech.ccmaesencrypt);
server->secmech.ccmaesencrypt = NULL;
}
if (server->secmech.ccmaesdecrypt) {
crypto_free_aead(server->secmech.ccmaesdecrypt);
server->secmech.ccmaesdecrypt = NULL;
}
kfree(server->secmech.sdesccmacaes); kfree(server->secmech.sdesccmacaes);
server->secmech.sdesccmacaes = NULL; server->secmech.sdesccmacaes = NULL;
kfree(server->secmech.sdeschmacsha256); kfree(server->secmech.sdeschmacsha256);
......
...@@ -1365,5 +1365,19 @@ MODULE_DESCRIPTION ...@@ -1365,5 +1365,19 @@ MODULE_DESCRIPTION
("VFS to access servers complying with the SNIA CIFS Specification " ("VFS to access servers complying with the SNIA CIFS Specification "
"e.g. Samba and Windows"); "e.g. Samba and Windows");
MODULE_VERSION(CIFS_VERSION); MODULE_VERSION(CIFS_VERSION);
MODULE_SOFTDEP("pre: arc4");
MODULE_SOFTDEP("pre: des");
MODULE_SOFTDEP("pre: ecb");
MODULE_SOFTDEP("pre: hmac");
MODULE_SOFTDEP("pre: md4");
MODULE_SOFTDEP("pre: md5");
MODULE_SOFTDEP("pre: nls");
#ifdef CONFIG_CIFS_SMB2
MODULE_SOFTDEP("pre: aes");
MODULE_SOFTDEP("pre: cmac");
MODULE_SOFTDEP("pre: sha256");
MODULE_SOFTDEP("pre: aead2");
MODULE_SOFTDEP("pre: ccm");
#endif /* CONFIG_CIFS_SMB2 */
module_init(init_cifs) module_init(init_cifs)
module_exit(exit_cifs) module_exit(exit_cifs)
...@@ -136,6 +136,8 @@ struct cifs_secmech { ...@@ -136,6 +136,8 @@ struct cifs_secmech {
struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */ struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */
struct sdesc *sdeschmacsha256; /* ctxt to generate smb2 signature */ struct sdesc *sdeschmacsha256; /* ctxt to generate smb2 signature */
struct sdesc *sdesccmacaes; /* ctxt to generate smb3 signature */ struct sdesc *sdesccmacaes; /* ctxt to generate smb3 signature */
struct crypto_aead *ccmaesencrypt; /* smb3 encryption aead */
struct crypto_aead *ccmaesdecrypt; /* smb3 decryption aead */
}; };
/* per smb session structure/fields */ /* per smb session structure/fields */
...@@ -208,7 +210,7 @@ struct cifsInodeInfo; ...@@ -208,7 +210,7 @@ struct cifsInodeInfo;
struct cifs_open_parms; struct cifs_open_parms;
struct smb_version_operations { struct smb_version_operations {
int (*send_cancel)(struct TCP_Server_Info *, void *, int (*send_cancel)(struct TCP_Server_Info *, struct smb_rqst *,
struct mid_q_entry *); struct mid_q_entry *);
bool (*compare_fids)(struct cifsFileInfo *, struct cifsFileInfo *); bool (*compare_fids)(struct cifsFileInfo *, struct cifsFileInfo *);
/* setup request: allocate mid, sign message */ /* setup request: allocate mid, sign message */
...@@ -433,6 +435,14 @@ struct smb_version_operations { ...@@ -433,6 +435,14 @@ struct smb_version_operations {
bool (*dir_needs_close)(struct cifsFileInfo *); bool (*dir_needs_close)(struct cifsFileInfo *);
long (*fallocate)(struct file *, struct cifs_tcon *, int, loff_t, long (*fallocate)(struct file *, struct cifs_tcon *, int, loff_t,
loff_t); loff_t);
/* init transform request - used for encryption for now */
int (*init_transform_rq)(struct TCP_Server_Info *, struct smb_rqst *,
struct smb_rqst *);
/* free transform request */
void (*free_transform_rq)(struct smb_rqst *);
int (*is_transform_hdr)(void *buf);
int (*receive_transform)(struct TCP_Server_Info *,
struct mid_q_entry **);
}; };
struct smb_version_values { struct smb_version_values {
...@@ -1119,7 +1129,10 @@ struct cifs_readdata { ...@@ -1119,7 +1129,10 @@ struct cifs_readdata {
int (*read_into_pages)(struct TCP_Server_Info *server, int (*read_into_pages)(struct TCP_Server_Info *server,
struct cifs_readdata *rdata, struct cifs_readdata *rdata,
unsigned int len); unsigned int len);
struct kvec iov; int (*copy_into_pages)(struct TCP_Server_Info *server,
struct cifs_readdata *rdata,
struct iov_iter *iter);
struct kvec iov[2];
unsigned int pagesz; unsigned int pagesz;
unsigned int tailsz; unsigned int tailsz;
unsigned int credits; unsigned int credits;
...@@ -1302,6 +1315,13 @@ typedef int (mid_receive_t)(struct TCP_Server_Info *server, ...@@ -1302,6 +1315,13 @@ typedef int (mid_receive_t)(struct TCP_Server_Info *server,
*/ */
typedef void (mid_callback_t)(struct mid_q_entry *mid); typedef void (mid_callback_t)(struct mid_q_entry *mid);
/*
* This is the protopyte for mid handle function. This is called once the mid
* has been recognized after decryption of the message.
*/
typedef int (mid_handle_t)(struct TCP_Server_Info *server,
struct mid_q_entry *mid);
/* one of these for every pending CIFS request to the server */ /* one of these for every pending CIFS request to the server */
struct mid_q_entry { struct mid_q_entry {
struct list_head qhead; /* mids waiting on reply from this server */ struct list_head qhead; /* mids waiting on reply from this server */
...@@ -1316,6 +1336,7 @@ struct mid_q_entry { ...@@ -1316,6 +1336,7 @@ struct mid_q_entry {
#endif #endif
mid_receive_t *receive; /* call receive callback */ mid_receive_t *receive; /* call receive callback */
mid_callback_t *callback; /* call completion callback */ mid_callback_t *callback; /* call completion callback */
mid_handle_t *handle; /* call handle mid callback */
void *callback_data; /* general purpose pointer for callback */ void *callback_data; /* general purpose pointer for callback */
void *resp_buf; /* pointer to received SMB header */ void *resp_buf; /* pointer to received SMB header */
int mid_state; /* wish this were enum but can not pass to wait_event */ int mid_state; /* wish this were enum but can not pass to wait_event */
...@@ -1323,6 +1344,7 @@ struct mid_q_entry { ...@@ -1323,6 +1344,7 @@ struct mid_q_entry {
bool large_buf:1; /* if valid response, is pointer to large buf */ bool large_buf:1; /* if valid response, is pointer to large buf */
bool multiRsp:1; /* multiple trans2 responses for one request */ bool multiRsp:1; /* multiple trans2 responses for one request */
bool multiEnd:1; /* both received */ bool multiEnd:1; /* both received */
bool decrypted:1; /* decrypted entry */
}; };
/* Make code in transport.c a little cleaner by moving /* Make code in transport.c a little cleaner by moving
...@@ -1475,7 +1497,9 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param, ...@@ -1475,7 +1497,9 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param,
#define CIFS_OBREAK_OP 0x0100 /* oplock break request */ #define CIFS_OBREAK_OP 0x0100 /* oplock break request */
#define CIFS_NEG_OP 0x0200 /* negotiate request */ #define CIFS_NEG_OP 0x0200 /* negotiate request */
#define CIFS_OP_MASK 0x0380 /* mask request type */ #define CIFS_OP_MASK 0x0380 /* mask request type */
#define CIFS_HAS_CREDITS 0x0400 /* already has credits */ #define CIFS_HAS_CREDITS 0x0400 /* already has credits */
#define CIFS_TRANSFORM_REQ 0x0800 /* transform request before sending */
/* Security Flags: indicate type of session setup needed */ /* Security Flags: indicate type of session setup needed */
#define CIFSSEC_MAY_SIGN 0x00001 #define CIFSSEC_MAY_SIGN 0x00001
......
...@@ -75,10 +75,16 @@ extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer, ...@@ -75,10 +75,16 @@ extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer,
extern void DeleteMidQEntry(struct mid_q_entry *midEntry); extern void DeleteMidQEntry(struct mid_q_entry *midEntry);
extern void cifs_delete_mid(struct mid_q_entry *mid); extern void cifs_delete_mid(struct mid_q_entry *mid);
extern void cifs_wake_up_task(struct mid_q_entry *mid); extern void cifs_wake_up_task(struct mid_q_entry *mid);
extern int cifs_handle_standard(struct TCP_Server_Info *server,
struct mid_q_entry *mid);
extern int cifs_discard_remaining_data(struct TCP_Server_Info *server);
extern int cifs_call_async(struct TCP_Server_Info *server, extern int cifs_call_async(struct TCP_Server_Info *server,
struct smb_rqst *rqst, struct smb_rqst *rqst,
mid_receive_t *receive, mid_callback_t *callback, mid_receive_t *receive, mid_callback_t *callback,
void *cbdata, const int flags); mid_handle_t *handle, void *cbdata, const int flags);
extern int cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
struct smb_rqst *rqst, int *resp_buf_type,
const int flags, struct kvec *resp_iov);
extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *, extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *,
struct smb_hdr * /* input */ , struct smb_hdr * /* input */ ,
struct smb_hdr * /* out */ , struct smb_hdr * /* out */ ,
...@@ -96,7 +102,8 @@ extern int cifs_wait_mtu_credits(struct TCP_Server_Info *server, ...@@ -96,7 +102,8 @@ extern int cifs_wait_mtu_credits(struct TCP_Server_Info *server,
unsigned int *credits); unsigned int *credits);
extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *, extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *,
struct kvec *, int /* nvec to send */, struct kvec *, int /* nvec to send */,
int * /* type of buf returned */ , const int flags); int * /* type of buf returned */, const int flags,
struct kvec * /* resp vec */);
extern int SendReceiveBlockingLock(const unsigned int xid, extern int SendReceiveBlockingLock(const unsigned int xid,
struct cifs_tcon *ptcon, struct cifs_tcon *ptcon,
struct smb_hdr *in_buf , struct smb_hdr *in_buf ,
...@@ -441,7 +448,7 @@ extern int SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *, ...@@ -441,7 +448,7 @@ extern int SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *,
const struct nls_table *); const struct nls_table *);
extern int setup_ntlm_response(struct cifs_ses *, const struct nls_table *); extern int setup_ntlm_response(struct cifs_ses *, const struct nls_table *);
extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *); extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *);
extern void cifs_crypto_shash_release(struct TCP_Server_Info *); extern void cifs_crypto_secmech_release(struct TCP_Server_Info *server);
extern int calc_seckey(struct cifs_ses *); extern int calc_seckey(struct cifs_ses *);
extern int generate_smb30signingkey(struct cifs_ses *); extern int generate_smb30signingkey(struct cifs_ses *);
extern int generate_smb311signingkey(struct cifs_ses *); extern int generate_smb311signingkey(struct cifs_ses *);
......
This diff is collapsed.
...@@ -787,6 +787,15 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid) ...@@ -787,6 +787,15 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
dump_smb(buf, server->total_read); dump_smb(buf, server->total_read);
return cifs_handle_standard(server, mid);
}
int
cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
{
char *buf = server->large_buf ? server->bigbuf : server->smallbuf;
int length;
/* /*
* We know that we received enough to get to the MID as we * We know that we received enough to get to the MID as we
* checked the pdu_length earlier. Now check to see * checked the pdu_length earlier. Now check to see
...@@ -872,12 +881,19 @@ cifs_demultiplex_thread(void *p) ...@@ -872,12 +881,19 @@ cifs_demultiplex_thread(void *p)
continue; continue;
server->total_read += length; server->total_read += length;
mid_entry = server->ops->find_mid(server, buf); if (server->ops->is_transform_hdr &&
server->ops->receive_transform &&
server->ops->is_transform_hdr(buf)) {
length = server->ops->receive_transform(server,
&mid_entry);
} else {
mid_entry = server->ops->find_mid(server, buf);
if (!mid_entry || !mid_entry->receive) if (!mid_entry || !mid_entry->receive)
length = standard_receive3(server, mid_entry); length = standard_receive3(server, mid_entry);
else else
length = mid_entry->receive(server, mid_entry); length = mid_entry->receive(server, mid_entry);
}
if (length < 0) if (length < 0)
continue; continue;
...@@ -2154,7 +2170,7 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect) ...@@ -2154,7 +2170,7 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
server->tcpStatus = CifsExiting; server->tcpStatus = CifsExiting;
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
cifs_crypto_shash_release(server); cifs_crypto_secmech_release(server);
cifs_fscache_release_client_cookie(server); cifs_fscache_release_client_cookie(server);
kfree(server->session_key.response); kfree(server->session_key.response);
...@@ -2273,7 +2289,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) ...@@ -2273,7 +2289,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
return tcp_ses; return tcp_ses;
out_err_crypto_release: out_err_crypto_release:
cifs_crypto_shash_release(tcp_ses); cifs_crypto_secmech_release(tcp_ses);
put_net(cifs_net_ns(tcp_ses)); put_net(cifs_net_ns(tcp_ses));
...@@ -2614,12 +2630,18 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) ...@@ -2614,12 +2630,18 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
return ERR_PTR(rc); return ERR_PTR(rc);
} }
static int match_tcon(struct cifs_tcon *tcon, const char *unc) static int match_tcon(struct cifs_tcon *tcon, struct smb_vol *volume_info)
{ {
if (tcon->tidStatus == CifsExiting) if (tcon->tidStatus == CifsExiting)
return 0; return 0;
if (strncmp(tcon->treeName, unc, MAX_TREE_SIZE)) if (strncmp(tcon->treeName, volume_info->UNC, MAX_TREE_SIZE))
return 0; return 0;
if (tcon->seal != volume_info->seal)
return 0;
#ifdef CONFIG_CIFS_SMB2
if (tcon->snapshot_time != volume_info->snapshot_time)
return 0;
#endif /* CONFIG_CIFS_SMB2 */
return 1; return 1;
} }
...@@ -2632,14 +2654,8 @@ cifs_find_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) ...@@ -2632,14 +2654,8 @@ cifs_find_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
spin_lock(&cifs_tcp_ses_lock); spin_lock(&cifs_tcp_ses_lock);
list_for_each(tmp, &ses->tcon_list) { list_for_each(tmp, &ses->tcon_list) {
tcon = list_entry(tmp, struct cifs_tcon, tcon_list); tcon = list_entry(tmp, struct cifs_tcon, tcon_list);
if (!match_tcon(tcon, volume_info->UNC)) if (!match_tcon(tcon, volume_info))
continue;
#ifdef CONFIG_CIFS_SMB2
if (tcon->snapshot_time != volume_info->snapshot_time)
continue; continue;
#endif /* CONFIG_CIFS_SMB2 */
++tcon->tc_count; ++tcon->tc_count;
spin_unlock(&cifs_tcp_ses_lock); spin_unlock(&cifs_tcp_ses_lock);
return tcon; return tcon;
...@@ -2685,8 +2701,6 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) ...@@ -2685,8 +2701,6 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
cifs_dbg(FYI, "Found match on UNC path\n"); cifs_dbg(FYI, "Found match on UNC path\n");
/* existing tcon already has a reference */ /* existing tcon already has a reference */
cifs_put_smb_ses(ses); cifs_put_smb_ses(ses);
if (tcon->seal != volume_info->seal)
cifs_dbg(VFS, "transport encryption setting conflicts with existing tid\n");
return tcon; return tcon;
} }
...@@ -2742,7 +2756,6 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) ...@@ -2742,7 +2756,6 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
tcon->Flags &= ~SMB_SHARE_IS_IN_DFS; tcon->Flags &= ~SMB_SHARE_IS_IN_DFS;
cifs_dbg(FYI, "DFS disabled (%d)\n", tcon->Flags); cifs_dbg(FYI, "DFS disabled (%d)\n", tcon->Flags);
} }
tcon->seal = volume_info->seal;
tcon->use_persistent = false; tcon->use_persistent = false;
/* check if SMB2 or later, CIFS does not support persistent handles */ /* check if SMB2 or later, CIFS does not support persistent handles */
if (volume_info->persistent) { if (volume_info->persistent) {
...@@ -2779,6 +2792,24 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) ...@@ -2779,6 +2792,24 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
tcon->use_resilient = true; tcon->use_resilient = true;
} }
if (volume_info->seal) {
if (ses->server->vals->protocol_id == 0) {
cifs_dbg(VFS,
"SMB3 or later required for encryption\n");
rc = -EOPNOTSUPP;
goto out_fail;
#ifdef CONFIG_CIFS_SMB2
} else if (tcon->ses->server->capabilities &
SMB2_GLOBAL_CAP_ENCRYPTION)
tcon->seal = true;
else {
cifs_dbg(VFS, "Encryption is not supported on share\n");
rc = -EOPNOTSUPP;
goto out_fail;
#endif /* CONFIG_CIFS_SMB2 */
}
}
/* /*
* We can have only one retry value for a connection to a share so for * We can have only one retry value for a connection to a share so for
* resources mounted more than once to the same server share the last * resources mounted more than once to the same server share the last
...@@ -2910,7 +2941,7 @@ cifs_match_super(struct super_block *sb, void *data) ...@@ -2910,7 +2941,7 @@ cifs_match_super(struct super_block *sb, void *data)
if (!match_server(tcp_srv, volume_info) || if (!match_server(tcp_srv, volume_info) ||
!match_session(ses, volume_info) || !match_session(ses, volume_info) ||
!match_tcon(tcon, volume_info->UNC) || !match_tcon(tcon, volume_info) ||
!match_prepath(sb, mnt_data)) { !match_prepath(sb, mnt_data)) {
rc = 0; rc = 0;
goto out; goto out;
......
...@@ -2884,7 +2884,15 @@ cifs_readdata_to_iov(struct cifs_readdata *rdata, struct iov_iter *iter) ...@@ -2884,7 +2884,15 @@ cifs_readdata_to_iov(struct cifs_readdata *rdata, struct iov_iter *iter)
for (i = 0; i < rdata->nr_pages; i++) { for (i = 0; i < rdata->nr_pages; i++) {
struct page *page = rdata->pages[i]; struct page *page = rdata->pages[i];
size_t copy = min_t(size_t, remaining, PAGE_SIZE); size_t copy = min_t(size_t, remaining, PAGE_SIZE);
size_t written = copy_page_to_iter(page, 0, copy, iter); size_t written;
if (unlikely(iter->type & ITER_PIPE)) {
void *addr = kmap_atomic(page);
written = copy_to_iter(addr, copy, iter);
kunmap_atomic(addr);
} else
written = copy_page_to_iter(page, 0, copy, iter);
remaining -= written; remaining -= written;
if (written < copy && iov_iter_count(iter) > 0) if (written < copy && iov_iter_count(iter) > 0)
break; break;
...@@ -2903,8 +2911,9 @@ cifs_uncached_readv_complete(struct work_struct *work) ...@@ -2903,8 +2911,9 @@ cifs_uncached_readv_complete(struct work_struct *work)
} }
static int static int
cifs_uncached_read_into_pages(struct TCP_Server_Info *server, uncached_fill_pages(struct TCP_Server_Info *server,
struct cifs_readdata *rdata, unsigned int len) struct cifs_readdata *rdata, struct iov_iter *iter,
unsigned int len)
{ {
int result = 0; int result = 0;
unsigned int i; unsigned int i;
...@@ -2933,7 +2942,10 @@ cifs_uncached_read_into_pages(struct TCP_Server_Info *server, ...@@ -2933,7 +2942,10 @@ cifs_uncached_read_into_pages(struct TCP_Server_Info *server,
rdata->tailsz = len; rdata->tailsz = len;
len = 0; len = 0;
} }
result = cifs_read_page_from_socket(server, page, n); if (iter)
result = copy_page_from_iter(page, 0, n, iter);
else
result = cifs_read_page_from_socket(server, page, n);
if (result < 0) if (result < 0)
break; break;
...@@ -2944,6 +2956,21 @@ cifs_uncached_read_into_pages(struct TCP_Server_Info *server, ...@@ -2944,6 +2956,21 @@ cifs_uncached_read_into_pages(struct TCP_Server_Info *server,
rdata->got_bytes : result; rdata->got_bytes : result;
} }
static int
cifs_uncached_read_into_pages(struct TCP_Server_Info *server,
struct cifs_readdata *rdata, unsigned int len)
{
return uncached_fill_pages(server, rdata, NULL, len);
}
static int
cifs_uncached_copy_into_pages(struct TCP_Server_Info *server,
struct cifs_readdata *rdata,
struct iov_iter *iter)
{
return uncached_fill_pages(server, rdata, iter, iter->count);
}
static int static int
cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file, cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file,
struct cifs_sb_info *cifs_sb, struct list_head *rdata_list) struct cifs_sb_info *cifs_sb, struct list_head *rdata_list)
...@@ -2991,6 +3018,7 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file, ...@@ -2991,6 +3018,7 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file,
rdata->pid = pid; rdata->pid = pid;
rdata->pagesz = PAGE_SIZE; rdata->pagesz = PAGE_SIZE;
rdata->read_into_pages = cifs_uncached_read_into_pages; rdata->read_into_pages = cifs_uncached_read_into_pages;
rdata->copy_into_pages = cifs_uncached_copy_into_pages;
rdata->credits = credits; rdata->credits = credits;
if (!rdata->cfile->invalidHandle || if (!rdata->cfile->invalidHandle ||
...@@ -3341,8 +3369,9 @@ cifs_readv_complete(struct work_struct *work) ...@@ -3341,8 +3369,9 @@ cifs_readv_complete(struct work_struct *work)
} }
static int static int
cifs_readpages_read_into_pages(struct TCP_Server_Info *server, readpages_fill_pages(struct TCP_Server_Info *server,
struct cifs_readdata *rdata, unsigned int len) struct cifs_readdata *rdata, struct iov_iter *iter,
unsigned int len)
{ {
int result = 0; int result = 0;
unsigned int i; unsigned int i;
...@@ -3396,7 +3425,10 @@ cifs_readpages_read_into_pages(struct TCP_Server_Info *server, ...@@ -3396,7 +3425,10 @@ cifs_readpages_read_into_pages(struct TCP_Server_Info *server,
continue; continue;
} }
result = cifs_read_page_from_socket(server, page, n); if (iter)
result = copy_page_from_iter(page, 0, n, iter);
else
result = cifs_read_page_from_socket(server, page, n);
if (result < 0) if (result < 0)
break; break;
...@@ -3407,6 +3439,21 @@ cifs_readpages_read_into_pages(struct TCP_Server_Info *server, ...@@ -3407,6 +3439,21 @@ cifs_readpages_read_into_pages(struct TCP_Server_Info *server,
rdata->got_bytes : result; rdata->got_bytes : result;
} }
static int
cifs_readpages_read_into_pages(struct TCP_Server_Info *server,
struct cifs_readdata *rdata, unsigned int len)
{
return readpages_fill_pages(server, rdata, NULL, len);
}
static int
cifs_readpages_copy_into_pages(struct TCP_Server_Info *server,
struct cifs_readdata *rdata,
struct iov_iter *iter)
{
return readpages_fill_pages(server, rdata, iter, iter->count);
}
static int static int
readpages_get_pages(struct address_space *mapping, struct list_head *page_list, readpages_get_pages(struct address_space *mapping, struct list_head *page_list,
unsigned int rsize, struct list_head *tmplist, unsigned int rsize, struct list_head *tmplist,
...@@ -3561,6 +3608,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -3561,6 +3608,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
rdata->pid = pid; rdata->pid = pid;
rdata->pagesz = PAGE_SIZE; rdata->pagesz = PAGE_SIZE;
rdata->read_into_pages = cifs_readpages_read_into_pages; rdata->read_into_pages = cifs_readpages_read_into_pages;
rdata->copy_into_pages = cifs_readpages_copy_into_pages;
rdata->credits = credits; rdata->credits = credits;
list_for_each_entry_safe(page, tpage, &tmplist, lru) { list_for_each_entry_safe(page, tpage, &tmplist, lru) {
......
...@@ -344,13 +344,12 @@ void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, ...@@ -344,13 +344,12 @@ void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
/* BB is NTLMV2 session security format easier to use here? */ /* BB is NTLMV2 session security format easier to use here? */
flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET | flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET |
NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC; NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC |
if (ses->server->sign) { NTLMSSP_NEGOTIATE_SEAL;
if (ses->server->sign)
flags |= NTLMSSP_NEGOTIATE_SIGN; flags |= NTLMSSP_NEGOTIATE_SIGN;
if (!ses->server->session_estab || if (!ses->server->session_estab || ses->ntlmssp->sesskey_per_smbsess)
ses->ntlmssp->sesskey_per_smbsess) flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
}
sec_blob->NegotiateFlags = cpu_to_le32(flags); sec_blob->NegotiateFlags = cpu_to_le32(flags);
...@@ -407,13 +406,12 @@ int build_ntlmssp_auth_blob(unsigned char **pbuffer, ...@@ -407,13 +406,12 @@ int build_ntlmssp_auth_blob(unsigned char **pbuffer,
flags = NTLMSSP_NEGOTIATE_56 | flags = NTLMSSP_NEGOTIATE_56 |
NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO |
NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC; NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC |
if (ses->server->sign) { NTLMSSP_NEGOTIATE_SEAL;
if (ses->server->sign)
flags |= NTLMSSP_NEGOTIATE_SIGN; flags |= NTLMSSP_NEGOTIATE_SIGN;
if (!ses->server->session_estab || if (!ses->server->session_estab || ses->ntlmssp->sesskey_per_smbsess)
ses->ntlmssp->sesskey_per_smbsess) flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
}
tmp = *pbuffer + sizeof(AUTHENTICATE_MESSAGE); tmp = *pbuffer + sizeof(AUTHENTICATE_MESSAGE);
sec_blob->NegotiateFlags = cpu_to_le32(flags); sec_blob->NegotiateFlags = cpu_to_le32(flags);
...@@ -652,6 +650,7 @@ sess_sendreceive(struct sess_data *sess_data) ...@@ -652,6 +650,7 @@ sess_sendreceive(struct sess_data *sess_data)
int rc; int rc;
struct smb_hdr *smb_buf = (struct smb_hdr *) sess_data->iov[0].iov_base; struct smb_hdr *smb_buf = (struct smb_hdr *) sess_data->iov[0].iov_base;
__u16 count; __u16 count;
struct kvec rsp_iov = { NULL, 0 };
count = sess_data->iov[1].iov_len + sess_data->iov[2].iov_len; count = sess_data->iov[1].iov_len + sess_data->iov[2].iov_len;
smb_buf->smb_buf_length = smb_buf->smb_buf_length =
...@@ -661,7 +660,9 @@ sess_sendreceive(struct sess_data *sess_data) ...@@ -661,7 +660,9 @@ sess_sendreceive(struct sess_data *sess_data)
rc = SendReceive2(sess_data->xid, sess_data->ses, rc = SendReceive2(sess_data->xid, sess_data->ses,
sess_data->iov, 3 /* num_iovecs */, sess_data->iov, 3 /* num_iovecs */,
&sess_data->buf0_type, &sess_data->buf0_type,
CIFS_LOG_ERROR); CIFS_LOG_ERROR, &rsp_iov);
cifs_small_buf_release(sess_data->iov[0].iov_base);
memcpy(&sess_data->iov[0], &rsp_iov, sizeof(struct kvec));
return rc; return rc;
} }
......
...@@ -36,11 +36,11 @@ ...@@ -36,11 +36,11 @@
* SMB_COM_NT_CANCEL request and then sends it. * SMB_COM_NT_CANCEL request and then sends it.
*/ */
static int static int
send_nt_cancel(struct TCP_Server_Info *server, void *buf, send_nt_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
struct mid_q_entry *mid) struct mid_q_entry *mid)
{ {
int rc = 0; int rc = 0;
struct smb_hdr *in_buf = (struct smb_hdr *)buf; struct smb_hdr *in_buf = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
/* -4 for RFC1001 length and +2 for BCC field */ /* -4 for RFC1001 length and +2 for BCC field */
in_buf->smb_buf_length = cpu_to_be32(sizeof(struct smb_hdr) - 4 + 2); in_buf->smb_buf_length = cpu_to_be32(sizeof(struct smb_hdr) - 4 + 2);
......
...@@ -61,4 +61,9 @@ ...@@ -61,4 +61,9 @@
/* Maximum buffer size value we can send with 1 credit */ /* Maximum buffer size value we can send with 1 credit */
#define SMB2_MAX_BUFFER_SIZE 65536 #define SMB2_MAX_BUFFER_SIZE 65536
static inline struct smb2_sync_hdr *get_sync_hdr(void *buf)
{
return &(((struct smb2_hdr *)buf)->sync_hdr);
}
#endif /* _SMB2_GLOB_H */ #endif /* _SMB2_GLOB_H */
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "smb2pdu.h" #include "smb2pdu.h"
#include "smb2proto.h" #include "smb2proto.h"
#include "smb2status.h" #include "smb2status.h"
#include "smb2glob.h"
struct status_to_posix_error { struct status_to_posix_error {
__le32 smb2_status; __le32 smb2_status;
...@@ -2449,10 +2450,10 @@ smb2_print_status(__le32 status) ...@@ -2449,10 +2450,10 @@ smb2_print_status(__le32 status)
int int
map_smb2_to_linux_error(char *buf, bool log_err) map_smb2_to_linux_error(char *buf, bool log_err)
{ {
struct smb2_hdr *hdr = (struct smb2_hdr *)buf; struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
unsigned int i; unsigned int i;
int rc = -EIO; int rc = -EIO;
__le32 smb2err = hdr->Status; __le32 smb2err = shdr->Status;
if (smb2err == 0) if (smb2err == 0)
return 0; return 0;
......
...@@ -28,31 +28,32 @@ ...@@ -28,31 +28,32 @@
#include "cifs_debug.h" #include "cifs_debug.h"
#include "cifs_unicode.h" #include "cifs_unicode.h"
#include "smb2status.h" #include "smb2status.h"
#include "smb2glob.h"
static int static int
check_smb2_hdr(struct smb2_hdr *hdr, __u64 mid) check_smb2_hdr(struct smb2_sync_hdr *shdr, __u64 mid)
{ {
__u64 wire_mid = le64_to_cpu(hdr->MessageId); __u64 wire_mid = le64_to_cpu(shdr->MessageId);
/* /*
* Make sure that this really is an SMB, that it is a response, * Make sure that this really is an SMB, that it is a response,
* and that the message ids match. * and that the message ids match.
*/ */
if ((hdr->ProtocolId == SMB2_PROTO_NUMBER) && if ((shdr->ProtocolId == SMB2_PROTO_NUMBER) &&
(mid == wire_mid)) { (mid == wire_mid)) {
if (hdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR) if (shdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR)
return 0; return 0;
else { else {
/* only one valid case where server sends us request */ /* only one valid case where server sends us request */
if (hdr->Command == SMB2_OPLOCK_BREAK) if (shdr->Command == SMB2_OPLOCK_BREAK)
return 0; return 0;
else else
cifs_dbg(VFS, "Received Request not response\n"); cifs_dbg(VFS, "Received Request not response\n");
} }
} else { /* bad signature or mid */ } else { /* bad signature or mid */
if (hdr->ProtocolId != SMB2_PROTO_NUMBER) if (shdr->ProtocolId != SMB2_PROTO_NUMBER)
cifs_dbg(VFS, "Bad protocol string signature header %x\n", cifs_dbg(VFS, "Bad protocol string signature header %x\n",
le32_to_cpu(hdr->ProtocolId)); le32_to_cpu(shdr->ProtocolId));
if (mid != wire_mid) if (mid != wire_mid)
cifs_dbg(VFS, "Mids do not match: %llu and %llu\n", cifs_dbg(VFS, "Mids do not match: %llu and %llu\n",
mid, wire_mid); mid, wire_mid);
...@@ -95,8 +96,9 @@ static const __le16 smb2_rsp_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = { ...@@ -95,8 +96,9 @@ static const __le16 smb2_rsp_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = {
int int
smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr) smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
{ {
struct smb2_hdr *hdr = (struct smb2_hdr *)buf; struct smb2_pdu *pdu = (struct smb2_pdu *)buf;
struct smb2_pdu *pdu = (struct smb2_pdu *)hdr; struct smb2_hdr *hdr = &pdu->hdr;
struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
__u64 mid; __u64 mid;
__u32 len = get_rfc1002_length(buf); __u32 len = get_rfc1002_length(buf);
__u32 clc_len; /* calculated length */ __u32 clc_len; /* calculated length */
...@@ -111,7 +113,7 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr) ...@@ -111,7 +113,7 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
* ie Validate the wct via smb2_struct_sizes table above * ie Validate the wct via smb2_struct_sizes table above
*/ */
if (hdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) { if (shdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) {
struct smb2_transform_hdr *thdr = struct smb2_transform_hdr *thdr =
(struct smb2_transform_hdr *)buf; (struct smb2_transform_hdr *)buf;
struct cifs_ses *ses = NULL; struct cifs_ses *ses = NULL;
...@@ -133,10 +135,10 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr) ...@@ -133,10 +135,10 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
} }
} }
mid = le64_to_cpu(shdr->MessageId);
mid = le64_to_cpu(hdr->MessageId);
if (length < sizeof(struct smb2_pdu)) { if (length < sizeof(struct smb2_pdu)) {
if ((length >= sizeof(struct smb2_hdr)) && (hdr->Status != 0)) { if ((length >= sizeof(struct smb2_hdr))
&& (shdr->Status != 0)) {
pdu->StructureSize2 = 0; pdu->StructureSize2 = 0;
/* /*
* As with SMB/CIFS, on some error cases servers may * As with SMB/CIFS, on some error cases servers may
...@@ -154,29 +156,30 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr) ...@@ -154,29 +156,30 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
return 1; return 1;
} }
if (check_smb2_hdr(hdr, mid)) if (check_smb2_hdr(shdr, mid))
return 1; return 1;
if (hdr->StructureSize != SMB2_HEADER_STRUCTURE_SIZE) { if (shdr->StructureSize != SMB2_HEADER_STRUCTURE_SIZE) {
cifs_dbg(VFS, "Illegal structure size %u\n", cifs_dbg(VFS, "Illegal structure size %u\n",
le16_to_cpu(hdr->StructureSize)); le16_to_cpu(shdr->StructureSize));
return 1; return 1;
} }
command = le16_to_cpu(hdr->Command); command = le16_to_cpu(shdr->Command);
if (command >= NUMBER_OF_SMB2_COMMANDS) { if (command >= NUMBER_OF_SMB2_COMMANDS) {
cifs_dbg(VFS, "Illegal SMB2 command %d\n", command); cifs_dbg(VFS, "Illegal SMB2 command %d\n", command);
return 1; return 1;
} }
if (smb2_rsp_struct_sizes[command] != pdu->StructureSize2) { if (smb2_rsp_struct_sizes[command] != pdu->StructureSize2) {
if (command != SMB2_OPLOCK_BREAK_HE && (hdr->Status == 0 || if (command != SMB2_OPLOCK_BREAK_HE && (shdr->Status == 0 ||
pdu->StructureSize2 != SMB2_ERROR_STRUCTURE_SIZE2)) { pdu->StructureSize2 != SMB2_ERROR_STRUCTURE_SIZE2)) {
/* error packets have 9 byte structure size */ /* error packets have 9 byte structure size */
cifs_dbg(VFS, "Illegal response size %u for command %d\n", cifs_dbg(VFS, "Illegal response size %u for command %d\n",
le16_to_cpu(pdu->StructureSize2), command); le16_to_cpu(pdu->StructureSize2), command);
return 1; return 1;
} else if (command == SMB2_OPLOCK_BREAK_HE && (hdr->Status == 0) } else if (command == SMB2_OPLOCK_BREAK_HE
&& (shdr->Status == 0)
&& (le16_to_cpu(pdu->StructureSize2) != 44) && (le16_to_cpu(pdu->StructureSize2) != 44)
&& (le16_to_cpu(pdu->StructureSize2) != 36)) { && (le16_to_cpu(pdu->StructureSize2) != 36)) {
/* special case for SMB2.1 lease break message */ /* special case for SMB2.1 lease break message */
...@@ -199,7 +202,7 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr) ...@@ -199,7 +202,7 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
clc_len, 4 + len, mid); clc_len, 4 + len, mid);
/* create failed on symlink */ /* create failed on symlink */
if (command == SMB2_CREATE_HE && if (command == SMB2_CREATE_HE &&
hdr->Status == STATUS_STOPPED_ON_SYMLINK) shdr->Status == STATUS_STOPPED_ON_SYMLINK)
return 0; return 0;
/* Windows 7 server returns 24 bytes more */ /* Windows 7 server returns 24 bytes more */
if (clc_len + 20 == len && command == SMB2_OPLOCK_BREAK_HE) if (clc_len + 20 == len && command == SMB2_OPLOCK_BREAK_HE)
...@@ -261,11 +264,12 @@ static const bool has_smb2_data_area[NUMBER_OF_SMB2_COMMANDS] = { ...@@ -261,11 +264,12 @@ static const bool has_smb2_data_area[NUMBER_OF_SMB2_COMMANDS] = {
char * char *
smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr) smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
{ {
struct smb2_sync_hdr *shdr = get_sync_hdr(hdr);
*off = 0; *off = 0;
*len = 0; *len = 0;
/* error responses do not have data area */ /* error responses do not have data area */
if (hdr->Status && hdr->Status != STATUS_MORE_PROCESSING_REQUIRED && if (shdr->Status && shdr->Status != STATUS_MORE_PROCESSING_REQUIRED &&
(((struct smb2_err_rsp *)hdr)->StructureSize) == (((struct smb2_err_rsp *)hdr)->StructureSize) ==
SMB2_ERROR_STRUCTURE_SIZE2) SMB2_ERROR_STRUCTURE_SIZE2)
return NULL; return NULL;
...@@ -275,7 +279,7 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr) ...@@ -275,7 +279,7 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
* of the data buffer offset and data buffer length for the particular * of the data buffer offset and data buffer length for the particular
* command. * command.
*/ */
switch (hdr->Command) { switch (shdr->Command) {
case SMB2_NEGOTIATE: case SMB2_NEGOTIATE:
*off = le16_to_cpu( *off = le16_to_cpu(
((struct smb2_negotiate_rsp *)hdr)->SecurityBufferOffset); ((struct smb2_negotiate_rsp *)hdr)->SecurityBufferOffset);
...@@ -346,7 +350,7 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr) ...@@ -346,7 +350,7 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
/* return pointer to beginning of data area, ie offset from SMB start */ /* return pointer to beginning of data area, ie offset from SMB start */
if ((*off != 0) && (*len != 0)) if ((*off != 0) && (*len != 0))
return (char *)(&hdr->ProtocolId) + *off; return (char *)shdr + *off;
else else
return NULL; return NULL;
} }
...@@ -358,12 +362,13 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr) ...@@ -358,12 +362,13 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
unsigned int unsigned int
smb2_calc_size(void *buf) smb2_calc_size(void *buf)
{ {
struct smb2_hdr *hdr = (struct smb2_hdr *)buf; struct smb2_pdu *pdu = (struct smb2_pdu *)buf;
struct smb2_pdu *pdu = (struct smb2_pdu *)hdr; struct smb2_hdr *hdr = &pdu->hdr;
struct smb2_sync_hdr *shdr = get_sync_hdr(hdr);
int offset; /* the offset from the beginning of SMB to data area */ int offset; /* the offset from the beginning of SMB to data area */
int data_length; /* the length of the variable length data area */ int data_length; /* the length of the variable length data area */
/* Structure Size has already been checked to make sure it is 64 */ /* Structure Size has already been checked to make sure it is 64 */
int len = 4 + le16_to_cpu(pdu->hdr.StructureSize); int len = 4 + le16_to_cpu(shdr->StructureSize);
/* /*
* StructureSize2, ie length of fixed parameter area has already * StructureSize2, ie length of fixed parameter area has already
...@@ -371,7 +376,7 @@ smb2_calc_size(void *buf) ...@@ -371,7 +376,7 @@ smb2_calc_size(void *buf)
*/ */
len += le16_to_cpu(pdu->StructureSize2); len += le16_to_cpu(pdu->StructureSize2);
if (has_smb2_data_area[le16_to_cpu(hdr->Command)] == false) if (has_smb2_data_area[le16_to_cpu(shdr->Command)] == false)
goto calc_size_exit; goto calc_size_exit;
smb2_get_data_area_len(&offset, &data_length, hdr); smb2_get_data_area_len(&offset, &data_length, hdr);
...@@ -582,7 +587,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) ...@@ -582,7 +587,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
cifs_dbg(FYI, "Checking for oplock break\n"); cifs_dbg(FYI, "Checking for oplock break\n");
if (rsp->hdr.Command != SMB2_OPLOCK_BREAK) if (rsp->hdr.sync_hdr.Command != SMB2_OPLOCK_BREAK)
return false; return false;
if (rsp->StructureSize != if (rsp->StructureSize !=
......
This diff is collapsed.
This diff is collapsed.
...@@ -101,10 +101,7 @@ ...@@ -101,10 +101,7 @@
#define SMB2_HEADER_STRUCTURE_SIZE cpu_to_le16(64) #define SMB2_HEADER_STRUCTURE_SIZE cpu_to_le16(64)
struct smb2_hdr { struct smb2_sync_hdr {
__be32 smb2_buf_length; /* big endian on wire */
/* length is only two or three bytes - with
one or two byte type preceding it that MBZ */
__le32 ProtocolId; /* 0xFE 'S' 'M' 'B' */ __le32 ProtocolId; /* 0xFE 'S' 'M' 'B' */
__le16 StructureSize; /* 64 */ __le16 StructureSize; /* 64 */
__le16 CreditCharge; /* MBZ */ __le16 CreditCharge; /* MBZ */
...@@ -120,16 +117,31 @@ struct smb2_hdr { ...@@ -120,16 +117,31 @@ struct smb2_hdr {
__u8 Signature[16]; __u8 Signature[16];
} __packed; } __packed;
struct smb2_sync_pdu {
struct smb2_sync_hdr sync_hdr;
__le16 StructureSize2; /* size of wct area (varies, request specific) */
} __packed;
struct smb2_hdr {
__be32 smb2_buf_length; /* big endian on wire */
/* length is only two or three bytes - with */
/* one or two byte type preceding it that MBZ */
struct smb2_sync_hdr sync_hdr;
} __packed;
struct smb2_pdu { struct smb2_pdu {
struct smb2_hdr hdr; struct smb2_hdr hdr;
__le16 StructureSize2; /* size of wct area (varies, request specific) */ __le16 StructureSize2; /* size of wct area (varies, request specific) */
} __packed; } __packed;
#define SMB3_AES128CMM_NONCE 11
#define SMB3_AES128GCM_NONCE 12
struct smb2_transform_hdr { struct smb2_transform_hdr {
__be32 smb2_buf_length; /* big endian on wire */ __be32 smb2_buf_length; /* big endian on wire */
/* length is only two or three bytes - with /* length is only two or three bytes - with
one or two byte type preceding it that MBZ */ one or two byte type preceding it that MBZ */
__u8 ProtocolId[4]; /* 0xFD 'S' 'M' 'B' */ __le32 ProtocolId; /* 0xFD 'S' 'M' 'B' */
__u8 Signature[16]; __u8 Signature[16];
__u8 Nonce[16]; __u8 Nonce[16];
__le32 OriginalMessageSize; __le32 OriginalMessageSize;
...@@ -814,8 +826,9 @@ struct smb2_flush_rsp { ...@@ -814,8 +826,9 @@ struct smb2_flush_rsp {
#define SMB2_CHANNEL_RDMA_V1 0x00000001 /* SMB3 or later */ #define SMB2_CHANNEL_RDMA_V1 0x00000001 /* SMB3 or later */
#define SMB2_CHANNEL_RDMA_V1_INVALIDATE 0x00000001 /* SMB3.02 or later */ #define SMB2_CHANNEL_RDMA_V1_INVALIDATE 0x00000001 /* SMB3.02 or later */
struct smb2_read_req { /* SMB2 read request without RFC1001 length at the beginning */
struct smb2_hdr hdr; struct smb2_read_plain_req {
struct smb2_sync_hdr sync_hdr;
__le16 StructureSize; /* Must be 49 */ __le16 StructureSize; /* Must be 49 */
__u8 Padding; /* offset from start of SMB2 header to place read */ __u8 Padding; /* offset from start of SMB2 header to place read */
__u8 Flags; /* MBZ unless SMB3.02 or later */ __u8 Flags; /* MBZ unless SMB3.02 or later */
......
...@@ -56,6 +56,10 @@ extern void smb2_echo_request(struct work_struct *work); ...@@ -56,6 +56,10 @@ extern void smb2_echo_request(struct work_struct *work);
extern __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode); extern __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode);
extern bool smb2_is_valid_oplock_break(char *buffer, extern bool smb2_is_valid_oplock_break(char *buffer,
struct TCP_Server_Info *srv); struct TCP_Server_Info *srv);
extern struct cifs_ses *smb2_find_smb_ses(struct TCP_Server_Info *server,
__u64 ses_id);
extern int smb3_handle_read_data(struct TCP_Server_Info *server,
struct mid_q_entry *mid);
extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst, extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst,
struct smb2_file_all_info *src); struct smb2_file_all_info *src);
...@@ -97,6 +101,7 @@ extern int smb2_unlock_range(struct cifsFileInfo *cfile, ...@@ -97,6 +101,7 @@ extern int smb2_unlock_range(struct cifsFileInfo *cfile,
struct file_lock *flock, const unsigned int xid); struct file_lock *flock, const unsigned int xid);
extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile); extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile);
extern void smb2_reconnect_server(struct work_struct *work); extern void smb2_reconnect_server(struct work_struct *work);
extern int smb3_crypto_aead_allocate(struct TCP_Server_Info *server);
/* /*
* SMB2 Worker functions - most of protocol specific implementation details * SMB2 Worker functions - most of protocol specific implementation details
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment