smb2: Enforce sec= mount option
authorSachin Prabhu <sprabhu@redhat.com>
Wed, 18 Jan 2017 10:05:57 +0000 (15:35 +0530)
committerSteve French <smfrench@gmail.com>
Fri, 3 Mar 2017 05:13:37 +0000 (23:13 -0600)
If the security type specified using a mount option is not supported,
the SMB2 session setup code changes the security type to RawNTLMSSP. We
should instead fail the mount and return an error.

The patch changes the code for SMB2 to make it similar to the code used
for SMB1. Like in SMB1, we now use the global security flags to select
the security method to be used when no security method is specified and
to return an error when the requested auth method is not available.

For SMB2, we also use ntlmv2 as a synonym for nltmssp.

Signed-off-by: Sachin Prabhu <sprabhu@redhat.com>
Acked-by: Pavel Shilovsky <pshilov@microsoft.com>
Acked-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <smfrench@gmail.com>
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/connect.c
fs/cifs/sess.c
fs/cifs/smb1ops.c
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c
fs/cifs/smb2proto.h

index af224cda86971b2b5132b4848ade8c95f0b0aa46..d42dd3288647808216a6c22c56731dc960e525f8 100644 (file)
@@ -443,6 +443,9 @@ struct smb_version_operations {
        int (*is_transform_hdr)(void *buf);
        int (*receive_transform)(struct TCP_Server_Info *,
                                 struct mid_q_entry **);
+       enum securityEnum (*select_sectype)(struct TCP_Server_Info *,
+                           enum securityEnum);
+
 };
 
 struct smb_version_values {
index 9ee46c1c3ebda325cc243d6dbeb54953bfd96352..97e5d236d26559806ca8bc278f7c248e0579ef77 100644 (file)
@@ -533,4 +533,6 @@ int cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
 int __cifs_calc_signature(struct smb_rqst *rqst,
                        struct TCP_Server_Info *server, char *signature,
                        struct shash_desc *shash);
+enum securityEnum cifs_select_sectype(struct TCP_Server_Info *,
+                                       enum securityEnum);
 #endif                 /* _CIFSPROTO_H */
index 777ad9f4fc3c84acbb5d96878939c589341b7f86..de4c56e8fb3756843162b21bac9eff508f6ef054 100644 (file)
@@ -2073,7 +2073,8 @@ match_security(struct TCP_Server_Info *server, struct smb_vol *vol)
         * that was specified, or "Unspecified" if that sectype was not
         * compatible with the given NEGOTIATE request.
         */
-       if (select_sectype(server, vol->sectype) == Unspecified)
+       if (server->ops->select_sectype(server, vol->sectype)
+            == Unspecified)
                return false;
 
        /*
index dcbcc927399a0ffbaecf07c1f52fec42afeb3459..8b0502cd39afb6b27f89b24fdb63e8122f162aee 100644 (file)
@@ -498,7 +498,7 @@ setup_ntlmv2_ret:
 }
 
 enum securityEnum
-select_sectype(struct TCP_Server_Info *server, enum securityEnum requested)
+cifs_select_sectype(struct TCP_Server_Info *server, enum securityEnum requested)
 {
        switch (server->negflavor) {
        case CIFS_NEGFLAVOR_EXTENDED:
@@ -1391,7 +1391,7 @@ static int select_sec(struct cifs_ses *ses, struct sess_data *sess_data)
 {
        int type;
 
-       type = select_sectype(ses->server, ses->sectype);
+       type = cifs_select_sectype(ses->server, ses->sectype);
        cifs_dbg(FYI, "sess setup type %d\n", type);
        if (type == Unspecified) {
                cifs_dbg(VFS,
index 67a987e4d026e0643a21dd1e4c520902d64deeae..cc93ba4da9b592468f36d37b80777e88b8e400e6 100644 (file)
@@ -1087,6 +1087,7 @@ struct smb_version_operations smb1_operations = {
        .is_read_op = cifs_is_read_op,
        .wp_retry_size = cifs_wp_retry_size,
        .dir_needs_close = cifs_dir_needs_close,
+       .select_sectype = cifs_select_sectype,
 #ifdef CONFIG_CIFS_XATTR
        .query_all_EAs = CIFSSMBQAllEAs,
        .set_EA = CIFSSMBSetEA,
index b360c381b00ec973ff25ae656ee7a181ddbe1402..0231108d9387a4af3448a2d89451a4c86a0bc17c 100644 (file)
@@ -2381,6 +2381,7 @@ struct smb_version_operations smb20_operations = {
        .wp_retry_size = smb2_wp_retry_size,
        .dir_needs_close = smb2_dir_needs_close,
        .get_dfs_refer = smb2_get_dfs_refer,
+       .select_sectype = smb2_select_sectype,
 };
 
 struct smb_version_operations smb21_operations = {
@@ -2463,6 +2464,7 @@ struct smb_version_operations smb21_operations = {
        .dir_needs_close = smb2_dir_needs_close,
        .enum_snapshots = smb3_enum_snapshots,
        .get_dfs_refer = smb2_get_dfs_refer,
+       .select_sectype = smb2_select_sectype,
 };
 
 struct smb_version_operations smb30_operations = {
@@ -2555,6 +2557,7 @@ struct smb_version_operations smb30_operations = {
        .is_transform_hdr = smb3_is_transform_hdr,
        .receive_transform = smb3_receive_transform,
        .get_dfs_refer = smb2_get_dfs_refer,
+       .select_sectype = smb2_select_sectype,
 };
 
 #ifdef CONFIG_CIFS_SMB311
@@ -2648,6 +2651,7 @@ struct smb_version_operations smb311_operations = {
        .is_transform_hdr = smb3_is_transform_hdr,
        .receive_transform = smb3_receive_transform,
        .get_dfs_refer = smb2_get_dfs_refer,
+       .select_sectype = smb2_select_sectype,
 };
 #endif /* CIFS_SMB311 */
 
index 2069431b32e368aa7db4dd801aa83e773b93c6c7..7446496850a3bd5f21fb36e12b65ba5c78532612 100644 (file)
@@ -657,6 +657,28 @@ vneg_out:
        return -EIO;
 }
 
+enum securityEnum
+smb2_select_sectype(struct TCP_Server_Info *server, enum securityEnum requested)
+{
+       switch (requested) {
+       case Kerberos:
+       case RawNTLMSSP:
+               return requested;
+       case NTLMv2:
+               return RawNTLMSSP;
+       case Unspecified:
+               if (server->sec_ntlmssp &&
+                       (global_secflags & CIFSSEC_MAY_NTLMSSP))
+                       return RawNTLMSSP;
+               if ((server->sec_kerberos || server->sec_mskerberos) &&
+                       (global_secflags & CIFSSEC_MAY_KRB5))
+                       return Kerberos;
+               /* Fallthrough */
+       default:
+               return Unspecified;
+       }
+}
+
 struct SMB2_sess_data {
        unsigned int xid;
        struct cifs_ses *ses;
@@ -1009,10 +1031,17 @@ out:
 static int
 SMB2_select_sec(struct cifs_ses *ses, struct SMB2_sess_data *sess_data)
 {
-       if (ses->sectype != Kerberos && ses->sectype != RawNTLMSSP)
-               ses->sectype = RawNTLMSSP;
+       int type;
+
+       type = smb2_select_sectype(ses->server, ses->sectype);
+       cifs_dbg(FYI, "sess setup type %d\n", type);
+       if (type == Unspecified) {
+               cifs_dbg(VFS,
+                       "Unable to select appropriate authentication method!");
+               return -EINVAL;
+       }
 
-       switch (ses->sectype) {
+       switch (type) {
        case Kerberos:
                sess_data->func = SMB2_auth_kerberos;
                break;
@@ -1020,7 +1049,7 @@ SMB2_select_sec(struct cifs_ses *ses, struct SMB2_sess_data *sess_data)
                sess_data->func = SMB2_sess_auth_rawntlmssp_negotiate;
                break;
        default:
-               cifs_dbg(VFS, "secType %d not supported!\n", ses->sectype);
+               cifs_dbg(VFS, "secType %d not supported!\n", type);
                return -EOPNOTSUPP;
        }
 
index 11d9f3013db85b1a5883710e4105772023d47c50..69e35873b1de734991fbe027fd68b97b505d01c3 100644 (file)
@@ -181,4 +181,6 @@ extern int SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon,
                            __u8 *lease_key, const __le32 lease_state);
 extern int smb3_validate_negotiate(const unsigned int, struct cifs_tcon *);
 
+extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *,
+                                       enum securityEnum);
 #endif                 /* _SMB2PROTO_H */