Commit 38d77c50 authored by Jeff Layton's avatar Jeff Layton Committed by Steve French
Browse files

cifs: track the enablement of signing in the TCP_Server_Info



Currently, we determine this according to flags in the sec_mode, flags
in the global_secflags and via other methods. That makes the semantics
very hard to follow and there are corner cases where we don't handle
this correctly.

Add a new bool to the TCP_Server_Info that acts as a simple flag to tell
us whether signing is enabled on this connection or not, and fix up the
places that need to determine this to use that flag.

This is a bit weird for the SMB2 case, where signing is per-session.
SMB2 needs work in this area already though. The existing SMB2 code has
similar logic to what we're using here, so there should be no real
change in behavior. These changes should make it easier to implement
per-session signing in the future though.

Signed-off-by: default avatarJeff Layton <jlayton@redhat.com>
Reviewed-by: default avatarPavel Shilovsky <piastry@etersoft.ru>
Signed-off-by: default avatarSteve French <smfrench@gmail.com>
parent 1e3cc57e
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -511,6 +511,7 @@ struct TCP_Server_Info {
	struct task_struct *tsk;
	struct task_struct *tsk;
	char server_GUID[16];
	char server_GUID[16];
	__u16 sec_mode;
	__u16 sec_mode;
	bool sign; /* is signing enabled on this connection? */
	bool session_estab; /* mark when very first sess is established */
	bool session_estab; /* mark when very first sess is established */
#ifdef CONFIG_CIFS_SMB2
#ifdef CONFIG_CIFS_SMB2
	int echo_credits;  /* echo reserved slots */
	int echo_credits;  /* echo reserved slots */
+1 −1
Original line number Original line Diff line number Diff line
@@ -212,7 +212,7 @@ extern int cifs_negotiate_protocol(const unsigned int xid,
				   struct cifs_ses *ses);
				   struct cifs_ses *ses);
extern int cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
extern int cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
			      struct nls_table *nls_info);
			      struct nls_table *nls_info);
extern int cifs_enable_signing(struct TCP_Server_Info *server, unsigned int secFlags);
extern int cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required);
extern int CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses);
extern int CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses);


extern int CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
extern int CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
+41 −35
Original line number Original line Diff line number Diff line
@@ -418,32 +418,43 @@ decode_ext_sec_blob(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
}
}


int
int
cifs_enable_signing(struct TCP_Server_Info *server, unsigned int secFlags)
cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
{
{
	if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
	bool srv_sign_required = server->sec_mode & SECMODE_SIGN_REQUIRED;
		/* MUST_SIGN already includes the MAY_SIGN FLAG
	bool srv_sign_enabled = server->sec_mode & SECMODE_SIGN_ENABLED;
		   so if this is zero it means that signing is disabled */
	bool mnt_sign_enabled = global_secflags & CIFSSEC_MAY_SIGN;
		cifs_dbg(FYI, "Signing disabled\n");

		if (server->sec_mode & SECMODE_SIGN_REQUIRED) {
	/*
			cifs_dbg(VFS, "Server requires packet signing to be enabled in /proc/fs/cifs/SecurityFlags\n");
	 * Is signing required by mnt options? If not then check
			return -EOPNOTSUPP;
	 * global_secflags to see if it is there.
	 */
	if (!mnt_sign_required)
		mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) ==
						CIFSSEC_MUST_SIGN);

	/*
	 * If signing is required then it's automatically enabled too,
	 * otherwise, check to see if the secflags allow it.
	 */
	mnt_sign_enabled = mnt_sign_required ? mnt_sign_required :
				(global_secflags & CIFSSEC_MAY_SIGN);

	/* If server requires signing, does client allow it? */
	if (srv_sign_required) {
		if (!mnt_sign_enabled) {
			cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!");
			return -ENOTSUPP;
		}
		}
		server->sec_mode &=
		server->sign = true;
			~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
	}
	} else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {

		/* signing required */
	/* If client requires signing, does server allow it? */
		cifs_dbg(FYI, "Must sign - secFlags 0x%x\n", secFlags);
	if (mnt_sign_required) {
		if ((server->sec_mode &
		if (!srv_sign_enabled) {
			(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
			cifs_dbg(VFS, "Server does not support signing!");
			cifs_dbg(VFS, "signing required but server lacks support\n");
			return -ENOTSUPP;
			return -EOPNOTSUPP;
		}
		} else
		server->sign = true;
			server->sec_mode |= SECMODE_SIGN_REQUIRED;
	} else {
		/* signing optional ie CIFSSEC_MAY_SIGN */
		if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0)
			server->sec_mode &=
				~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
	}
	}


	return 0;
	return 0;
@@ -685,7 +696,7 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)


signing_check:
signing_check:
	if (!rc)
	if (!rc)
		rc = cifs_enable_signing(server, secFlags);
		rc = cifs_enable_signing(server, ses->sign);
neg_err_exit:
neg_err_exit:
	cifs_buf_release(pSMB);
	cifs_buf_release(pSMB);


@@ -810,8 +821,7 @@ CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)


	pSMB->hdr.Mid = get_next_mid(ses->server);
	pSMB->hdr.Mid = get_next_mid(ses->server);


	if (ses->server->sec_mode &
	if (ses->server->sign)
		   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
		pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
		pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;


	pSMB->hdr.Uid = ses->Suid;
	pSMB->hdr.Uid = ses->Suid;
@@ -1573,8 +1583,7 @@ cifs_readv_callback(struct mid_q_entry *mid)
	switch (mid->mid_state) {
	switch (mid->mid_state) {
	case MID_RESPONSE_RECEIVED:
	case MID_RESPONSE_RECEIVED:
		/* result already set, check signature */
		/* result already set, check signature */
		if (server->sec_mode &
		if (server->sign) {
		    (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
			int rc = 0;
			int rc = 0;


			rc = cifs_verify_signature(&rqst, server,
			rc = cifs_verify_signature(&rqst, server,
@@ -4827,11 +4836,8 @@ getDFSRetry:
		strncpy(pSMB->RequestFileName, search_name, name_len);
		strncpy(pSMB->RequestFileName, search_name, name_len);
	}
	}


	if (ses->server) {
	if (ses->server && ses->server->sign)
		if (ses->server->sec_mode &
		   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
		pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
		pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
	}


	pSMB->hdr.Uid = ses->Suid;
	pSMB->hdr.Uid = ses->Suid;


+3 −9
Original line number Original line Diff line number Diff line
@@ -2037,12 +2037,7 @@ match_security(struct TCP_Server_Info *server, struct smb_vol *vol)
	}
	}


	/* now check if signing mode is acceptable */
	/* now check if signing mode is acceptable */
	if ((secFlags & CIFSSEC_MAY_SIGN) == 0 &&
	if (vol->sign && !server->sign)
	    (server->sec_mode & SECMODE_SIGN_REQUIRED))
			return false;
	else if (((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) &&
		 (server->sec_mode &
		  (SECMODE_SIGN_ENABLED|SECMODE_SIGN_REQUIRED)) == 0)
		return false;
		return false;


	return true;
	return true;
@@ -3704,8 +3699,7 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
		}
		}
	}
	}


	if (ses->server->sec_mode &
	if (ses->server->sign)
			(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
		smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
		smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;


	if (ses->capabilities & CAP_STATUS32) {
	if (ses->capabilities & CAP_STATUS32) {
+1 −2
Original line number Original line Diff line number Diff line
@@ -267,8 +267,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
		if (treeCon->nocase)
		if (treeCon->nocase)
			buffer->Flags  |= SMBFLG_CASELESS;
			buffer->Flags  |= SMBFLG_CASELESS;
		if ((treeCon->ses) && (treeCon->ses->server))
		if ((treeCon->ses) && (treeCon->ses->server))
			if (treeCon->ses->server->sec_mode &
			if (treeCon->ses->server->sign)
			  (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
				buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
				buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
	}
	}


Loading