Commit 253cf5ba authored by Pavel Shilovsky's avatar Pavel Shilovsky Committed by Thadeu Lima de Souza Cascardo

CIFS: Allow to switch on encryption with seal mount option

BugLink: http://bugs.launchpad.net/bugs/1670508

This allows users to inforce encryption for SMB3 shares if a server
supports it.
Signed-off-by: default avatarPavel Shilovsky <pshilov@microsoft.com>
(backport from commit ae6f8dd4)
Signed-off-by: default avatarJoseph Salisbury <joseph.salisbury@canonical.com>
[cascardo: fixup of conflict with 06e7bc14]
Signed-off-by: default avatarThadeu Lima de Souza Cascardo <cascardo@canonical.com>
parent 2df50fc9
...@@ -2601,12 +2601,18 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) ...@@ -2601,12 +2601,18 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
return ERR_PTR(rc); return ERR_PTR(rc);
} }
static int match_tcon(struct cifs_tcon *tcon, const char *unc) static int match_tcon(struct cifs_tcon *tcon, struct smb_vol *volume_info)
{ {
if (tcon->tidStatus == CifsExiting) if (tcon->tidStatus == CifsExiting)
return 0; return 0;
if (strncmp(tcon->treeName, unc, MAX_TREE_SIZE)) if (strncmp(tcon->treeName, volume_info->UNC, MAX_TREE_SIZE))
return 0; return 0;
if (tcon->seal != volume_info->seal)
return 0;
#ifdef CONFIG_CIFS_SMB2
if (tcon->snapshot_time != volume_info->snapshot_time)
return 0;
#endif /* CONFIG_CIFS_SMB2 */
return 1; return 1;
} }
...@@ -2619,14 +2625,8 @@ cifs_find_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) ...@@ -2619,14 +2625,8 @@ cifs_find_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
spin_lock(&cifs_tcp_ses_lock); spin_lock(&cifs_tcp_ses_lock);
list_for_each(tmp, &ses->tcon_list) { list_for_each(tmp, &ses->tcon_list) {
tcon = list_entry(tmp, struct cifs_tcon, tcon_list); tcon = list_entry(tmp, struct cifs_tcon, tcon_list);
if (!match_tcon(tcon, volume_info->UNC)) if (!match_tcon(tcon, volume_info))
continue;
#ifdef CONFIG_CIFS_SMB2
if (tcon->snapshot_time != volume_info->snapshot_time)
continue; continue;
#endif /* CONFIG_CIFS_SMB2 */
++tcon->tc_count; ++tcon->tc_count;
spin_unlock(&cifs_tcp_ses_lock); spin_unlock(&cifs_tcp_ses_lock);
return tcon; return tcon;
...@@ -2672,8 +2672,6 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) ...@@ -2672,8 +2672,6 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
cifs_dbg(FYI, "Found match on UNC path\n"); cifs_dbg(FYI, "Found match on UNC path\n");
/* existing tcon already has a reference */ /* existing tcon already has a reference */
cifs_put_smb_ses(ses); cifs_put_smb_ses(ses);
if (tcon->seal != volume_info->seal)
cifs_dbg(VFS, "transport encryption setting conflicts with existing tid\n");
return tcon; return tcon;
} }
...@@ -2729,7 +2727,6 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) ...@@ -2729,7 +2727,6 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
tcon->Flags &= ~SMB_SHARE_IS_IN_DFS; tcon->Flags &= ~SMB_SHARE_IS_IN_DFS;
cifs_dbg(FYI, "DFS disabled (%d)\n", tcon->Flags); cifs_dbg(FYI, "DFS disabled (%d)\n", tcon->Flags);
} }
tcon->seal = volume_info->seal;
tcon->use_persistent = false; tcon->use_persistent = false;
/* check if SMB2 or later, CIFS does not support persistent handles */ /* check if SMB2 or later, CIFS does not support persistent handles */
if (volume_info->persistent) { if (volume_info->persistent) {
...@@ -2766,6 +2763,24 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) ...@@ -2766,6 +2763,24 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
tcon->use_resilient = true; tcon->use_resilient = true;
} }
if (volume_info->seal) {
if (ses->server->vals->protocol_id == 0) {
cifs_dbg(VFS,
"SMB3 or later required for encryption\n");
rc = -EOPNOTSUPP;
goto out_fail;
#ifdef CONFIG_CIFS_SMB2
} else if (tcon->ses->server->capabilities &
SMB2_GLOBAL_CAP_ENCRYPTION)
tcon->seal = true;
else {
cifs_dbg(VFS, "Encryption is not supported on share\n");
rc = -EOPNOTSUPP;
goto out_fail;
#endif /* CONFIG_CIFS_SMB2 */
}
}
/* /*
* We can have only one retry value for a connection to a share so for * We can have only one retry value for a connection to a share so for
* resources mounted more than once to the same server share the last * resources mounted more than once to the same server share the last
...@@ -2897,7 +2912,7 @@ cifs_match_super(struct super_block *sb, void *data) ...@@ -2897,7 +2912,7 @@ cifs_match_super(struct super_block *sb, void *data)
if (!match_server(tcp_srv, volume_info) || if (!match_server(tcp_srv, volume_info) ||
!match_session(ses, volume_info) || !match_session(ses, volume_info) ||
!match_tcon(tcon, volume_info->UNC) || !match_tcon(tcon, volume_info) ||
!match_prepath(sb, mnt_data)) { !match_prepath(sb, mnt_data)) {
rc = 0; rc = 0;
goto out; goto out;
......
...@@ -79,9 +79,14 @@ static const int smb2_req_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = { ...@@ -79,9 +79,14 @@ static const int smb2_req_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = {
static int encryption_required(const struct cifs_tcon *tcon) static int encryption_required(const struct cifs_tcon *tcon)
{ {
if (!tcon)
return 0;
if ((tcon->ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA) || if ((tcon->ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA) ||
(tcon->share_flags & SHI1005_FLAGS_ENCRYPT_DATA)) (tcon->share_flags & SHI1005_FLAGS_ENCRYPT_DATA))
return 1; return 1;
if (tcon->seal &&
(tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION))
return 1;
return 0; return 0;
} }
...@@ -831,8 +836,6 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data) ...@@ -831,8 +836,6 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
ses->Suid = rsp->hdr.sync_hdr.SessionId; ses->Suid = rsp->hdr.sync_hdr.SessionId;
ses->session_flags = le16_to_cpu(rsp->SessionFlags); ses->session_flags = le16_to_cpu(rsp->SessionFlags);
if (ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA)
cifs_dbg(VFS, "SMB3 encryption not supported yet\n");
rc = SMB2_sess_establish_session(sess_data); rc = SMB2_sess_establish_session(sess_data);
out_put_spnego_key: out_put_spnego_key:
...@@ -929,8 +932,6 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data) ...@@ -929,8 +932,6 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
ses->Suid = rsp->hdr.sync_hdr.SessionId; ses->Suid = rsp->hdr.sync_hdr.SessionId;
ses->session_flags = le16_to_cpu(rsp->SessionFlags); ses->session_flags = le16_to_cpu(rsp->SessionFlags);
if (ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA)
cifs_dbg(VFS, "SMB3 encryption not supported yet\n");
out: out:
kfree(ntlmssp_blob); kfree(ntlmssp_blob);
...@@ -989,8 +990,6 @@ SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data) ...@@ -989,8 +990,6 @@ SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data)
ses->Suid = rsp->hdr.sync_hdr.SessionId; ses->Suid = rsp->hdr.sync_hdr.SessionId;
ses->session_flags = le16_to_cpu(rsp->SessionFlags); ses->session_flags = le16_to_cpu(rsp->SessionFlags);
if (ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA)
cifs_dbg(VFS, "SMB3 encryption not supported yet\n");
rc = SMB2_sess_establish_session(sess_data); rc = SMB2_sess_establish_session(sess_data);
out: out:
...@@ -1138,12 +1137,6 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, ...@@ -1138,12 +1137,6 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
else else
return -EIO; return -EIO;
if ((tcon && tcon->seal) &&
((ses->server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION) == 0)) {
cifs_dbg(VFS, "encryption requested but no server support");
return -EOPNOTSUPP;
}
unc_path = kmalloc(MAX_SHARENAME_LENGTH * 2, GFP_KERNEL); unc_path = kmalloc(MAX_SHARENAME_LENGTH * 2, GFP_KERNEL);
if (unc_path == NULL) if (unc_path == NULL)
return -ENOMEM; return -ENOMEM;
...@@ -1165,15 +1158,16 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, ...@@ -1165,15 +1158,16 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
return rc; return rc;
} }
if (ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA)
flags |= CIFS_TRANSFORM_REQ;
if (tcon == NULL) { if (tcon == NULL) {
if ((ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA))
flags |= CIFS_TRANSFORM_REQ;
/* since no tcon, smb2_init can not do this, so do here */ /* since no tcon, smb2_init can not do this, so do here */
req->hdr.sync_hdr.SessionId = ses->Suid; req->hdr.sync_hdr.SessionId = ses->Suid;
/* if (ses->server->sec_mode & SECMODE_SIGN_REQUIRED) /* if (ses->server->sec_mode & SECMODE_SIGN_REQUIRED)
req->hdr.Flags |= SMB2_FLAGS_SIGNED; */ req->hdr.Flags |= SMB2_FLAGS_SIGNED; */
} } else if (encryption_required(tcon))
flags |= CIFS_TRANSFORM_REQ;
iov[0].iov_base = (char *)req; iov[0].iov_base = (char *)req;
/* 4 for rfc1002 length field and 1 for pad */ /* 4 for rfc1002 length field and 1 for pad */
...@@ -1230,9 +1224,12 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, ...@@ -1230,9 +1224,12 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
if ((rsp->Capabilities & SMB2_SHARE_CAP_DFS) && if ((rsp->Capabilities & SMB2_SHARE_CAP_DFS) &&
((tcon->share_flags & SHI1005_FLAGS_DFS) == 0)) ((tcon->share_flags & SHI1005_FLAGS_DFS) == 0))
cifs_dbg(VFS, "DFS capability contradicts DFS flag\n"); cifs_dbg(VFS, "DFS capability contradicts DFS flag\n");
if (tcon->seal &&
!(tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION))
cifs_dbg(VFS, "Encryption is requested but not supported\n");
init_copy_chunk_defaults(tcon); init_copy_chunk_defaults(tcon);
if (tcon->share_flags & SHI1005_FLAGS_ENCRYPT_DATA)
cifs_dbg(VFS, "Encrypted shares not supported");
if (tcon->ses->server->ops->validate_negotiate) if (tcon->ses->server->ops->validate_negotiate)
rc = tcon->ses->server->ops->validate_negotiate(xid, tcon); rc = tcon->ses->server->ops->validate_negotiate(xid, tcon);
tcon_exit: tcon_exit:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment