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

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
Loading
Loading
Loading
Loading
+7 −5
Original line number Original line Diff line number Diff line
@@ -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


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


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 −17
Original line number Original line Diff line number Diff line
@@ -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,
	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 */
		if (i == 0) {
			if (iov[0].iov_len <= 8) /* cmd field at offset 9 */
			break; /* nothing to sign or corrupt header */
			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,
		rc = crypto_shash_update(shash,
					 iov[i].iov_base, iov[i].iov_len);
					 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,
	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,
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,
	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)
}
}


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)
		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);
+14 −0
Original line number Original line Diff line number Diff line
@@ -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)
+26 −2
Original line number Original line Diff line number Diff line
@@ -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;
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 {
	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 {
	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,
 */
 */
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 {
#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 {
	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,
#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
+10 −3
Original line number Original line Diff line number Diff line
@@ -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,
				 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 *,
			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 *);
Loading