Skip to content

Commit

Permalink
Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Linus Torvalds committed Sep 27, 2015
2 parents d8cc397 + 8862714 commit 69ea8b8
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 19 deletions.
53 changes: 51 additions & 2 deletions fs/cifs/cifsencrypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,48 @@ find_domain_name(struct cifs_ses *ses, const struct nls_table *nls_cp)
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,
const struct nls_table *nls_cp)
{
Expand Down Expand Up @@ -641,6 +683,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
struct ntlmv2_resp *ntlmv2;
char ntlmv2_hash[16];
unsigned char *tiblob = NULL; /* target info blob */
__le64 rsp_timestamp;

if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED) {
if (!ses->domainName) {
Expand All @@ -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);
tilen = ses->auth_key.len;
tiblob = ses->auth_key.response;
Expand All @@ -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);
ntlmv2->blob_signature = cpu_to_le32(0x00000101);
ntlmv2->reserved = 0;
/* Must be within 5 minutes of the server */
ntlmv2->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
ntlmv2->time = rsp_timestamp;

get_random_bytes(&ntlmv2->client_chal, sizeof(ntlmv2->client_chal));
ntlmv2->reserved2 = 0;

Expand Down
8 changes: 6 additions & 2 deletions fs/cifs/smb2ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,13 @@ change_conf(struct TCP_Server_Info *server)
break;
default:
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->oplock_credits = 1;
}
server->credits -= server->echo_credits + server->oplock_credits;
return 0;
Expand Down
84 changes: 69 additions & 15 deletions fs/cifs/smb2pdu.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#include "smb2status.h"
#include "smb2glob.h"
#include "cifspdu.h"
#include "cifs_spnego.h"

/*
* The following table defines the expected "StructureSize" of SMB2 requests
Expand Down Expand Up @@ -486,19 +487,15 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
cifs_dbg(FYI, "missing security blob on negprot\n");

rc = cifs_enable_signing(server, ses->sign);
#ifdef CONFIG_SMB2_ASN1 /* BB REMOVEME when updated asn1.c ready */
if (rc)
goto neg_exit;
if (blob_length)
if (blob_length) {
rc = decode_negTokenInit(security_blob, blob_length, server);
if (rc == 1)
rc = 0;
else if (rc == 0) {
rc = -EIO;
goto neg_exit;
if (rc == 1)
rc = 0;
else if (rc == 0)
rc = -EIO;
}
#endif

neg_exit:
free_rsp_buf(resp_buftype, rsp);
return rc;
Expand Down Expand Up @@ -592,7 +589,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
__le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */
struct TCP_Server_Info *server = ses->server;
u16 blob_length = 0;
char *security_blob;
struct key *spnego_key = NULL;
char *security_blob = NULL;
char *ntlmssp_blob = NULL;
bool use_spnego = false; /* else use raw ntlmssp */

Expand Down Expand Up @@ -620,7 +618,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
ses->ntlmssp->sesskey_per_smbsess = true;

/* 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:
if (phase == NtLmChallenge)
Expand Down Expand Up @@ -649,7 +648,48 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
iov[0].iov_base = (char *)req;
/* 4 for rfc1002 length field and 1 for pad */
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),
GFP_KERNEL);
if (ntlmssp_blob == NULL) {
Expand All @@ -672,6 +712,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
/* with raw NTLMSSP we don't encapsulate in SPNEGO */
security_blob = ntlmssp_blob;
}
iov[1].iov_base = security_blob;
iov[1].iov_len = blob_length;
} else if (phase == NtLmAuthenticate) {
req->hdr.SessionId = ses->Suid;
ntlmssp_blob = kzalloc(sizeof(struct _NEGOTIATE_MESSAGE) + 500,
Expand Down Expand Up @@ -699,6 +741,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
} else {
security_blob = ntlmssp_blob;
}
iov[1].iov_base = security_blob;
iov[1].iov_len = blob_length;
} else {
cifs_dbg(VFS, "illegal ntlmssp phase\n");
rc = -EIO;
Expand All @@ -710,8 +754,6 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
cpu_to_le16(sizeof(struct smb2_sess_setup_req) -
1 /* pad */ - 4 /* rfc1001 len */);
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 */);

Expand All @@ -722,6 +764,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,

kfree(security_blob);
rsp = (struct smb2_sess_setup_rsp *)iov[0].iov_base;
ses->Suid = rsp->hdr.SessionId;
if (resp_buftype != CIFS_NO_BUFFER &&
rsp->hdr.Status == STATUS_MORE_PROCESSING_REQUIRED) {
if (phase != NtLmNegotiate) {
Expand All @@ -739,7 +782,6 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
/* NTLMSSP Negotiate sent now processing challenge (response) */
phase = NtLmChallenge; /* process ntlmssp challenge */
rc = 0; /* MORE_PROCESSING is not an error here but expected */
ses->Suid = rsp->hdr.SessionId;
rc = decode_ntlmssp_challenge(rsp->Buffer,
le16_to_cpu(rsp->SecurityBufferLength), ses);
}
Expand Down Expand Up @@ -796,6 +838,10 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
kfree(ses->auth_key.response);
ses->auth_key.response = NULL;
}
if (spnego_key) {
key_invalidate(spnego_key);
key_put(spnego_key);
}
kfree(ses->ntlmssp);

return rc;
Expand Down Expand Up @@ -876,6 +922,12 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
if (tcon && tcon->bad_network_name)
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);
if (unc_path == NULL)
return -ENOMEM;
Expand Down Expand Up @@ -955,6 +1007,8 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
((tcon->share_flags & SHI1005_FLAGS_DFS) == 0))
cifs_dbg(VFS, "DFS capability contradicts DFS flag\n");
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)
rc = tcon->ses->server->ops->validate_negotiate(xid, tcon);
tcon_exit:
Expand Down

0 comments on commit 69ea8b8

Please sign in to comment.