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

Jeff Layton <[email protected]>
Newsgroups gmane.linux.file-systems.cifs
Message-ID <[email protected]>
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 <[email protected]>
---
 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(-)

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);
-- 
1.6.6.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.