All of lore.kernel.org
 help / color / mirror / Atom feed
From: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Subject: [PATCH 10/16] CIFS: Add capability to send SMB2 negotiate message
Date: Mon, 26 Mar 2012 13:21:37 +0400	[thread overview]
Message-ID: <1332753703-4315-11-git-send-email-piastry@etersoft.ru> (raw)
In-Reply-To: <1332753703-4315-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>

and temporarily disable SMB2.1 negotiating.

Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
 fs/cifs/Makefile    |    2 +-
 fs/cifs/cifsglob.h  |   11 +-
 fs/cifs/cifsproto.h |    1 +
 fs/cifs/cifssmb.c   |    8 +-
 fs/cifs/connect.c   |   21 +++-
 fs/cifs/misc.c      |    3 +-
 fs/cifs/sess.c      |    2 +-
 fs/cifs/smb2misc.c  |    8 +-
 fs/cifs/smb2pdu.c   |  385 +++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/cifs/smb2pdu.h   |   39 +++++
 fs/cifs/smb2proto.h |    8 +
 11 files changed, 475 insertions(+), 13 deletions(-)
 create mode 100644 fs/cifs/smb2pdu.c

diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile
index 5bbafe4..2af9cbb 100644
--- a/fs/cifs/Makefile
+++ b/fs/cifs/Makefile
@@ -16,4 +16,4 @@ cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o
 
 cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o
 
-cifs-$(CONFIG_CIFS_SMB2) += smb2maperror.o smb2transport.o smb2misc.o
+cifs-$(CONFIG_CIFS_SMB2) += smb2maperror.o smb2transport.o smb2misc.o smb2pdu.o
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 658280e..49f6a57 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -269,7 +269,7 @@ struct TCP_Server_Info {
 	struct mutex srv_mutex;
 	struct task_struct *tsk;
 	char server_GUID[16];
-	char sec_mode;
+	__u16 sec_mode;
 	bool session_estab; /* mark when very first sess is established */
 #ifdef CONFIG_CIFS_SMB2
 	bool is_smb2;	/* SMB2 not CIFS protocol negotiated */
@@ -322,6 +322,10 @@ struct TCP_Server_Info {
 	atomic_t in_send; /* requests trying to send */
 	atomic_t num_waiters;   /* blocked waiting to get in sendrecv */
 #endif
+#ifdef CONFIG_CIFS_SMB2
+	unsigned int	max_read;
+	unsigned int	max_write;
+#endif /* CONFIG_CIFS_SMB2 */
 };
 
 static inline unsigned int
@@ -336,7 +340,8 @@ in_flight(struct TCP_Server_Info *server)
 
 #define   CIFS_OBREAK_OP    0x080    /* oplock break request */
 #define   CIFS_ECHO_OP     0x0100    /* echo request */
-#define   CIFS_REQ_MASK    0x0180    /* mask request type */
+#define   CIFS_NEG_OP      0x0200    /* negotiate request */
+#define   CIFS_REQ_MASK    0x0380    /* mask request type */
 
 static inline int*
 get_credits_field(struct TCP_Server_Info *server, const int optype)
@@ -432,7 +437,7 @@ struct cifs_ses {
 	char *serverOS;		/* name of operating system underlying server */
 	char *serverNOS;	/* name of network operating system of server */
 	char *serverDomain;	/* security realm of server */
-	int Suid;		/* remote smb uid  */
+	__u64 Suid;		/* remote smb uid  */
 	uid_t linux_uid;        /* overriding owner of files on the mount */
 	uid_t cred_uid;		/* owner of credentials */
 	int capabilities;
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index b92e4ab..5378311 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -178,6 +178,7 @@ extern struct smb_vol *cifs_get_volume_info(char *mount_data,
 					    const char *devname);
 extern int cifs_mount(struct cifs_sb_info *, struct smb_vol *);
 extern void cifs_umount(struct cifs_sb_info *);
+extern void cifs_mark_open_files_invalid(struct cifs_tcon *tcon);
 
 #if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL)
 extern void cifs_dfs_release_automount_timer(void);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index e858d9c..c97dcdc 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -91,7 +91,7 @@ static void cifs_readv_complete(struct work_struct *work);
 
 /* Mark as invalid, all open files on tree connections since they
    were closed when session to server was lost */
-static void mark_open_files_invalid(struct cifs_tcon *pTcon)
+void cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
 {
 	struct cifsFileInfo *open_file = NULL;
 	struct list_head *tmp;
@@ -99,7 +99,7 @@ static void mark_open_files_invalid(struct cifs_tcon *pTcon)
 
 /* list all files open on tree connection and mark them invalid */
 	spin_lock(&cifs_file_list_lock);
-	list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
+	list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
 		open_file = list_entry(tmp, struct cifsFileInfo, tlist);
 		open_file->invalidHandle = true;
 		open_file->oplock_break_cancelled = true;
@@ -186,7 +186,7 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
 		goto out;
 	}
 
-	mark_open_files_invalid(tcon);
+	cifs_mark_open_files_invalid(tcon);
 	rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
 	mutex_unlock(&ses->session_mutex);
 	cFYI(1, "reconnect tcon rc = %d", rc);
@@ -457,7 +457,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
 			rc = -EOPNOTSUPP;
 			goto neg_err_exit;
 		}
-		server->sec_mode = (__u8)le16_to_cpu(rsp->SecurityMode);
+		server->sec_mode = le16_to_cpu(rsp->SecurityMode);
 		server->maxReq = min_t(unsigned int,
 				       le16_to_cpu(rsp->MaxMpxCount),
 				       cifs_max_pending);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 7a7ef74..c59d051 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -4124,11 +4124,26 @@ int cifs_negotiate_protocol(unsigned int xid, struct cifs_ses *ses)
 	int rc = 0;
 	struct TCP_Server_Info *server = ses->server;
 
+	cifs_set_credits(server, 1);
+
+#ifdef CONFIG_CIFS_SMB2
+	if (ses->server->is_smb2) {
+		if (server->max_read != 0)
+			return 0;
+		server->CurrentMid = 0;
+		rc = SMB2_negotiate(xid, ses);
+		/* BB we probably don't need to retry with modern servers */
+		if (rc == -EAGAIN)
+			rc = -EHOSTDOWN;
+
+		goto neg_prot_exit;
+	}
+#endif /* CONFIG_CIFS_SMB2 */
+
 	/* only send once per connect */
 	if (server->maxBuf != 0)
 		return 0;
 
-	cifs_set_credits(server, 1);
 	rc = CIFSSMBNegotiate(xid, ses);
 	if (rc == -EAGAIN) {
 		/* retry only once on 1st time connection */
@@ -4137,6 +4152,10 @@ int cifs_negotiate_protocol(unsigned int xid, struct cifs_ses *ses)
 		if (rc == -EAGAIN)
 			rc = -EHOSTDOWN;
 	}
+
+#ifdef CONFIG_CIFS_SMB2
+neg_prot_exit:
+#endif /* CONFIG_CIFS_SMB2 */
 	if (rc == 0) {
 		spin_lock(&GlobalMid_Lock);
 		if (server->tcpStatus == CifsNeedNegotiate)
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index cd587c0..fd8bef7 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -777,7 +777,8 @@ cifs_add_credits(struct TCP_Server_Info *server, const unsigned int add,
 	*val += add;
 	server->in_flight--;
 #ifdef CONFIG_CIFS_SMB2
-	if (server->is_smb2 && server->in_flight == 0) {
+	if (server->is_smb2 && server->in_flight == 0 &&
+	    (optype & CIFS_REQ_MASK) != CIFS_NEG_OP) {
 		server->credits += server->echo_credits +
 				   server->oplock_credits;
 		cifs_change_conf(server);
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index 551d0c2..f88fa4d 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -898,7 +898,7 @@ ssetup_ntlmssp_authenticate:
 	if (action & GUEST_LOGIN)
 		cFYI(1, "Guest login"); /* BB mark SesInfo struct? */
 	ses->Suid = smb_buf->Uid;   /* UID left in wire format (le) */
-	cFYI(1, "UID = %d ", ses->Suid);
+	cFYI(1, "UID = %llu ", ses->Suid);
 	/* response can have either 3 or 4 word count - Samba sends 3 */
 	/* and lanman response is 3 */
 	bytes_remaining = get_bcc(smb_buf);
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
index db9ecd5..88918ac 100644
--- a/fs/cifs/smb2misc.c
+++ b/fs/cifs/smb2misc.c
@@ -198,8 +198,7 @@ static const bool has_smb2_data_area[NUMBER_OF_SMB2_COMMANDS] = {
  * Returns the pointer to the beginning of the data area. Length of the data
  * area and the offset to it (from the beginning of the smb are also returned.
  */
-static char *
-smb2_get_data_area_len(int *poff, int *plen, struct smb2_hdr *pSMB2)
+char *smb2_get_data_area_len(int *poff, int *plen, struct smb2_hdr *pSMB2)
 {
 	*poff = 0;
 	*plen = 0;
@@ -217,6 +216,11 @@ smb2_get_data_area_len(int *poff, int *plen, struct smb2_hdr *pSMB2)
 	 */
 	switch (pSMB2->Command) {
 	case SMB2_NEGOTIATE:
+		*poff = le16_to_cpu(
+		    ((struct smb2_negotiate_rsp *)pSMB2)->SecurityBufferOffset);
+		*plen = le16_to_cpu(
+		    ((struct smb2_negotiate_rsp *)pSMB2)->SecurityBufferLength);
+		break;
 	case SMB2_SESSION_SETUP:
 	case SMB2_CREATE:
 	case SMB2_READ:
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
new file mode 100644
index 0000000..1a12e7f
--- /dev/null
+++ b/fs/cifs/smb2pdu.c
@@ -0,0 +1,385 @@
+/*
+ *   fs/cifs/smb2pdu.c
+ *
+ *   Copyright (C) International Business Machines  Corp., 2009, 2011
+ *                 Etersoft, 2012
+ *   Author(s): Steve French (sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org)
+ *              Pavel Shilovsky (pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org) 2012
+ *
+ *   Contains the routines for constructing the SMB2 PDUs themselves
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+ /* SMB2 PDU handling routines here - except for leftovers (eg session setup) */
+ /* Note that there are handle based routines which must be		      */
+ /* treated slightly differently for reconnection purposes since we never     */
+ /* want to reuse a stale file handle and only the caller knows the file info */
+
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/vfs.h>
+#include <linux/uaccess.h>
+#include <linux/xattr.h>
+#include "smb2pdu.h"
+#include "cifsglob.h"
+#include "cifsacl.h"
+#include "cifsproto.h"
+#include "smb2proto.h"
+#include "cifs_unicode.h"
+#include "cifs_debug.h"
+#include "ntlmssp.h"
+#include "smb2status.h"
+
+/*
+ *  The following table defines the expected "StructureSize" of SMB2 requests
+ *  in order by SMB2 command.  This is similar to "wct" in SMB/CIFS requests.
+ *
+ *  Note that commands are defined in smb2pdu.h in le16 but the array below is
+ *  indexed by command in host byte order
+ */
+static const int smb2_req_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = {
+	/* SMB2_NEGOTIATE */ 36,
+	/* SMB2_SESSION_SETUP */ 25,
+	/* SMB2_LOGOFF */ 4,
+	/* SMB2_TREE_CONNECT */	9,
+	/* SMB2_TREE_DISCONNECT */ 4,
+	/* SMB2_CREATE */ 57,
+	/* SMB2_CLOSE */ 24,
+	/* SMB2_FLUSH */ 24,
+	/* SMB2_READ */	49,
+	/* SMB2_WRITE */ 49,
+	/* SMB2_LOCK */	48,
+	/* SMB2_IOCTL */ 57,
+	/* SMB2_CANCEL */ 4,
+	/* SMB2_ECHO */ 4,
+	/* SMB2_QUERY_DIRECTORY */ 33,
+	/* SMB2_CHANGE_NOTIFY */ 32,
+	/* SMB2_QUERY_INFO */ 41,
+	/* SMB2_SET_INFO */ 33,
+	/* SMB2_OPLOCK_BREAK */  24 /* BB this is 36 for LEASE_BREAK variant */
+};
+
+
+/*
+ * NB: MID can not be set if tcon not passed in, in that
+ * case it is responsbility of caller to set the mid
+ */
+static void
+smb2_hdr_assemble(struct smb2_hdr *buffer, __le16 smb2_cmd /* command */ ,
+		  const struct cifs_tcon *tcon)
+{
+	struct list_head *temp_item;
+	struct cifs_ses *ses;
+	struct smb2_pdu *smb = (struct smb2_pdu *)buffer;
+	char *temp = (char *) buffer;
+	/* lookup word count ie StructureSize from table */
+	__u16 parmsize = smb2_req_struct_sizes[le16_to_cpu(smb2_cmd)];
+
+	/*
+	 * smaller than SMALL_BUFFER_SIZE but bigger than fixed area of
+	 * largest operations (Create)
+	 */
+	memset(temp, 0, 256);
+
+	/* Note this is only network field converted to big endian */
+	buffer->smb2_buf_length = cpu_to_be32(parmsize + sizeof(struct smb2_hdr)
+			- 4 /*  RFC 1001 length field itself not counted */);
+
+	buffer->ProtocolId[0] = 0xFE;
+	buffer->ProtocolId[1] = 'S';
+	buffer->ProtocolId[2] = 'M';
+	buffer->ProtocolId[3] = 'B';
+	buffer->StructureSize = cpu_to_le16(64);
+	buffer->Command = smb2_cmd;
+	buffer->CreditRequest = cpu_to_le16(2); /* BB make this dynamic */
+	buffer->ProcessId = cpu_to_le32((__u16)current->tgid);
+
+	if (!tcon)
+		goto out;
+
+	buffer->TreeId = tcon->tid;
+	/* For the multiuser case, there are few obvious technically  */
+	/* possible mechanisms to match the local linux user (uid)    */
+	/* to a valid remote smb user (smb_uid):		      */
+	/*      1) Query Winbind (or other local pam/nss daemon       */
+	/*         for userid/password/logon_domain or credential      */
+	/*      2) Query Winbind for uid to sid to username mapping   */
+	/*         and see if we have a matching password for existing*/
+	/*         session for that user perhas getting password by   */
+	/*         adding a new pam_smb2 module that stores passwords */
+	/*         so that the smb2 vfs can get at that for all logged*/
+	/*         on users					      */
+	/*      3) (Which is the mechanism we have chosen)	      */
+	/*         Search through sessions to the same server for a   */
+	/*         a match on the uid that was passed in on mount     */
+	/*         with the current processes uid (or euid?) and use  */
+	/*         that smb uid.   If no existing smb session for     */
+	/*         that uid found, use the default smb session ie     */
+	/*         the smb session for the volume mounted which is    */
+	/*         the same as would be used if the multiuser mount   */
+	/*         flag were disabled.  */
+
+	/*  BB Add support for establishing new tcon and SMB Session  */
+	/*      with userid/password pairs found on the smb session   */
+	/*      for other target tcp/ip addresses		BB    */
+	if (!tcon->ses)
+		goto set_tcon_flags;
+
+	/* Uid is not converted */
+	buffer->SessionId = tcon->ses->Suid;
+	/* BB check this against related recent cifs changes */
+	if (multiuser_mount == 0)
+		goto set_tcon_flags;
+
+	if (current_fsuid() == tcon->ses->linux_uid)
+		goto set_tcon_flags;
+
+	cFYI(1, "Multiuser mode and UID did not match tcon uid");
+	spin_lock(&cifs_tcp_ses_lock);
+	list_for_each(temp_item,
+		      &tcon->ses->server->smb_ses_list) {
+		ses = list_entry(temp_item, struct cifs_ses,
+				 smb_ses_list);
+		if (ses->linux_uid == current_fsuid()) {
+			if (ses->server == tcon->ses->server) {
+				buffer->SessionId = ses->Suid;
+				break;
+			}
+			/* BB eventually setup a session here */
+			cFYI(1, "local UID found but no smb ses server exists");
+		}
+	}
+	spin_unlock(&cifs_tcp_ses_lock);
+set_tcon_flags:
+	/* BB check following DFS flags BB */
+	/* BB do we have to add check for SHI1005_FLAGS_DFS_ROOT too? */
+	/* if (tcon->share_flags & SHI1005_FLAGS_DFS)
+		buffer->Flags |= SMB2_FLAGS_DFS_OPERATIONS; */
+	/* BB how does SMB2 do case sensitive? */
+	/* if (tcon->nocase)
+		buffer->Flags |= SMBFLG_CASELESS; */
+	/* if (tcon->ses && tcon->ses->server &&
+	    (tcon->ses->server->sec_mode & SECMODE_SIGN_REQUIRED))
+		buffer->Flags |= SMB2_FLAGS_SIGNED; */
+out:
+	smb->StructureSize2 = cpu_to_le16(parmsize);
+	return;
+}
+
+static int
+smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
+{
+	int rc = 0;
+	/* BB add missing code here */
+	return rc;
+}
+
+/*
+ * Allocate and return pointer to an SMB request buffer, and set basic
+ * SMB information in the SMB header. If the return code is zero, this
+ * function must have filled in request_buf pointer.
+ */
+static int
+small_smb2_init(__le16 smb2_command, struct cifs_tcon *tcon,
+		void **request_buf)
+{
+	int rc = 0;
+
+	rc = smb2_reconnect(smb2_command, tcon);
+	if (rc)
+		return rc;
+
+	/* BB eventually switch this to SMB2 specific small buf size */
+	*request_buf = cifs_small_buf_get();
+	if (*request_buf == NULL) {
+		/* BB should we add a retry in here if not a writepage? */
+		return -ENOMEM;
+	}
+
+	smb2_hdr_assemble((struct smb2_hdr *) *request_buf, smb2_command, tcon);
+
+	if (tcon != NULL) {
+#ifdef CONFIG_CIFS_STATS2
+		/*
+		uint16_t com_code = le16_to_cpu(smb2_command);
+		cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_sent[com_code]);
+		*/
+#endif
+		cifs_stats_inc(&tcon->num_smbs_sent);
+	}
+
+	return rc;
+}
+
+static void free_rsp_buf(int resp_buftype, void *pSMB2r)
+{
+	if (resp_buftype == CIFS_SMALL_BUFFER)
+		cifs_small_buf_release(pSMB2r);
+	else if (resp_buftype == CIFS_LARGE_BUFFER)
+		cifs_buf_release(pSMB2r);
+}
+
+#define SMB2_NUM_PROT 1
+
+#define SMB2_PROT   0
+#define SMB21_PROT  1
+#define BAD_PROT 0xFFFF
+
+#define SMB2_PROT_ID  0x0202
+#define SMB21_PROT_ID 0x0210
+#define BAD_PROT_ID   0xFFFF
+
+static struct {
+	int index;
+	__le16 name;
+} smb2protocols[] = {
+	{SMB2_PROT,  cpu_to_le16(SMB2_PROT_ID)},
+	{SMB21_PROT, cpu_to_le16(SMB21_PROT_ID)},
+	{BAD_PROT,   cpu_to_le16(BAD_PROT_ID)}
+};
+
+/*
+ *
+ *	SMB2 Worker functions follow:
+ *
+ *	The general structure of the worker functions is:
+ *	1) Call smb2_init (assembles SMB2 header)
+ *	2) Initialize SMB2 command specific fields in fixed length area of SMB
+ *	3) Call smb_sendrcv2 (sends request on socket and waits for response)
+ *	4) Decode SMB2 command specific fields in the fixed length area
+ *	5) Decode variable length data area (if any for this SMB2 command type)
+ *	6) Call free smb buffer
+ *	7) return
+ *
+ */
+
+int
+SMB2_negotiate(unsigned int xid, struct cifs_ses *ses)
+{
+	struct smb2_negotiate_req *pSMB2;
+	struct smb2_negotiate_rsp *pSMB2r;
+	struct kvec iov[1];
+	int rc = 0;
+	int resp_buftype;
+	struct TCP_Server_Info *server;
+	unsigned int sec_flags;
+	u16 i;
+	u16 temp = 0;
+	int blob_offset, blob_length;
+	char *security_blob;
+	int flags = CIFS_NEG_OP;
+
+	cFYI(1, "Negotiate protocol");
+
+	if (ses->server)
+		server = ses->server;
+	else {
+		rc = -EIO;
+		return rc;
+	}
+
+	rc = small_smb2_init(SMB2_NEGOTIATE, NULL, (void **) &pSMB2);
+	if (rc)
+		return rc;
+
+	/* if any of auth flags (ie not sign or seal) are overriden use them */
+	if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
+		sec_flags = ses->overrideSecFlg;  /* BB FIXME fix sign flags?*/
+	else /* if override flags set only sign/seal OR them with global auth */
+		sec_flags = global_secflags | ses->overrideSecFlg;
+
+	cFYI(1, "sec_flags 0x%x", sec_flags);
+
+	pSMB2->hdr.SessionId = 0;
+
+	for (i = 0; i < SMB2_NUM_PROT; i++)
+		pSMB2->Dialects[i] = smb2protocols[i].name;
+
+	pSMB2->DialectCount = cpu_to_le16(i);
+	pSMB2->hdr.smb2_buf_length =
+		cpu_to_be32(be32_to_cpu(pSMB2->hdr.smb2_buf_length) + (i * 2));
+
+	/* only one of SMB2 signing flags may be set in SMB2 request */
+	if ((sec_flags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN)
+		temp = SMB2_NEGOTIATE_SIGNING_REQUIRED;
+	else if (sec_flags & CIFSSEC_MAY_SIGN) /* MAY_SIGN is a single flag */
+		temp = SMB2_NEGOTIATE_SIGNING_ENABLED;
+
+	pSMB2->SecurityMode = cpu_to_le16(temp);
+
+	pSMB2->Capabilities = cpu_to_le32(SMB2_GLOBAL_CAP_DFS);
+
+	iov[0].iov_base = (char *)pSMB2;
+	iov[0].iov_len = be32_to_cpu(pSMB2->hdr.smb2_buf_length) + 4;
+
+	rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, flags);
+
+	pSMB2r = (struct smb2_negotiate_rsp *)iov[0].iov_base;
+	/*
+	 * No tcon so can't do
+	 * cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]);
+	 */
+	if (rc != 0)
+		goto neg_exit;
+
+	if (pSMB2r == NULL) {
+		rc = -EIO;
+		goto neg_exit;
+	}
+
+	cFYI(1, "mode 0x%x", pSMB2r->SecurityMode);
+
+	if (pSMB2r->DialectRevision == smb2protocols[SMB21_PROT].name)
+		cFYI(1, "negotiated smb2.1 dialect");
+	else if (pSMB2r->DialectRevision == smb2protocols[SMB2_PROT].name)
+		cFYI(1, "negotiated smb2 dialect");
+	else {
+		cERROR(1, "Illegal dialect returned by server %d",
+			   le16_to_cpu(pSMB2r->DialectRevision));
+		rc = -EIO;
+		goto neg_exit;
+	}
+	ses->server->dialect = le16_to_cpu(pSMB2r->DialectRevision);
+
+	ses->server->maxBuf = le32_to_cpu(pSMB2r->MaxTransactSize);
+	ses->server->max_read = le32_to_cpu(pSMB2r->MaxReadSize);
+	ses->server->max_write = le32_to_cpu(pSMB2r->MaxWriteSize);
+	/* BB Do we need to validate the SecurityMode? */
+	ses->server->sec_mode = le16_to_cpu(pSMB2r->SecurityMode);
+	ses->server->capabilities = le32_to_cpu(pSMB2r->Capabilities);
+
+	security_blob = smb2_get_data_area_len(&blob_offset, &blob_length,
+					       &pSMB2r->hdr);
+	if (blob_length == 0) {
+		cERROR(1, "missing security blob on negprot");
+		rc = -EIO;
+		goto neg_exit;
+	}
+#ifdef CONFIG_SMB2_ASN1  /* BB REMOVEME when updated asn1.c ready */
+	rc = decode_neg_token_init(security_blob, blob_length,
+				   &ses->server->sec_type);
+	if (rc == 1)
+		rc = 0;
+	else if (rc == 0) {
+		rc = -EIO;
+		goto neg_exit;
+	}
+#endif
+
+neg_exit:
+	free_rsp_buf(resp_buftype, pSMB2r);
+	return rc;
+}
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 66ab8d6..65be640 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -142,4 +142,43 @@ struct smb2_err_rsp {
 	__u8   ErrorData[1];  /* variable length */
 } __packed;
 
+struct smb2_negotiate_req {
+	struct smb2_hdr hdr;
+	__le16 StructureSize; /* Must be 36 */
+	__le16 DialectCount;
+	__le16 SecurityMode;
+	__le16 Reserved;	/* MBZ */
+	__le32 Capabilities;
+	__u8   ClientGUID[16];	/* MBZ */
+	__le64 ClientStartTime;	/* MBZ */
+	__le16 Dialects[2]; /* variable length */ /* Must include 0x0202 */
+} __packed;
+
+/* SecurityMode flags */
+#define	SMB2_NEGOTIATE_SIGNING_ENABLED	0x0001
+#define SMB2_NEGOTIATE_SIGNING_REQUIRED	0x0002
+/* Capabilities flags */
+#define SMB2_GLOBAL_CAP_DFS		0x00000001
+#define SMB2_GLOBAL_CAP_LEASING		0x00000002 /* Resp only New to SMB2.1 */
+#define SMB2_GLOBAL_CAP_LARGE_MTU	0X00000004 /* Resp only New to SMB2.1 */
+
+struct smb2_negotiate_rsp {
+	struct smb2_hdr hdr;
+	__le16 StructureSize;	/* Must be 65 */
+	__le16 SecurityMode;
+	__le16 DialectRevision; /* Should be 0x0202 */
+	__le16 Reserved;	/* MBZ */
+	__u8   ServerGUID[16];
+	__le32 Capabilities;
+	__le32 MaxTransactSize;
+	__le32 MaxReadSize;
+	__le32 MaxWriteSize;
+	__le64 SystemTime;	/* MBZ */
+	__le64 ServerStartTime;
+	__le16 SecurityBufferOffset;
+	__le16 SecurityBufferLength;
+	__le32 Reserved2;	/* may be any value, Ignore */
+	__u8   Buffer[1];	/* variable length GSS security buffer */
+} __packed;
+
 #endif				/* _SMB2PDU_H */
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 1c7c8e4..bc283ff 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -35,10 +35,18 @@ struct statfs;
 extern int map_smb2_to_linux_error(struct smb2_hdr *smb2, int log_err);
 extern int checkSMB2(char *buf, unsigned int length);
 extern unsigned int smb2_calc_size(struct smb2_hdr *pSMB2h);
+extern char *smb2_get_data_area_len(int *poff, int *plen,
+				     struct smb2_hdr *pSMB2);
 
 extern int smb2_check_receive(struct mid_q_entry *mid,
 			      struct TCP_Server_Info *server, bool log_error);
 extern int smb2_setup_request(struct cifs_ses *ses, struct kvec *iov,
 			      unsigned int nvec, struct mid_q_entry **ret_mid);
 
+/*
+ *  SMB2 Worker functions - most of protocol specific implementation details
+ *  are contained within these calls
+ */
+extern int SMB2_negotiate(unsigned int xid, struct cifs_ses *ses);
+
 #endif			/* _SMB2PROTO_H */
-- 
1.7.1

  parent reply	other threads:[~2012-03-26  9:21 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-03-26  9:21 [PATCH 00/16] Get SMB2 mount work Pavel Shilovsky
     [not found] ` <1332753703-4315-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-03-26  9:21   ` [PATCH 01/16] CIFS: Introduce SMB2 Kconfig option Pavel Shilovsky
     [not found]     ` <1332753703-4315-2-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-05-06 12:25       ` Jeff Layton
2012-03-26  9:21   ` [PATCH 02/16] CIFS: Introduce SMB2 mounts as vers=2 Pavel Shilovsky
     [not found]     ` <1332753703-4315-3-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-05-06 12:31       ` Jeff Layton
     [not found]         ` <20120506083103.605e3dae-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
2012-05-06 12:37           ` Jeff Layton
2012-03-26  9:21   ` [PATCH 03/16] CIFS: Check for SMB2 vs CIFS in find_tcp_session Pavel Shilovsky
     [not found]     ` <1332753703-4315-4-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-05-06 14:01       ` Jeff Layton
     [not found]         ` <20120506100129.0b2f626b-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
2012-05-07  3:32           ` Steve French
     [not found]             ` <CAH2r5mvX4pfxR4B9TXYcSDOTn3cY0d+Be50zwZ+NhceDOR6vxQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-05-07 11:36               ` Jeff Layton
     [not found]                 ` <20120507073636.1d10a9ae-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
2012-05-07 12:52                   ` Steve French
     [not found]                     ` <CAH2r5mt7hxvaCzaUU0n96p9SVQ6Sso5p6JaYg0gwm6QA0SgHeg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-05-07 13:32                       ` Jeff Layton
     [not found]                         ` <20120507093233.04d13b0d-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
2012-05-07 13:34                           ` Steve French
     [not found]                             ` <CAH2r5msg8C8WMk_+4WYss_109EWec8v2R=vcH4BGmsGtb2tUQw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-05-07 13:36                               ` Steve French
     [not found]                                 ` <CAH2r5msOqC=jgX7m6GfKs_S7oMaxzC5rh+0_-ZGLYrVOJri=Vg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-05-07 13:51                                   ` Jeff Layton
2012-05-11 17:21           ` Jeff Layton
2012-03-26  9:21   ` [PATCH 04/16] CIFS: Add SMB2 status codes Pavel Shilovsky
     [not found]     ` <1332753703-4315-5-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-05-06 14:10       ` Jeff Layton
2012-03-26  9:21   ` [PATCH 06/16] CIFS: Make transport routines work with SMB2 Pavel Shilovsky
2012-03-26  9:21   ` [PATCH 07/16] CIFS: Add SMB2 credits support Pavel Shilovsky
2012-03-26  9:21   ` [PATCH 08/16] CIFS: Make demultiplex_thread work with SMB2 code Pavel Shilovsky
2012-03-26  9:21   ` [PATCH 09/16] CIFS: Respect SMB2 max hdr size for cifs_request kmem_cache Pavel Shilovsky
2012-03-26  9:21   ` Pavel Shilovsky [this message]
2012-03-26  9:21   ` [PATCH 11/16] CIFS: Add session setup/logoff capability for SMB2 Pavel Shilovsky
2012-03-26  9:21   ` [PATCH 12/16] CIFS: Add tree connect/disconnect " Pavel Shilovsky
2012-03-26  9:21   ` [PATCH 13/16] CIFS: Process reconnects for SMB2 shares Pavel Shilovsky
2012-03-26  9:21   ` [PATCH 14/16] CIFS: Add SMB2 support for is_path_accessible Pavel Shilovsky
2012-03-26  9:21   ` [PATCH 15/16] CIFS: Query SMB2 inode info Pavel Shilovsky
2012-03-26  9:21   ` [PATCH 16/16] CIFS: Get SMB2 mount work Pavel Shilovsky

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1332753703-4315-11-git-send-email-piastry@etersoft.ru \
    --to=piastry-7qunaywfiewox3rin2dayq@public.gmane.org \
    --cc=linux-cifs-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.