@@ -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 */
@@ -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
@@ -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;
@@ -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) {
@@ -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)
@@ -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 */
@@ -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"));
@@ -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);
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(-)