Commit 32cb38e6 authored by Pavel Shilovsky's avatar Pavel Shilovsky

Update 3.19 sources from stable (v3.19.8-ckt10)

parent 4fdfe234
...@@ -441,6 +441,48 @@ find_domain_name(struct cifs_ses *ses, const struct nls_table *nls_cp) ...@@ -441,6 +441,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)
{ {
...@@ -637,6 +679,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) ...@@ -637,6 +679,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) {
...@@ -655,6 +698,12 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) ...@@ -655,6 +698,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;
...@@ -671,8 +720,8 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) ...@@ -671,8 +720,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;
......
...@@ -394,17 +394,17 @@ cifs_show_options(struct seq_file *s, struct dentry *root) ...@@ -394,17 +394,17 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
struct sockaddr *srcaddr; struct sockaddr *srcaddr;
srcaddr = (struct sockaddr *)&tcon->ses->server->srcaddr; srcaddr = (struct sockaddr *)&tcon->ses->server->srcaddr;
seq_printf(s, ",vers=%s", tcon->ses->server->vals->version_string); seq_show_option(s, "vers", tcon->ses->server->vals->version_string);
cifs_show_security(s, tcon->ses); cifs_show_security(s, tcon->ses);
cifs_show_cache_flavor(s, cifs_sb); cifs_show_cache_flavor(s, cifs_sb);
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)
seq_puts(s, ",multiuser"); seq_puts(s, ",multiuser");
else if (tcon->ses->user_name) else if (tcon->ses->user_name)
seq_printf(s, ",username=%s", tcon->ses->user_name); seq_show_option(s, "username", tcon->ses->user_name);
if (tcon->ses->domainName) if (tcon->ses->domainName)
seq_printf(s, ",domain=%s", tcon->ses->domainName); seq_show_option(s, "domain", tcon->ses->domainName);
if (srcaddr->sa_family != AF_UNSPEC) { if (srcaddr->sa_family != AF_UNSPEC) {
struct sockaddr_in *saddr4; struct sockaddr_in *saddr4;
......
...@@ -2015,7 +2015,6 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, ...@@ -2015,7 +2015,6 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
struct tcon_link *tlink = NULL; struct tcon_link *tlink = NULL;
struct cifs_tcon *tcon = NULL; struct cifs_tcon *tcon = NULL;
struct TCP_Server_Info *server; struct TCP_Server_Info *server;
struct cifs_io_parms io_parms;
/* /*
* To avoid spurious oplock breaks from server, in the case of * To avoid spurious oplock breaks from server, in the case of
...@@ -2037,18 +2036,6 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, ...@@ -2037,18 +2036,6 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
rc = -ENOSYS; rc = -ENOSYS;
cifsFileInfo_put(open_file); cifsFileInfo_put(open_file);
cifs_dbg(FYI, "SetFSize for attrs rc = %d\n", rc); cifs_dbg(FYI, "SetFSize for attrs rc = %d\n", rc);
if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
unsigned int bytes_written;
io_parms.netfid = open_file->fid.netfid;
io_parms.pid = open_file->pid;
io_parms.tcon = tcon;
io_parms.offset = 0;
io_parms.length = attrs->ia_size;
rc = CIFSSMBWrite(xid, &io_parms, &bytes_written,
NULL, NULL, 1);
cifs_dbg(FYI, "Wrt seteof rc %d\n", rc);
}
} else } else
rc = -EINVAL; rc = -EINVAL;
...@@ -2074,28 +2061,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, ...@@ -2074,28 +2061,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
else else
rc = -ENOSYS; rc = -ENOSYS;
cifs_dbg(FYI, "SetEOF by path (setattrs) rc = %d\n", rc); cifs_dbg(FYI, "SetEOF by path (setattrs) rc = %d\n", rc);
if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
__u16 netfid;
int oplock = 0;
rc = SMBLegacyOpen(xid, tcon, full_path, FILE_OPEN,
GENERIC_WRITE, CREATE_NOT_DIR, &netfid,
&oplock, NULL, cifs_sb->local_nls,
cifs_remap(cifs_sb));
if (rc == 0) {
unsigned int bytes_written;
io_parms.netfid = netfid;
io_parms.pid = current->tgid;
io_parms.tcon = tcon;
io_parms.offset = 0;
io_parms.length = attrs->ia_size;
rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, NULL,
NULL, 1);
cifs_dbg(FYI, "wrt seteof rc %d\n", rc);
CIFSSMBClose(xid, tcon, netfid);
}
}
if (tlink) if (tlink)
cifs_put_tlink(tlink); cifs_put_tlink(tlink);
......
...@@ -67,6 +67,12 @@ static long cifs_ioctl_clone(unsigned int xid, struct file *dst_file, ...@@ -67,6 +67,12 @@ static long cifs_ioctl_clone(unsigned int xid, struct file *dst_file,
goto out_drop_write; goto out_drop_write;
} }
if (src_file.file->f_op->unlocked_ioctl != cifs_ioctl) {
rc = -EBADF;
cifs_dbg(VFS, "src file seems to be from a different filesystem type\n");
goto out_fput;
}
if ((!src_file.file->private_data) || (!dst_file->private_data)) { if ((!src_file.file->private_data) || (!dst_file->private_data)) {
rc = -EBADF; rc = -EBADF;
cifs_dbg(VFS, "missing cifsFileInfo on copy range src file\n"); cifs_dbg(VFS, "missing cifsFileInfo on copy range src file\n");
......
...@@ -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
...@@ -427,19 +428,15 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) ...@@ -427,19 +428,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;
...@@ -533,7 +530,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, ...@@ -533,7 +530,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 */
...@@ -561,7 +559,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, ...@@ -561,7 +559,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)
...@@ -590,7 +589,48 @@ ssetup_ntlmssp_authenticate: ...@@ -590,7 +589,48 @@ ssetup_ntlmssp_authenticate:
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) {
...@@ -613,6 +653,8 @@ ssetup_ntlmssp_authenticate: ...@@ -613,6 +653,8 @@ ssetup_ntlmssp_authenticate:
/* 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,
...@@ -640,6 +682,8 @@ ssetup_ntlmssp_authenticate: ...@@ -640,6 +682,8 @@ ssetup_ntlmssp_authenticate:
} 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;
...@@ -651,8 +695,6 @@ ssetup_ntlmssp_authenticate: ...@@ -651,8 +695,6 @@ ssetup_ntlmssp_authenticate:
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 */);
...@@ -663,6 +705,7 @@ ssetup_ntlmssp_authenticate: ...@@ -663,6 +705,7 @@ ssetup_ntlmssp_authenticate:
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) {
...@@ -680,7 +723,6 @@ ssetup_ntlmssp_authenticate: ...@@ -680,7 +723,6 @@ ssetup_ntlmssp_authenticate:
/* 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);
} }
...@@ -737,6 +779,10 @@ keygen_exit: ...@@ -737,6 +779,10 @@ keygen_exit:
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;
......
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