Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3f618223 authored by Jeff Layton's avatar Jeff Layton Committed by Steve French
Browse files

move sectype to the cifs_ses instead of TCP_Server_Info



Now that we track what sort of NEGOTIATE response was received, stop
mandating that every session on a socket use the same type of auth.

Push that decision out into the session setup code, and make the sectype
a per-session property. This should allow us to mix multiple sectypes on
a socket as long as they are compatible with the NEGOTIATE response.

With this too, we can now eliminate the ses->secFlg field since that
info is redundant and harder to work with than a securityEnum.

Signed-off-by: default avatarJeff Layton <jlayton@redhat.com>
Acked-by: default avatarPavel Shilovsky <piastry@etersoft.ru>
Signed-off-by: default avatarSteve French <smfrench@gmail.com>
parent 38d77c50
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -535,7 +535,7 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
		return rc;
	}

	if (ses->server->secType == RawNTLMSSP)
	if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED)
		memcpy(ses->auth_key.response + offset,
			ses->ntlmssp->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
	else
@@ -567,7 +567,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
	char ntlmv2_hash[16];
	unsigned char *tiblob = NULL; /* target info blob */

	if (ses->server->secType == RawNTLMSSP) {
	if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED) {
		if (!ses->domainName) {
			rc = find_domain_name(ses, nls_cp);
			if (rc) {
+0 −2
Original line number Diff line number Diff line
@@ -401,7 +401,6 @@ struct smb_vol {
	kgid_t backupgid;
	umode_t file_mode;
	umode_t dir_mode;
	unsigned secFlg;
	enum securityEnum sectype; /* sectype requested via mnt opts */
	bool sign; /* was signing requested via mnt opts? */
	bool retry:1;
@@ -519,7 +518,6 @@ struct TCP_Server_Info {
	bool echoes:1; /* enable echoes */
#endif
	u16 dialect; /* dialect index that server chose */
	enum securityEnum secType;
	bool oplocks:1; /* enable oplocks */
	unsigned int maxReq;	/* Clients should submit no more */
	/* than maxReq distinct unanswered SMBs to the server when using  */
+2 −0
Original line number Diff line number Diff line
@@ -118,6 +118,8 @@ extern void header_assemble(struct smb_hdr *, char /* command */ ,
extern int small_smb_init_no_tc(const int smb_cmd, const int wct,
				struct cifs_ses *ses,
				void **request_buf);
extern enum securityEnum select_sectype(struct TCP_Server_Info *server,
				enum securityEnum requested);
extern int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
			  const struct nls_table *nls_cp);
extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601);
+20 −72
Original line number Diff line number Diff line
@@ -368,11 +368,12 @@ static int validate_t2(struct smb_t2_rsp *pSMB)
}

static int
decode_ext_sec_blob(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
{
	int	rc = 0;
	u16	count;
	char	*guid = pSMBr->u.extended_response.GUID;
	struct TCP_Server_Info *server = ses->server;

	count = get_bcc(&pSMBr->hdr);
	if (count < SMB1_CLIENT_GUID_SIZE)
@@ -391,27 +392,13 @@ decode_ext_sec_blob(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
	}

	if (count == SMB1_CLIENT_GUID_SIZE) {
		server->secType = RawNTLMSSP;
		server->sec_ntlmssp = true;
	} else {
		count -= SMB1_CLIENT_GUID_SIZE;
		rc = decode_negTokenInit(
			pSMBr->u.extended_response.SecurityBlob, count, server);
		if (rc != 1)
			return -EINVAL;

		/* Make sure server supports what we want to use */
		switch(server->secType) {
		case Kerberos:
			if (!server->sec_kerberos && !server->sec_mskerberos)
				return -EOPNOTSUPP;
			break;
		case RawNTLMSSP:
			if (!server->sec_ntlmssp)
				return -EOPNOTSUPP;
			break;
		default:
			return -EOPNOTSUPP;
		}
	}

	return 0;
@@ -462,8 +449,7 @@ cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)

#ifdef CONFIG_CIFS_WEAK_PW_HASH
static int
decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr,
			  unsigned int secFlags)
decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
{
	__s16 tmp;
	struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
@@ -471,12 +457,6 @@ decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr,
	if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT)
		return -EOPNOTSUPP;

	if ((secFlags & CIFSSEC_MAY_LANMAN) || (secFlags & CIFSSEC_MAY_PLNTXT))
		server->secType = LANMAN;
	else {
		cifs_dbg(VFS, "mount failed weak security disabled in /proc/fs/cifs/SecurityFlags\n");
		return -EOPNOTSUPP;
	}
	server->sec_mode = le16_to_cpu(rsp->SecurityMode);
	server->maxReq = min_t(unsigned int,
			       le16_to_cpu(rsp->MaxMpxCount),
@@ -542,8 +522,7 @@ decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr,
}
#else
static inline int
decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr,
			  unsigned int secFlags)
decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
{
	cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
	return -EOPNOTSUPP;
@@ -551,18 +530,21 @@ decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr,
#endif

static bool
should_set_ext_sec_flag(unsigned int secFlags)
should_set_ext_sec_flag(enum securityEnum sectype)
{
	if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
		return true;
	else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5)
		return true;
	else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
	switch (sectype) {
	case RawNTLMSSP:
	case Kerberos:
		return true;
	else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP)
	case Unspecified:
		if (global_secflags &
		    (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP))
			return true;
		/* Fallthrough */
	default:
		return false;
	}
}

int
CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
@@ -574,7 +556,6 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
	int i;
	struct TCP_Server_Info *server = ses->server;
	u16 count;
	unsigned int secFlags;

	if (!server) {
		WARN(1, "%s: server is NULL!\n", __func__);
@@ -586,18 +567,10 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
	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;

	cifs_dbg(FYI, "secFlags 0x%x\n", secFlags);

	pSMB->hdr.Mid = get_next_mid(server);
	pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);

	if (should_set_ext_sec_flag(secFlags)) {
	if (should_set_ext_sec_flag(ses->sectype)) {
		cifs_dbg(FYI, "Requesting extended security.");
		pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
	}
@@ -627,7 +600,7 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
		goto neg_err_exit;
	} else if (pSMBr->hdr.WordCount == 13) {
		server->negflavor = CIFS_NEGFLAVOR_LANMAN;
		rc = decode_lanman_negprot_rsp(server, pSMBr, secFlags);
		rc = decode_lanman_negprot_rsp(server, pSMBr);
		goto signing_check;
	} else if (pSMBr->hdr.WordCount != 17) {
		/* unknown wct */
@@ -640,31 +613,6 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
	if ((server->sec_mode & SECMODE_USER) == 0)
		cifs_dbg(FYI, "share mode security\n");

	if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
#ifdef CONFIG_CIFS_WEAK_PW_HASH
		if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
#endif /* CIFS_WEAK_PW_HASH */
			cifs_dbg(VFS, "Server requests plain text password but client support disabled\n");

	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;
	else {
		rc = -EOPNOTSUPP;
		cifs_dbg(VFS, "Invalid security type\n");
		goto neg_err_exit;
	}
	/* else ... any others ...? */

	/* one byte, so no need to convert this or EncryptionKeyLen from
	   little endian */
	server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
@@ -686,7 +634,7 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
			server->capabilities & CAP_EXTENDED_SECURITY) &&
				(pSMBr->EncryptionKeyLength == 0)) {
		server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
		rc = decode_ext_sec_blob(server, pSMBr);
		rc = decode_ext_sec_blob(ses, pSMBr);
	} else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
		rc = -EIO; /* no crypt key only if plain text pwd */
	} else {
+33 −84
Original line number Diff line number Diff line
@@ -1033,56 +1033,40 @@ static int cifs_parse_security_flavors(char *value,
	vol->sign = false;

	switch (match_token(value, cifs_secflavor_tokens, args)) {
	case Opt_sec_krb5p:
		cifs_dbg(VFS, "sec=krb5p is not supported!\n");
		return 1;
	case Opt_sec_krb5i:
		vol->sign = true;
		/* Fallthrough */
	case Opt_sec_krb5:
		vol->sectype = Kerberos;
		vol->secFlg |= CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_SIGN;
		break;
	case Opt_sec_krb5i:
		vol->sectype = Kerberos;
	case Opt_sec_ntlmsspi:
		vol->sign = true;
		vol->secFlg |= CIFSSEC_MAY_KRB5 | CIFSSEC_MUST_SIGN;
		break;
	case Opt_sec_krb5p:
		/* vol->secFlg |= CIFSSEC_MUST_SEAL | CIFSSEC_MAY_KRB5; */
		cifs_dbg(VFS, "Krb5 cifs privacy not supported\n");
		break;
		/* Fallthrough */
	case Opt_sec_ntlmssp:
		vol->sectype = RawNTLMSSP;
		vol->secFlg |= CIFSSEC_MAY_NTLMSSP;
		break;
	case Opt_sec_ntlmsspi:
		vol->sectype = RawNTLMSSP;
	case Opt_sec_ntlmi:
		vol->sign = true;
		vol->secFlg |= CIFSSEC_MAY_NTLMSSP | CIFSSEC_MUST_SIGN;
		break;
		/* Fallthrough */
	case Opt_ntlm:
		/* ntlm is default so can be turned off too */
		vol->sectype = NTLM;
		vol->secFlg |= CIFSSEC_MAY_NTLM;
		break;
	case Opt_sec_ntlmi:
		vol->sectype = NTLM;
	case Opt_sec_ntlmv2i:
		vol->sign = true;
		vol->secFlg |= CIFSSEC_MAY_NTLM | CIFSSEC_MUST_SIGN;
		break;
		/* Fallthrough */
	case Opt_sec_ntlmv2:
		vol->sectype = NTLMv2;
		vol->secFlg |= CIFSSEC_MAY_NTLMV2;
		break;
	case Opt_sec_ntlmv2i:
		vol->sectype = NTLMv2;
		vol->sign = true;
		vol->secFlg |= CIFSSEC_MAY_NTLMV2 | CIFSSEC_MUST_SIGN;
		break;
#ifdef CONFIG_CIFS_WEAK_PW_HASH
	case Opt_sec_lanman:
		vol->sectype = LANMAN;
		vol->secFlg |= CIFSSEC_MAY_LANMAN;
		break;
#endif
	case Opt_sec_none:
		vol->nullauth = 1;
		vol->secFlg |= CIFSSEC_MAY_NTLM;
		break;
	default:
		cifs_dbg(VFS, "bad security option: %s\n", value);
@@ -1445,7 +1429,6 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
			vol->local_lease = 1;
			break;
		case Opt_sign:
			vol->secFlg |= CIFSSEC_MUST_SIGN;
			vol->sign = true;
			break;
		case Opt_seal:
@@ -2003,40 +1986,19 @@ match_address(struct TCP_Server_Info *server, struct sockaddr *addr,
static bool
match_security(struct TCP_Server_Info *server, struct smb_vol *vol)
{
	unsigned int secFlags;

	if (vol->secFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
		secFlags = vol->secFlg;
	else
		secFlags = global_secflags | vol->secFlg;

	switch (server->secType) {
	case LANMAN:
		if (!(secFlags & (CIFSSEC_MAY_LANMAN|CIFSSEC_MAY_PLNTXT)))
			return false;
		break;
	case NTLMv2:
		if (!(secFlags & CIFSSEC_MAY_NTLMV2))
			return false;
		break;
	case NTLM:
		if (!(secFlags & CIFSSEC_MAY_NTLM))
			return false;
		break;
	case Kerberos:
		if (!(secFlags & CIFSSEC_MAY_KRB5))
			return false;
		break;
	case RawNTLMSSP:
		if (!(secFlags & CIFSSEC_MAY_NTLMSSP))
			return false;
		break;
	default:
		/* shouldn't happen */
	/*
	 * The select_sectype function should either return the vol->sectype
	 * that was specified, or "Unspecified" if that sectype was not
	 * compatible with the given NEGOTIATE request.
	 */
	if (select_sectype(server, vol->sectype) == Unspecified)
		return false;
	}

	/* now check if signing mode is acceptable */
	/*
	 * Now check if signing mode is acceptable. No need to check
	 * global_secflags at this point since if MUST_SIGN is set then
	 * the server->sign had better be too.
	 */
	if (vol->sign && !server->sign)
		return false;

@@ -2239,7 +2201,11 @@ cifs_get_tcp_session(struct smb_vol *volume_info)

static int match_session(struct cifs_ses *ses, struct smb_vol *vol)
{
	switch (ses->server->secType) {
	if (vol->sectype != Unspecified &&
	    vol->sectype != ses->sectype)
		return 0;

	switch (ses->sectype) {
	case Kerberos:
		if (!uid_eq(vol->cred_uid, ses->cred_uid))
			return 0;
@@ -2516,7 +2482,6 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
	ses->cred_uid = volume_info->cred_uid;
	ses->linux_uid = volume_info->linux_uid;

	ses->overrideSecFlg = volume_info->secFlg;
	ses->sectype = volume_info->sectype;
	ses->sign = volume_info->sign;

@@ -3681,7 +3646,7 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *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->sec_mode &
					    SECMODE_PW_ENCRYPT ? true : false,
@@ -3893,27 +3858,11 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
static int
cifs_set_vol_auth(struct smb_vol *vol, struct cifs_ses *ses)
{
	switch (ses->server->secType) {
	case Kerberos:
		vol->secFlg = CIFSSEC_MUST_KRB5;
	vol->sectype = ses->sectype;

	/* krb5 is special, since we don't need username or pw */
	if (vol->sectype == Kerberos)
		return 0;
	case NTLMv2:
		vol->secFlg = CIFSSEC_MUST_NTLMV2;
		break;
	case NTLM:
		vol->secFlg = CIFSSEC_MUST_NTLM;
		break;
	case RawNTLMSSP:
		vol->secFlg = CIFSSEC_MUST_NTLMSSP;
		break;
	case LANMAN:
		vol->secFlg = CIFSSEC_MUST_LANMAN;
		break;
	default:
		/* should never happen */
		vol->secFlg = 0;
		break;
	}

	return cifs_set_cifscreds(vol, ses);
}
Loading