Commit 69ea8b85 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6

Pull CIFS fixes from Steve French:
 "Four fixes from testing at the recent SMB3 Plugfest including two
  important authentication ones (one fixes authentication problems to
  some popular servers when clock times differ more than two hours
  between systems, the other fixes Kerberos authentication for SMB3)"

* 'for-next' of git://git.samba.org/sfrench/cifs-2.6:
  fix encryption error checks on mount
  [SMB3] Fix sec=krb5 on smb3 mounts
  cifs: use server timestamp for ntlmv2 authentication
  disabling oplocks/leases via module parm enable_oplocks broken for SMB3
parents d8cc3972 88627148
...@@ -444,6 +444,48 @@ find_domain_name(struct cifs_ses *ses, const struct nls_table *nls_cp) ...@@ -444,6 +444,48 @@ find_domain_name(struct cifs_ses *ses, const struct nls_table *nls_cp)
return 0; return 0;
} }
/* Server has provided av pairs/target info in the type 2 challenge
* packet and we have plucked it and stored within smb session.
* We parse that blob here to find the server given timestamp
* as part of ntlmv2 authentication (or local current time as
* default in case of failure)
*/
static __le64
find_timestamp(struct cifs_ses *ses)
{
unsigned int attrsize;
unsigned int type;
unsigned int onesize = sizeof(struct ntlmssp2_name);
unsigned char *blobptr;
unsigned char *blobend;
struct ntlmssp2_name *attrptr;
if (!ses->auth_key.len || !ses->auth_key.response)
return 0;
blobptr = ses->auth_key.response;
blobend = blobptr + ses->auth_key.len;
while (blobptr + onesize < blobend) {
attrptr = (struct ntlmssp2_name *) blobptr;
type = le16_to_cpu(attrptr->type);
if (type == NTLMSSP_AV_EOL)
break;
blobptr += 2; /* advance attr type */
attrsize = le16_to_cpu(attrptr->length);
blobptr += 2; /* advance attr size */
if (blobptr + attrsize > blobend)
break;
if (type == NTLMSSP_AV_TIMESTAMP) {
if (attrsize == sizeof(u64))
return *((__le64 *)blobptr);
}
blobptr += attrsize; /* advance attr value */
}
return cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
}
static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
const struct nls_table *nls_cp) const struct nls_table *nls_cp)
{ {
...@@ -641,6 +683,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) ...@@ -641,6 +683,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
struct ntlmv2_resp *ntlmv2; struct ntlmv2_resp *ntlmv2;
char ntlmv2_hash[16]; char ntlmv2_hash[16];
unsigned char *tiblob = NULL; /* target info blob */ unsigned char *tiblob = NULL; /* target info blob */
__le64 rsp_timestamp;
if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED) { if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED) {
if (!ses->domainName) { if (!ses->domainName) {
...@@ -659,6 +702,12 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) ...@@ -659,6 +702,12 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
} }
} }
/* Must be within 5 minutes of the server (or in range +/-2h
* in case of Mac OS X), so simply carry over server timestamp
* (as Windows 7 does)
*/
rsp_timestamp = find_timestamp(ses);
baselen = CIFS_SESS_KEY_SIZE + sizeof(struct ntlmv2_resp); baselen = CIFS_SESS_KEY_SIZE + sizeof(struct ntlmv2_resp);
tilen = ses->auth_key.len; tilen = ses->auth_key.len;
tiblob = ses->auth_key.response; tiblob = ses->auth_key.response;
...@@ -675,8 +724,8 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) ...@@ -675,8 +724,8 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
(ses->auth_key.response + CIFS_SESS_KEY_SIZE); (ses->auth_key.response + CIFS_SESS_KEY_SIZE);
ntlmv2->blob_signature = cpu_to_le32(0x00000101); ntlmv2->blob_signature = cpu_to_le32(0x00000101);
ntlmv2->reserved = 0; ntlmv2->reserved = 0;
/* Must be within 5 minutes of the server */ ntlmv2->time = rsp_timestamp;
ntlmv2->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
get_random_bytes(&ntlmv2->client_chal, sizeof(ntlmv2->client_chal)); get_random_bytes(&ntlmv2->client_chal, sizeof(ntlmv2->client_chal));
ntlmv2->reserved2 = 0; ntlmv2->reserved2 = 0;
......
...@@ -50,9 +50,13 @@ change_conf(struct TCP_Server_Info *server) ...@@ -50,9 +50,13 @@ change_conf(struct TCP_Server_Info *server)
break; break;
default: default:
server->echoes = true; server->echoes = true;
server->oplocks = true; if (enable_oplocks) {
server->oplocks = true;
server->oplock_credits = 1;
} else
server->oplocks = false;
server->echo_credits = 1; server->echo_credits = 1;
server->oplock_credits = 1;
} }
server->credits -= server->echo_credits + server->oplock_credits; server->credits -= server->echo_credits + server->oplock_credits;
return 0; return 0;
......
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#include "smb2status.h" #include "smb2status.h"
#include "smb2glob.h" #include "smb2glob.h"
#include "cifspdu.h" #include "cifspdu.h"
#include "cifs_spnego.h"
/* /*
* The following table defines the expected "StructureSize" of SMB2 requests * The following table defines the expected "StructureSize" of SMB2 requests
...@@ -486,19 +487,15 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) ...@@ -486,19 +487,15 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
cifs_dbg(FYI, "missing security blob on negprot\n"); cifs_dbg(FYI, "missing security blob on negprot\n");
rc = cifs_enable_signing(server, ses->sign); rc = cifs_enable_signing(server, ses->sign);
#ifdef CONFIG_SMB2_ASN1 /* BB REMOVEME when updated asn1.c ready */
if (rc) if (rc)
goto neg_exit; goto neg_exit;
if (blob_length) if (blob_length) {
rc = decode_negTokenInit(security_blob, blob_length, server); rc = decode_negTokenInit(security_blob, blob_length, server);
if (rc == 1) if (rc == 1)
rc = 0; rc = 0;
else if (rc == 0) { else if (rc == 0)
rc = -EIO; rc = -EIO;
goto neg_exit;
} }
#endif
neg_exit: neg_exit:
free_rsp_buf(resp_buftype, rsp); free_rsp_buf(resp_buftype, rsp);
return rc; return rc;
...@@ -592,7 +589,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, ...@@ -592,7 +589,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
__le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */
struct TCP_Server_Info *server = ses->server; struct TCP_Server_Info *server = ses->server;
u16 blob_length = 0; u16 blob_length = 0;
char *security_blob; struct key *spnego_key = NULL;
char *security_blob = NULL;
char *ntlmssp_blob = NULL; char *ntlmssp_blob = NULL;
bool use_spnego = false; /* else use raw ntlmssp */ bool use_spnego = false; /* else use raw ntlmssp */
...@@ -620,7 +618,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, ...@@ -620,7 +618,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
ses->ntlmssp->sesskey_per_smbsess = true; ses->ntlmssp->sesskey_per_smbsess = true;
/* FIXME: allow for other auth types besides NTLMSSP (e.g. krb5) */ /* FIXME: allow for other auth types besides NTLMSSP (e.g. krb5) */
ses->sectype = RawNTLMSSP; if (ses->sectype != Kerberos && ses->sectype != RawNTLMSSP)
ses->sectype = RawNTLMSSP;
ssetup_ntlmssp_authenticate: ssetup_ntlmssp_authenticate:
if (phase == NtLmChallenge) if (phase == NtLmChallenge)
...@@ -649,7 +648,48 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, ...@@ -649,7 +648,48 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
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 */
iov[0].iov_len = get_rfc1002_length(req) + 4 - 1; iov[0].iov_len = get_rfc1002_length(req) + 4 - 1;
if (phase == NtLmNegotiate) {
if (ses->sectype == Kerberos) {
#ifdef CONFIG_CIFS_UPCALL
struct cifs_spnego_msg *msg;
spnego_key = cifs_get_spnego_key(ses);
if (IS_ERR(spnego_key)) {
rc = PTR_ERR(spnego_key);
spnego_key = NULL;
goto ssetup_exit;
}
msg = spnego_key->payload.data;
/*
* check version field to make sure that cifs.upcall is
* sending us a response in an expected form
*/
if (msg->version != CIFS_SPNEGO_UPCALL_VERSION) {
cifs_dbg(VFS,
"bad cifs.upcall version. Expected %d got %d",
CIFS_SPNEGO_UPCALL_VERSION, msg->version);
rc = -EKEYREJECTED;
goto ssetup_exit;
}
ses->auth_key.response = kmemdup(msg->data, msg->sesskey_len,
GFP_KERNEL);
if (!ses->auth_key.response) {
cifs_dbg(VFS,
"Kerberos can't allocate (%u bytes) memory",
msg->sesskey_len);
rc = -ENOMEM;
goto ssetup_exit;
}
ses->auth_key.len = msg->sesskey_len;
blob_length = msg->secblob_len;
iov[1].iov_base = msg->data + msg->sesskey_len;
iov[1].iov_len = blob_length;
#else
rc = -EOPNOTSUPP;
goto ssetup_exit;
#endif /* CONFIG_CIFS_UPCALL */
} else if (phase == NtLmNegotiate) { /* if not krb5 must be ntlmssp */
ntlmssp_blob = kmalloc(sizeof(struct _NEGOTIATE_MESSAGE), ntlmssp_blob = kmalloc(sizeof(struct _NEGOTIATE_MESSAGE),
GFP_KERNEL); GFP_KERNEL);
if (ntlmssp_blob == NULL) { if (ntlmssp_blob == NULL) {
...@@ -672,6 +712,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, ...@@ -672,6 +712,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
/* with raw NTLMSSP we don't encapsulate in SPNEGO */ /* with raw NTLMSSP we don't encapsulate in SPNEGO */
security_blob = ntlmssp_blob; security_blob = ntlmssp_blob;
} }
iov[1].iov_base = security_blob;
iov[1].iov_len = blob_length;
} else if (phase == NtLmAuthenticate) { } else if (phase == NtLmAuthenticate) {
req->hdr.SessionId = ses->Suid; req->hdr.SessionId = ses->Suid;
ntlmssp_blob = kzalloc(sizeof(struct _NEGOTIATE_MESSAGE) + 500, ntlmssp_blob = kzalloc(sizeof(struct _NEGOTIATE_MESSAGE) + 500,
...@@ -699,6 +741,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, ...@@ -699,6 +741,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
} else { } else {
security_blob = ntlmssp_blob; security_blob = ntlmssp_blob;
} }
iov[1].iov_base = security_blob;
iov[1].iov_len = blob_length;
} else { } else {
cifs_dbg(VFS, "illegal ntlmssp phase\n"); cifs_dbg(VFS, "illegal ntlmssp phase\n");
rc = -EIO; rc = -EIO;
...@@ -710,8 +754,6 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, ...@@ -710,8 +754,6 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
cpu_to_le16(sizeof(struct smb2_sess_setup_req) - cpu_to_le16(sizeof(struct smb2_sess_setup_req) -
1 /* pad */ - 4 /* rfc1001 len */); 1 /* pad */ - 4 /* rfc1001 len */);
req->SecurityBufferLength = cpu_to_le16(blob_length); req->SecurityBufferLength = cpu_to_le16(blob_length);
iov[1].iov_base = security_blob;
iov[1].iov_len = blob_length;
inc_rfc1001_len(req, blob_length - 1 /* pad */); inc_rfc1001_len(req, blob_length - 1 /* pad */);
...@@ -722,6 +764,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, ...@@ -722,6 +764,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
kfree(security_blob); kfree(security_blob);
rsp = (struct smb2_sess_setup_rsp *)iov[0].iov_base; rsp = (struct smb2_sess_setup_rsp *)iov[0].iov_base;
ses->Suid = rsp->hdr.SessionId;
if (resp_buftype != CIFS_NO_BUFFER && if (resp_buftype != CIFS_NO_BUFFER &&
rsp->hdr.Status == STATUS_MORE_PROCESSING_REQUIRED) { rsp->hdr.Status == STATUS_MORE_PROCESSING_REQUIRED) {
if (phase != NtLmNegotiate) { if (phase != NtLmNegotiate) {
...@@ -739,7 +782,6 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, ...@@ -739,7 +782,6 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
/* NTLMSSP Negotiate sent now processing challenge (response) */ /* NTLMSSP Negotiate sent now processing challenge (response) */
phase = NtLmChallenge; /* process ntlmssp challenge */ phase = NtLmChallenge; /* process ntlmssp challenge */
rc = 0; /* MORE_PROCESSING is not an error here but expected */ rc = 0; /* MORE_PROCESSING is not an error here but expected */
ses->Suid = rsp->hdr.SessionId;
rc = decode_ntlmssp_challenge(rsp->Buffer, rc = decode_ntlmssp_challenge(rsp->Buffer,
le16_to_cpu(rsp->SecurityBufferLength), ses); le16_to_cpu(rsp->SecurityBufferLength), ses);
} }
...@@ -796,6 +838,10 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, ...@@ -796,6 +838,10 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
kfree(ses->auth_key.response); kfree(ses->auth_key.response);
ses->auth_key.response = NULL; ses->auth_key.response = NULL;
} }
if (spnego_key) {
key_invalidate(spnego_key);
key_put(spnego_key);
}
kfree(ses->ntlmssp); kfree(ses->ntlmssp);
return rc; return rc;
...@@ -876,6 +922,12 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, ...@@ -876,6 +922,12 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
if (tcon && tcon->bad_network_name) if (tcon && tcon->bad_network_name)
return -ENOENT; return -ENOENT;
if ((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;
...@@ -955,6 +1007,8 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, ...@@ -955,6 +1007,8 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
((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");
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