Patchwork [09/11] cifs: allow mixed secTypes on a socket

login
register
mail settings
Submitter Jeff Layton
Date April 17, 2010, 2:05 a.m.
Message ID <1271469958-4894-10-git-send-email-jlayton@redhat.com>
Download mbox | patch
Permalink /patch/50372/
State New
Headers show

Comments

Jeff Layton - April 17, 2010, 2:05 a.m.
Allow secType to be set on a per-session basis. This allows us to mix
secTypes on a single socket. Also, add a "sign" bool to cifsSesInfo
and determine whether signing should be enabled at session setup
time.

Try to clarify the code that makes decisions about what sectype to
use by using a securityEnum in the volume info instead of a set of
flags.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/cifs/cifsglob.h  |   12 ++-
 fs/cifs/cifspdu.h   |    2 +
 fs/cifs/cifssmb.c   |  128 ++------------------------------
 fs/cifs/connect.c   |  202 ++++++++++++++++++++++++++++++++++++++++++++-------
 fs/cifs/file.c      |   12 +--
 fs/cifs/misc.c      |    6 +-
 fs/cifs/sess.c      |   34 +++++----
 fs/cifs/transport.c |   12 +--
 8 files changed, 218 insertions(+), 190 deletions(-)

Patch

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 4a99487..1ececf4 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -80,12 +80,13 @@  enum statusEnum {
 };
 
 enum securityEnum {
-	PLAINTXT = 0, 		/* Legacy with Plaintext passwords */
+	Undefined = 0,		/* Uninitialized */
+	Anonymous,		/* Anonymous login */
+	Plaintext, 		/* Legacy with plaintext passwords */
 	LANMAN,			/* Legacy LANMAN auth */
 	NTLM,			/* Legacy NTLM012 auth with NTLM hash */
 	NTLMv2,			/* Legacy NTLM auth with NTLMv2 hash */
-	RawNTLMSSP,		/* NTLMSSP without SPNEGO, NTLMv2 hash */
-/*	NTLMSSP, */ /* can use rawNTLMSSP instead of NTLMSSP via SPNEGO */
+	NTLMSSP,		/* NTLMSSP, NTLMv1 hash */
 	Kerberos,		/* Kerberos via SPNEGO */
 };
 
@@ -160,7 +161,6 @@  struct TCP_Server_Info {
 	struct task_struct *tsk;
 	char server_GUID[16];
 	char secMode;
-	enum securityEnum secType;
 	unsigned int maxReq;	/* Clients should submit no more */
 	/* than maxReq distinct unanswered SMBs to the server when using  */
 	/* multiplexed reads or writes */
@@ -186,6 +186,7 @@  struct TCP_Server_Info {
 	unsigned long lstrp; /* when we got last response from this server */
 	u16 dialect; /* dialect index that server chose */
 	/* extended security flavors that server supports */
+	bool	ext_security;		/* extended security should be used */
 	bool	sec_kerberos;		/* supports plain Kerberos */
 	bool	sec_mskerberos;		/* supports legacy MS Kerberos */
 	bool	sec_kerberosu2u;	/* supports U2U Kerberos */
@@ -218,7 +219,7 @@  struct cifsSesInfo {
 	struct TCP_Server_Info *server;	/* pointer to server info */
 	int ses_count;		/* reference counter */
 	enum statusEnum status;
-	unsigned overrideSecFlg;  /* if non-zero override global sec flags */
+	enum securityEnum secType;
 	__u16 ipc_tid;		/* special tid for connection to IPC share */
 	__u16 flags;
 	__u16 vcnum;
@@ -233,6 +234,7 @@  struct cifsSesInfo {
 	char userName[MAX_USERNAME_SIZE + 1];
 	char *domainName;
 	char *password;
+	bool sign:1;		/* packet signing enabled */
 	bool need_reconnect:1; /* connection reset, uid now invalid */
 };
 /* no more than one of the following three session flags may be set */
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 14d036d..d72960c 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -530,6 +530,8 @@  typedef struct negotiate_rsp {
 #define SECMODE_SIGN_ENABLED  0x04	/* SMB security signatures enabled */
 #define SECMODE_SIGN_REQUIRED 0x08	/* SMB security signatures required */
 
+#define SECMODE_SIGN	(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)
+
 /* Negotiate response Capabilities */
 #define CAP_RAW_MODE           0x00000001
 #define CAP_MPX_MODE           0x00000002
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 95510ce..2af0ba4 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -353,46 +353,18 @@  CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
 	int rc = 0;
 	int bytes_returned;
 	int i;
-	struct TCP_Server_Info *server;
+	struct TCP_Server_Info *server = ses->server;
 	u16 count;
-	unsigned int secFlags;
 
-	if (ses->server)
-		server = ses->server;
-	else {
-		rc = -EIO;
-		return rc;
-	}
 	rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
 		      (void **) &pSMB, (void **) &pSMBr);
 	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)))
-		secFlags = ses->overrideSecFlg;  /* BB FIXME fix sign flags? */
-	else /* if override flags set only sign/seal OR them with global auth */
-		secFlags = global_secflags | ses->overrideSecFlg;
-
-	cFYI(1, ("secFlags 0x%x", secFlags));
-
 	pSMB->hdr.Mid = GetNextMid(server);
-	pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
-
-	if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
-		pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
-	else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
-		cFYI(1, ("Kerberos only mechanism, enable extended security"));
+	pSMB->hdr.Flags2 |= SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS;
+	if (server->ext_security)
 		pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
-	}
-#ifdef CONFIG_CIFS_EXPERIMENTAL
-	else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
-		pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
-	else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
-		cFYI(1, ("NTLMSSP only mechanism, enable extended security"));
-		pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
-	}
-#endif
 
 	count = 0;
 	for (i = 0; i < CIFS_NUM_PROT; i++) {
@@ -424,15 +396,6 @@  CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
 		__s16 tmp;
 		struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
 
-		if ((secFlags & CIFSSEC_MAY_LANMAN) ||
-			(secFlags & CIFSSEC_MAY_PLNTXT))
-			server->secType = LANMAN;
-		else {
-			cERROR(1, ("mount failed weak security disabled"
-				   " in /proc/fs/cifs/SecurityFlags"));
-			rc = -EOPNOTSUPP;
-			goto neg_err_exit;
-		}
 		server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
 		server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
 		server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
@@ -496,7 +459,7 @@  CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
 		cFYI(1, ("LANMAN negotiated"));
 		/* we will not end up setting signing flags - as no signing
 		was in LANMAN and server did not return the flags on */
-		goto signing_check;
+		goto neg_err_exit;
 #else /* weak security disabled */
 	} else if (pSMBr->hdr.WordCount == 13) {
 		cERROR(1, ("mount failed, cifs module not built "
@@ -514,36 +477,6 @@  CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
 	if ((server->secMode & SECMODE_USER) == 0)
 		cFYI(1, ("share mode security"));
 
-	if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
-#ifdef CONFIG_CIFS_WEAK_PW_HASH
-		if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
-#endif /* CIFS_WEAK_PW_HASH */
-			cERROR(1, ("Server requests plain text password"
-				  " but client support disabled"));
-
-	if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
-		server->secType = NTLMv2;
-	else if (secFlags & CIFSSEC_MAY_NTLM)
-		server->secType = NTLM;
-	else if (secFlags & CIFSSEC_MAY_NTLMV2)
-		server->secType = NTLMv2;
-	else if (secFlags & CIFSSEC_MAY_KRB5)
-		server->secType = Kerberos;
-	else if (secFlags & CIFSSEC_MAY_NTLMSSP)
-		server->secType = RawNTLMSSP;
-	else if (secFlags & CIFSSEC_MAY_LANMAN)
-		server->secType = LANMAN;
-/* #ifdef CONFIG_CIFS_EXPERIMENTAL
-	else if (secFlags & CIFSSEC_MAY_PLNTXT)
-		server->secType = ??
-#endif */
-	else {
-		rc = -EOPNOTSUPP;
-		cERROR(1, ("Invalid security type"));
-		goto neg_err_exit;
-	}
-	/* else ... any others ...? */
-
 	/* one byte, so no need to convert this or EncryptionKeyLen from
 	   little endian */
 	server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
@@ -594,7 +527,7 @@  CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
 		}
 
 		if (count == 16) {
-			server->secType = RawNTLMSSP;
+			ses->secType = NTLMSSP;
 		} else {
 			rc = decode_negTokenInit(pSMBr->u.extended_response.
 						 SecurityBlob, count - 16,
@@ -603,49 +536,10 @@  CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
 				rc = 0;
 			else
 				rc = -EINVAL;
-
-			if (server->sec_kerberos || server->sec_mskerberos)
-				server->secType = Kerberos;
-			else if (server->sec_ntlmssp)
-				server->secType = RawNTLMSSP;
-			else
-				rc = -EOPNOTSUPP;
 		}
 	} else
 		server->capabilities &= ~CAP_EXTENDED_SECURITY;
 
-#ifdef CONFIG_CIFS_WEAK_PW_HASH
-signing_check:
-#endif
-	if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
-		/* MUST_SIGN already includes the MAY_SIGN FLAG
-		   so if this is zero it means that signing is disabled */
-		cFYI(1, ("Signing disabled"));
-		if (server->secMode & SECMODE_SIGN_REQUIRED) {
-			cERROR(1, ("Server requires "
-				   "packet signing to be enabled in "
-				   "/proc/fs/cifs/SecurityFlags."));
-			rc = -EOPNOTSUPP;
-		}
-		server->secMode &=
-			~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
-	} else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
-		/* signing required */
-		cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
-		if ((server->secMode &
-			(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
-			cERROR(1,
-				("signing required but server lacks support"));
-			rc = -EOPNOTSUPP;
-		} else
-			server->secMode |= SECMODE_SIGN_REQUIRED;
-	} else {
-		/* signing optional ie CIFSSEC_MAY_SIGN */
-		if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
-			server->secMode &=
-				~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
-	}
-
 neg_err_exit:
 	cifs_buf_release(pSMB);
 
@@ -719,9 +613,8 @@  CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
 
 	pSMB->hdr.Mid = GetNextMid(ses->server);
 
-	if (ses->server->secMode &
-		   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-			pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+	if (ses->sign)
+		pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
 	pSMB->hdr.Uid = ses->Suid;
 
@@ -4159,11 +4052,8 @@  getDFSRetry:
 		strncpy(pSMB->RequestFileName, searchName, name_len);
 	}
 
-	if (ses->server) {
-		if (ses->server->secMode &
-		   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-			pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
-	}
+	if (ses->sign)
+		pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
 	pSMB->hdr.Uid = ses->Suid;
 
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index a7ad9df..2e70071 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -70,7 +70,7 @@  struct smb_vol {
 	gid_t linux_gid;
 	mode_t file_mode;
 	mode_t dir_mode;
-	unsigned secFlg;
+	enum securityEnum sectype;
 	bool retry:1;
 	bool intr:1;
 	bool setuids:1;
@@ -87,10 +87,10 @@  struct smb_vol {
 	bool posix_paths:1; /* unset to not ask for posix pathnames. */
 	bool no_linux_ext:1;
 	bool sfu_emul:1;
-	bool nullauth:1;   /* attempt to authenticate with null user */
 	bool nocase:1;     /* request case insensitive filenames */
 	bool nobrl:1;      /* disable sending byte range locks to srv */
 	bool mand_lock:1;  /* send mandatory not posix byte range lock reqs */
+	bool sign:1;
 	bool seal:1;       /* request transport encryption on share */
 	bool nodfs:1;      /* Do not request DFS, even if available */
 	bool local_lease:1; /* check leases only on local system, not remote */
@@ -872,7 +872,7 @@  cifs_parse_mount_options(char *options, const char *devname,
 				return 1;	/* needs_arg; */
 			} else if (!*value) {
 				/* null user, ie anonymous, authentication */
-				vol->nullauth = 1;
+				vol->sectype = Anonymous;
 			}
 			if (strnlen(value, 200) < 200) {
 				vol->username = value;
@@ -978,42 +978,39 @@  cifs_parse_mount_options(char *options, const char *devname,
 				cERROR(1, ("no security value specified"));
 				continue;
 			} else if (strnicmp(value, "krb5i", 5) == 0) {
-				vol->secFlg |= CIFSSEC_MAY_KRB5 |
-					CIFSSEC_MUST_SIGN;
+				vol->sectype = Kerberos;
+				vol->sign = true;
 			} else if (strnicmp(value, "krb5p", 5) == 0) {
-				/* vol->secFlg |= CIFSSEC_MUST_SEAL |
-					CIFSSEC_MAY_KRB5; */
 				cERROR(1, ("Krb5 cifs privacy not supported"));
 				return 1;
 			} else if (strnicmp(value, "krb5", 4) == 0) {
-				vol->secFlg |= CIFSSEC_MAY_KRB5;
+				vol->sectype = Kerberos;
 #ifdef CONFIG_CIFS_EXPERIMENTAL
 			} else if (strnicmp(value, "ntlmsspi", 8) == 0) {
-				vol->secFlg |= CIFSSEC_MAY_NTLMSSP |
-					CIFSSEC_MUST_SIGN;
+				vol->sectype = NTLMSSP;
+				vol->sign = true;
 			} else if (strnicmp(value, "ntlmssp", 7) == 0) {
-				vol->secFlg |= CIFSSEC_MAY_NTLMSSP;
+				vol->sectype = NTLMSSP;
 #endif
 			} else if (strnicmp(value, "ntlmv2i", 7) == 0) {
-				vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
-					CIFSSEC_MUST_SIGN;
+				vol->sectype = NTLMv2;
+				vol->sign = true;
 			} else if (strnicmp(value, "ntlmv2", 6) == 0) {
-				vol->secFlg |= CIFSSEC_MAY_NTLMV2;
+				vol->sectype = NTLMv2;
 			} else if (strnicmp(value, "ntlmi", 5) == 0) {
-				vol->secFlg |= CIFSSEC_MAY_NTLM |
-					CIFSSEC_MUST_SIGN;
+				vol->sectype = NTLM;
+				vol->sign = true;
 			} else if (strnicmp(value, "ntlm", 4) == 0) {
-				/* ntlm is default so can be turned off too */
-				vol->secFlg |= CIFSSEC_MAY_NTLM;
+				vol->sectype = NTLM;
 			} else if (strnicmp(value, "nontlm", 6) == 0) {
 				/* BB is there a better way to do this? */
-				vol->secFlg |= CIFSSEC_MAY_NTLMV2;
+				vol->sectype = NTLMv2;
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
 			} else if (strnicmp(value, "lanman", 6) == 0) {
-				vol->secFlg |= CIFSSEC_MAY_LANMAN;
+				vol->sectype = LANMAN;
 #endif
 			} else if (strnicmp(value, "none", 4) == 0) {
-				vol->nullauth = 1;
+				vol->sectype = Anonymous;
 			} else {
 				cERROR(1, ("bad security option: %s", value));
 				return 1;
@@ -1316,12 +1313,11 @@  cifs_parse_mount_options(char *options, const char *devname,
 			vol->local_lease = 1;
 #endif
 		} else if (strnicmp(data, "sign", 4) == 0) {
-			vol->secFlg |= CIFSSEC_MUST_SIGN;
+			vol->sign = 1;
 		} else if (strnicmp(data, "seal", 4) == 0) {
 			/* we do not do the following in secFlags because seal
 			   is a per tree connection (mount) not a per socket
 			   or per-smb connection option in the protocol */
-			/* vol->secFlg |= CIFSSEC_MUST_SEAL; */
 			vol->seal = 1;
 		} else if (strnicmp(data, "direct", 6) == 0) {
 			vol->direct_io = 1;
@@ -1380,6 +1376,150 @@  cifs_parse_mount_options(char *options, const char *devname,
 	return 0;
 }
 
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+static enum securityEnum
+check_lanman(void)
+{
+	/* only allow if secflags say it's ok */
+	if (global_secflags & (CIFSSEC_MAY_LANMAN|CIFSSEC_MAY_PLNTXT))
+		return LANMAN;
+
+	return Undefined;
+}
+
+static bool
+check_plaintext(struct TCP_Server_Info *server) {
+	if (server->secMode & SECMODE_PW_ENCRYPT)
+		return true;
+	if (global_secflags & CIFSSEC_MAY_PLNTXT)
+		return true;
+	cERROR(1, ("Server requested plaintext password, but support is "
+		   "disabled in /proc/fs/cifs/SecurityFlags"));
+	return false;
+}
+#else /* CONFIG_CIFS_WEAK_PW_HASH */
+static enum securityEnum
+check_lanman(void)
+{
+	return Undefined;
+}
+
+static bool
+check_plaintext(struct TCP_Server_Info *server) {
+	return false;
+}
+#endif /* CONFIG_CIFS_WEAK_PW_HASH */
+
+static bool
+use_extended_security(struct smb_vol *vol)
+{
+	if (vol->sectype == Kerberos || vol->sectype == NTLMSSP)
+		return true;
+	return false;
+}
+
+/* decide whether session has signing enabled */
+static int
+set_ses_signing(struct cifsSesInfo *ses, struct smb_vol *vol)
+{
+	/* no signing on anonymous login */
+	if (ses->secType == Anonymous) {
+		ses->sign = false;
+	} else if (vol->sign || global_secflags & SECMODE_SIGN_REQUIRED) {
+		if (ses->server->secMode & SECMODE_SIGN) {
+			ses->sign = true;
+		} else {
+			cERROR(1, ("mount options specify signing, but server "
+				   "does not support it."));
+			return -EINVAL;
+		}
+	} else if (global_secflags & SECMODE_SIGN) {
+		if (ses->server->secMode & SECMODE_SIGN_REQUIRED)
+			ses->sign = true;
+	} else if (ses->server->secMode & SECMODE_SIGN_REQUIRED) {
+		cERROR(1, ("server requires signing, but client has it"
+			   "disabled in /proc/fs/cifs/SecurityFlags"));
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * determine the security type to use for session
+ *
+ * The decision is based on several inputs:
+ *
+ * 1) the global security flags (/proc/fs/cifs/SecurityFlags)
+ * 2) mount options (vol->sectype)
+ * 3) what the server actually supports (several fields in TCP_Server_Info)
+ *
+ * ...this is far more complicated than it ought to be, but we're saddled
+ * with legacy interfaces (SecurityFlags in particular).
+ */
+static enum securityEnum
+smb_ses_sectype(struct cifsSesInfo *ses, struct smb_vol *vol)
+{
+	struct TCP_Server_Info *server = ses->server;
+	enum securityEnum type;
+
+	/* don't change an existing session */
+	if (ses->secType != Undefined)
+		return ses->secType;
+
+	switch(vol->sectype) {
+	case Undefined:
+		break;
+	case Anonymous:
+	case NTLMSSP:
+	case NTLMv2:
+	case NTLM:
+	case LANMAN:
+		return vol->sectype;
+	case Kerberos:
+		if (server->sec_kerberos || server->sec_mskerberos)
+			return Kerberos;
+		cERROR(1, ("Server doesn't support kerberos auth."));
+		return Undefined;
+	default:
+		cERROR(1, ("Unknown secType=%d", vol->sectype));
+		return Undefined;
+	}
+
+	/*
+	 * no sec= option, determine based on global_secflags and what the
+	 * server supports.
+	 */
+
+	/*
+	 * extended security requires either krb5 or NTLMSSP. krb5 auth must
+	 * be specified in mount opts. That leaves NTLMSSP if it wasn't.
+	 */
+	if (server->capabilities & CAP_EXTENDED_SECURITY)
+		return NTLMSSP;
+
+	/* check for lanman first if server dialect is ancient */
+	if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT) {
+		type = check_lanman();
+		if (type != Undefined && !check_plaintext(server))
+			return Undefined;
+	}
+
+	if (type != Undefined)
+		return type;
+
+	if (global_secflags & CIFSSEC_MUST_NTLMV2)
+		return NTLMv2;
+	if (global_secflags & CIFSSEC_MAY_NTLM)
+		return NTLM;
+	if (global_secflags & CIFSSEC_MAY_NTLMV2)
+		return NTLMv2;
+	if (global_secflags & CIFSSEC_MAY_LANMAN)
+		return LANMAN;
+
+	return Undefined;
+}
+
 static struct TCP_Server_Info *
 cifs_find_tcp_session(struct sockaddr_storage *addr, unsigned short int port)
 {
@@ -1531,6 +1671,7 @@  cifs_get_tcp_session(struct smb_vol *volume_info)
 	tcp_ses->sequence_number = 0;
 	INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
 	INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
+	tcp_ses->ext_security = use_extended_security(volume_info);
 
 	/*
 	 * at this point we are the only ones with the pointer
@@ -1708,10 +1849,16 @@  cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
 			strcpy(ses->domainName, volume_info->domainname);
 	}
 	ses->linux_uid = volume_info->linux_uid;
-	ses->overrideSecFlg = volume_info->secFlg;
 
 	mutex_lock(&ses->session_mutex);
 	rc = cifs_negotiate_protocol(xid, ses);
+	if (!rc) {
+		ses->secType = smb_ses_sectype(ses, volume_info);
+		if (ses->secType == Undefined)
+			rc = -EOPNOTSUPP;
+	}
+	if (!rc)
+		rc = set_ses_signing(ses, volume_info);
 	if (!rc)
 		rc = cifs_setup_session(xid, ses, volume_info->local_nls);
 	mutex_unlock(&ses->session_mutex);
@@ -2516,7 +2663,7 @@  try_mount_again:
 		goto out;
 	}
 
-	if (volume_info->nullauth) {
+	if (volume_info->sectype == Anonymous) {
 		cFYI(1, ("null user"));
 		volume_info->username = "";
 	} else if (volume_info->username) {
@@ -2763,7 +2910,7 @@  CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
 		   NTLMv2 password here) */
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
 		if ((global_secflags & CIFSSEC_MAY_LANMAN) &&
-		    (ses->server->secType == LANMAN))
+		    (ses->secType == LANMAN))
 			calc_lanman_hash(tcon->password, ses->server->cryptKey,
 					 ses->server->secMode &
 					    SECMODE_PW_ENCRYPT ? true : false,
@@ -2781,8 +2928,7 @@  CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
 		}
 	}
 
-	if (ses->server->secMode &
-			(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+	if (ses->sign)
 		smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
 	if (ses->capabilities & CAP_STATUS32) {
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 9b11a8f..031ccae 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1130,10 +1130,7 @@  static ssize_t cifs_write(struct file *file, const char *write_data,
 				if (rc != 0)
 					break;
 			}
-			if (experimEnabled || (pTcon->ses->server &&
-				((pTcon->ses->server->secMode &
-				(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-				== 0))) {
+			if (experimEnabled || !pTcon->ses->sign) {
 				struct kvec iov[2];
 				unsigned int len;
 
@@ -1395,11 +1392,8 @@  static int cifs_writepages(struct address_space *mapping,
 	if (cifs_sb->wsize < PAGE_CACHE_SIZE)
 		return generic_writepages(mapping, wbc);
 
-	if ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
-		if (cifs_sb->tcon->ses->server->secMode &
-				(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-			if (!experimEnabled)
-				return generic_writepages(mapping, wbc);
+	if (cifs_sb->tcon->ses->sign && !experimEnabled)
+		return generic_writepages(mapping, wbc);
 
 	iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
 	if (iov == NULL)
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index d147499..7b783d1 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -369,10 +369,8 @@  header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
 			buffer->Flags2 |= SMBFLG2_DFS;
 		if (treeCon->nocase)
 			buffer->Flags  |= SMBFLG_CASELESS;
-		if ((treeCon->ses) && (treeCon->ses->server))
-			if (treeCon->ses->server->secMode &
-			  (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-				buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+		if (treeCon->ses->sign)
+			buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 	}
 
 /*  endian conversion of flags is now done just before sending */
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index 1acfc27..184e359 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -139,8 +139,7 @@  static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
 	capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
 			CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
 
-	if (ses->server->secMode &
-	    (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+	if (ses->sign)
 		pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
 	if (ses->capabilities & CAP_UNICODE) {
@@ -222,7 +221,7 @@  static void unicode_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses,
 		bcc_ptr++;
 	} */
 	/* copy user */
-	if (ses->userName == NULL) {
+	if (ses->secType == Anonymous) {
 		/* null user mount */
 		*bcc_ptr = 0;
 		*(bcc_ptr+1) = 0;
@@ -426,8 +425,7 @@  static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
 	flags = NTLMSSP_NEGOTIATE_56 |	NTLMSSP_REQUEST_TARGET |
 		NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
 		NTLMSSP_NEGOTIATE_NT_ONLY | NTLMSSP_NEGOTIATE_NTLM;
-	if (ses->server->secMode &
-	   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+	if (ses->sign)
 		flags |= NTLMSSP_NEGOTIATE_SIGN;
 	if (ses->server->secMode & SECMODE_SIGN_REQUIRED)
 		flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
@@ -463,8 +461,7 @@  static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
 		NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO |
 		NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
 		NTLMSSP_NEGOTIATE_NT_ONLY | NTLMSSP_NEGOTIATE_NTLM;
-	if (ses->server->secMode &
-	   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+	if (ses->sign)
 		flags |= NTLMSSP_NEGOTIATE_SIGN;
 	if (ses->server->secMode & SECMODE_SIGN_REQUIRED)
 		flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
@@ -588,14 +585,15 @@  CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
 	first_time = is_first_ses_reconnect(ses);
 	read_unlock(&cifs_tcp_ses_lock);
 
-	type = ses->server->secType;
+	type = ses->secType;
 
 	cFYI(1, ("sess setup type %d", type));
 ssetup_ntlmssp_authenticate:
 	if (phase == NtLmChallenge)
 		phase = NtLmAuthenticate; /* if ntlmssp, now final phase */
 
-	if (type == LANMAN) {
+	switch(type) {
+	case LANMAN:
 #ifndef CONFIG_CIFS_WEAK_PW_HASH
 		/* LANMAN and plaintext are less secure and off by default.
 		So we make this explicitly be turned on in kconfig (in the
@@ -605,11 +603,15 @@  ssetup_ntlmssp_authenticate:
 		return -EOPNOTSUPP;
 #endif
 		wct = 10; /* lanman 2 style sessionsetup */
-	} else if ((type == NTLM) || (type == NTLMv2)) {
-		/* For NTLMv2 failures eventually may need to retry NTLM */
-		wct = 13; /* old style NTLM sessionsetup */
-	} else /* same size: negotiate or auth, NTLMSSP or extended security */
+		break;
+	case NTLM:
+	case NTLMv2:
+	case Anonymous:
+		wct = 13;
+		break;
+	default:
 		wct = 12;
+	}
 
 	rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses,
 			    (void **)&smb_buf);
@@ -675,7 +677,7 @@  ssetup_ntlmssp_authenticate:
 		/* Unicode not allowed for LANMAN dialects */
 		ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
 #endif
-	} else if (type == NTLM) {
+	} else if (type == NTLM || type == Anonymous) {
 		char ntlm_session_key[CIFS_SESS_KEY_SIZE];
 
 		pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
@@ -809,7 +811,7 @@  ssetup_ntlmssp_authenticate:
 #endif /* CONFIG_CIFS_UPCALL */
 	} else {
 #ifdef CONFIG_CIFS_EXPERIMENTAL
-		if (type == RawNTLMSSP) {
+		if (type == NTLMSSP) {
 			if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) {
 				cERROR(1, ("NTLMSSP requires Unicode support"));
 				rc = -ENOSYS;
@@ -874,7 +876,7 @@  ssetup_ntlmssp_authenticate:
 	pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base;
 	smb_buf = (struct smb_hdr *)iov[0].iov_base;
 
-	if ((type == RawNTLMSSP) && (smb_buf->Status.CifsError ==
+	if ((type == NTLMSSP) && (smb_buf->Status.CifsError ==
 			cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))) {
 		if (phase != NtLmNegotiate) {
 			cERROR(1, ("Unexpected more processing error"));
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index ad081fe..4ccf5c1 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -541,9 +541,7 @@  SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
 
 		dump_smb(midQ->resp_buf, 80);
 		/* convert the length into a more usable form */
-		if ((receive_len > 24) &&
-		    (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
-					     SECMODE_SIGN_ENABLED))) {
+		if (receive_len > 24 && ses->sign) {
 			rc = cifs_verify_signature(midQ->resp_buf,
 						&ses->server->mac_signing_key,
 						midQ->sequence_number+1);
@@ -729,9 +727,7 @@  SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
 
 		dump_smb(out_buf, 92);
 		/* convert the length into a more usable form */
-		if ((receive_len > 24) &&
-		    (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
-					     SECMODE_SIGN_ENABLED))) {
+		if (receive_len > 24 && ses->sign) {
 			rc = cifs_verify_signature(out_buf,
 						&ses->server->mac_signing_key,
 						midQ->sequence_number+1);
@@ -979,9 +975,7 @@  SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
 
 	dump_smb(out_buf, 92);
 	/* convert the length into a more usable form */
-	if ((receive_len > 24) &&
-	    (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
-				     SECMODE_SIGN_ENABLED))) {
+	if (receive_len > 24 && ses->sign) {
 		rc = cifs_verify_signature(out_buf,
 					   &ses->server->mac_signing_key,
 					   midQ->sequence_number+1);