summaryrefslogtreecommitdiffstats
path: root/fs/cifs/smb2pdu.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/smb2pdu.c')
-rw-r--r--fs/cifs/smb2pdu.c860
1 files changed, 564 insertions, 296 deletions
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 28c0be5e69b7..96c172d94fba 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -85,7 +85,7 @@ static const int smb2_req_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = {
int smb3_encryption_required(const struct cifs_tcon *tcon)
{
- if (!tcon)
+ if (!tcon || !tcon->ses)
return 0;
if ((tcon->ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA) ||
(tcon->share_flags & SHI1005_FLAGS_ENCRYPT_DATA))
@@ -98,14 +98,13 @@ int smb3_encryption_required(const struct cifs_tcon *tcon)
static void
smb2_hdr_assemble(struct smb2_sync_hdr *shdr, __le16 smb2_cmd,
- const struct cifs_tcon *tcon)
+ const struct cifs_tcon *tcon,
+ struct TCP_Server_Info *server)
{
shdr->ProtocolId = SMB2_PROTO_NUMBER;
shdr->StructureSize = cpu_to_le16(64);
shdr->Command = smb2_cmd;
- if (tcon && tcon->ses && tcon->ses->server) {
- struct TCP_Server_Info *server = tcon->ses->server;
-
+ if (server) {
spin_lock(&server->req_lock);
/* Request up to 10 credits but don't go over the limit. */
if (server->credits >= server->max_credits)
@@ -125,8 +124,7 @@ smb2_hdr_assemble(struct smb2_sync_hdr *shdr, __le16 smb2_cmd,
/* GLOBAL_CAP_LARGE_MTU will only be set if dialect > SMB2.02 */
/* See sections 2.2.4 and 3.2.4.1.5 of MS-SMB2 */
- if ((tcon->ses) && (tcon->ses->server) &&
- (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
+ if (server && (server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
shdr->CreditCharge = cpu_to_le16(1);
/* else CreditCharge MBZ */
@@ -148,100 +146,19 @@ smb2_hdr_assemble(struct smb2_sync_hdr *shdr, __le16 smb2_cmd,
/* if (tcon->share_flags & SHI1005_FLAGS_DFS)
shdr->Flags |= SMB2_FLAGS_DFS_OPERATIONS; */
- if (tcon->ses && tcon->ses->server && tcon->ses->server->sign &&
- !smb3_encryption_required(tcon))
+ if (server && server->sign && !smb3_encryption_required(tcon))
shdr->Flags |= SMB2_FLAGS_SIGNED;
out:
return;
}
-#ifdef CONFIG_CIFS_DFS_UPCALL
-static int __smb2_reconnect(const struct nls_table *nlsc,
- struct cifs_tcon *tcon)
-{
- int rc;
- struct dfs_cache_tgt_list tl;
- struct dfs_cache_tgt_iterator *it = NULL;
- char *tree;
- const char *tcp_host;
- size_t tcp_host_len;
- const char *dfs_host;
- size_t dfs_host_len;
-
- tree = kzalloc(MAX_TREE_SIZE, GFP_KERNEL);
- if (!tree)
- return -ENOMEM;
-
- if (tcon->ipc) {
- scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$",
- tcon->ses->server->hostname);
- rc = SMB2_tcon(0, tcon->ses, tree, tcon, nlsc);
- goto out;
- }
-
- if (!tcon->dfs_path) {
- rc = SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nlsc);
- goto out;
- }
-
- rc = dfs_cache_noreq_find(tcon->dfs_path + 1, NULL, &tl);
- if (rc)
- goto out;
-
- extract_unc_hostname(tcon->ses->server->hostname, &tcp_host,
- &tcp_host_len);
-
- for (it = dfs_cache_get_tgt_iterator(&tl); it;
- it = dfs_cache_get_next_tgt(&tl, it)) {
- const char *tgt = dfs_cache_get_tgt_name(it);
-
- extract_unc_hostname(tgt, &dfs_host, &dfs_host_len);
-
- if (dfs_host_len != tcp_host_len
- || strncasecmp(dfs_host, tcp_host, dfs_host_len) != 0) {
- cifs_dbg(FYI, "%s: skipping %.*s, doesn't match %.*s",
- __func__,
- (int)dfs_host_len, dfs_host,
- (int)tcp_host_len, tcp_host);
- continue;
- }
-
- scnprintf(tree, MAX_TREE_SIZE, "\\%s", tgt);
-
- rc = SMB2_tcon(0, tcon->ses, tree, tcon, nlsc);
- if (!rc)
- break;
- if (rc == -EREMOTE)
- break;
- }
-
- if (!rc) {
- if (it)
- rc = dfs_cache_noreq_update_tgthint(tcon->dfs_path + 1,
- it);
- else
- rc = -ENOENT;
- }
- dfs_cache_free_tgts(&tl);
-out:
- kfree(tree);
- return rc;
-}
-#else
-static inline int __smb2_reconnect(const struct nls_table *nlsc,
- struct cifs_tcon *tcon)
-{
- return SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nlsc);
-}
-#endif
-
static int
-smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
+smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
+ struct TCP_Server_Info *server)
{
int rc;
struct nls_table *nls_codepage;
struct cifs_ses *ses;
- struct TCP_Server_Info *server;
int retries;
/*
@@ -270,12 +187,10 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
}
}
if ((!tcon->ses) || (tcon->ses->status == CifsExiting) ||
- (!tcon->ses->server))
+ (!tcon->ses->server) || !server)
return -EIO;
ses = tcon->ses;
- server = ses->server;
-
retries = server->nr_targets;
/*
@@ -303,8 +218,8 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
(server->tcpStatus != CifsNeedReconnect),
10 * HZ);
if (rc < 0) {
- cifs_dbg(FYI, "%s: aborting reconnect due to a received"
- " signal by the process\n", __func__);
+ cifs_dbg(FYI, "%s: aborting reconnect due to a received signal by the process\n",
+ __func__);
return -ERESTARTSYS;
}
@@ -349,15 +264,31 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
goto out;
}
+ /*
+ * If we are reconnecting an extra channel, bind
+ */
+ if (server->is_channel) {
+ ses->binding = true;
+ ses->binding_chan = cifs_ses_find_chan(ses, server);
+ }
+
rc = cifs_negotiate_protocol(0, tcon->ses);
if (!rc && tcon->ses->need_reconnect) {
rc = cifs_setup_session(0, tcon->ses, nls_codepage);
if ((rc == -EACCES) && !tcon->retry) {
rc = -EHOSTDOWN;
+ ses->binding = false;
+ ses->binding_chan = NULL;
mutex_unlock(&tcon->ses->session_mutex);
goto failed;
}
}
+ /*
+ * End of channel binding
+ */
+ ses->binding = false;
+ ses->binding_chan = NULL;
+
if (rc || !tcon->need_reconnect) {
mutex_unlock(&tcon->ses->session_mutex);
goto out;
@@ -367,18 +298,18 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
if (tcon->use_persistent)
tcon->need_reopen_files = true;
- rc = __smb2_reconnect(nls_codepage, tcon);
+ rc = cifs_tree_connect(0, tcon, nls_codepage);
mutex_unlock(&tcon->ses->session_mutex);
cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
if (rc) {
/* If sess reconnected but tcon didn't, something strange ... */
- printk_once(KERN_WARNING "reconnect tcon failed rc = %d\n", rc);
+ pr_warn_once("reconnect tcon failed rc = %d\n", rc);
goto out;
}
if (smb2_command != SMB2_INTERNAL_CMD)
- queue_delayed_work(cifsiod_wq, &server->reconnect, 0);
+ mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
atomic_inc(&tconInfoReconnectCount);
out:
@@ -408,7 +339,9 @@ failed:
}
static void
-fill_small_buf(__le16 smb2_command, struct cifs_tcon *tcon, void *buf,
+fill_small_buf(__le16 smb2_command, struct cifs_tcon *tcon,
+ struct TCP_Server_Info *server,
+ void *buf,
unsigned int *total_len)
{
struct smb2_sync_pdu *spdu = (struct smb2_sync_pdu *)buf;
@@ -421,7 +354,7 @@ fill_small_buf(__le16 smb2_command, struct cifs_tcon *tcon, void *buf,
*/
memset(buf, 0, 256);
- smb2_hdr_assemble(&spdu->sync_hdr, smb2_command, tcon);
+ smb2_hdr_assemble(&spdu->sync_hdr, smb2_command, tcon, server);
spdu->StructureSize2 = cpu_to_le16(parmsize);
*total_len = parmsize + sizeof(struct smb2_sync_hdr);
@@ -433,7 +366,8 @@ fill_small_buf(__le16 smb2_command, struct cifs_tcon *tcon, void *buf,
* function must have filled in request_buf pointer.
*/
static int __smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon,
- void **request_buf, unsigned int *total_len)
+ struct TCP_Server_Info *server,
+ void **request_buf, unsigned int *total_len)
{
/* BB eventually switch this to SMB2 specific small buf size */
if (smb2_command == SMB2_SET_INFO)
@@ -445,7 +379,7 @@ static int __smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon,
return -ENOMEM;
}
- fill_small_buf(smb2_command, tcon,
+ fill_small_buf(smb2_command, tcon, server,
(struct smb2_sync_hdr *)(*request_buf),
total_len);
@@ -459,27 +393,30 @@ static int __smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon,
}
static int smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon,
+ struct TCP_Server_Info *server,
void **request_buf, unsigned int *total_len)
{
int rc;
- rc = smb2_reconnect(smb2_command, tcon);
+ rc = smb2_reconnect(smb2_command, tcon, server);
if (rc)
return rc;
- return __smb2_plain_req_init(smb2_command, tcon, request_buf,
+ return __smb2_plain_req_init(smb2_command, tcon, server, request_buf,
total_len);
}
static int smb2_ioctl_req_init(u32 opcode, struct cifs_tcon *tcon,
+ struct TCP_Server_Info *server,
void **request_buf, unsigned int *total_len)
{
/* Skip reconnect only for FSCTL_VALIDATE_NEGOTIATE_INFO IOCTLs */
if (opcode == FSCTL_VALIDATE_NEGOTIATE_INFO) {
- return __smb2_plain_req_init(SMB2_IOCTL, tcon, request_buf,
- total_len);
+ return __smb2_plain_req_init(SMB2_IOCTL, tcon, server,
+ request_buf, total_len);
}
- return smb2_plain_req_init(SMB2_IOCTL, tcon, request_buf, total_len);
+ return smb2_plain_req_init(SMB2_IOCTL, tcon, server,
+ request_buf, total_len);
}
/* For explanation of negotiate contexts see MS-SMB2 section 2.2.3.1 */
@@ -615,13 +552,13 @@ static void decode_preauth_context(struct smb2_preauth_neg_context *ctxt)
/* If invalid preauth context warn but use what we requested, SHA-512 */
if (len < MIN_PREAUTH_CTXT_DATA_LEN) {
- printk_once(KERN_WARNING "server sent bad preauth context\n");
+ pr_warn_once("server sent bad preauth context\n");
return;
}
if (le16_to_cpu(ctxt->HashAlgorithmCount) != 1)
- printk_once(KERN_WARNING "illegal SMB3 hash algorithm count\n");
+ pr_warn_once("Invalid SMB3 hash algorithm count\n");
if (ctxt->HashAlgorithms != SMB2_PREAUTH_INTEGRITY_SHA512)
- printk_once(KERN_WARNING "unknown SMB3 hash algorithm\n");
+ pr_warn_once("unknown SMB3 hash algorithm\n");
}
static void decode_compress_ctx(struct TCP_Server_Info *server,
@@ -631,15 +568,15 @@ static void decode_compress_ctx(struct TCP_Server_Info *server,
/* sizeof compress context is a one element compression capbility struct */
if (len < 10) {
- printk_once(KERN_WARNING "server sent bad compression cntxt\n");
+ pr_warn_once("server sent bad compression cntxt\n");
return;
}
if (le16_to_cpu(ctxt->CompressionAlgorithmCount) != 1) {
- printk_once(KERN_WARNING "illegal SMB3 compress algorithm count\n");
+ pr_warn_once("Invalid SMB3 compress algorithm count\n");
return;
}
if (le16_to_cpu(ctxt->CompressionAlgorithms[0]) > 3) {
- printk_once(KERN_WARNING "unknown compression algorithm\n");
+ pr_warn_once("unknown compression algorithm\n");
return;
}
server->compress_algorithm = ctxt->CompressionAlgorithms[0];
@@ -652,18 +589,18 @@ static int decode_encrypt_ctx(struct TCP_Server_Info *server,
cifs_dbg(FYI, "decode SMB3.11 encryption neg context of len %d\n", len);
if (len < MIN_ENCRYPT_CTXT_DATA_LEN) {
- printk_once(KERN_WARNING "server sent bad crypto ctxt len\n");
+ pr_warn_once("server sent bad crypto ctxt len\n");
return -EINVAL;
}
if (le16_to_cpu(ctxt->CipherCount) != 1) {
- printk_once(KERN_WARNING "illegal SMB3.11 cipher count\n");
+ pr_warn_once("Invalid SMB3.11 cipher count\n");
return -EINVAL;
}
cifs_dbg(FYI, "SMB311 cipher type:%d\n", le16_to_cpu(ctxt->Ciphers[0]));
if ((ctxt->Ciphers[0] != SMB2_ENCRYPTION_AES128_CCM) &&
(ctxt->Ciphers[0] != SMB2_ENCRYPTION_AES128_GCM)) {
- printk_once(KERN_WARNING "invalid SMB3.11 cipher returned\n");
+ pr_warn_once("Invalid SMB3.11 cipher returned\n");
return -EINVAL;
}
server->cipher_type = ctxt->Ciphers[0];
@@ -763,7 +700,7 @@ create_posix_buf(umode_t mode)
buf->Name[14] = 0xCD;
buf->Name[15] = 0x7C;
buf->Mode = cpu_to_le32(mode);
- cifs_dbg(FYI, "mode on posix create 0%o", mode);
+ cifs_dbg(FYI, "mode on posix create 0%o\n", mode);
return buf;
}
@@ -775,7 +712,7 @@ add_posix_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode)
iov[num].iov_base = create_posix_buf(mode);
if (mode == ACL_NO_MODE)
- cifs_dbg(FYI, "illegal mode\n");
+ cifs_dbg(FYI, "Invalid mode\n");
if (iov[num].iov_base == NULL)
return -ENOMEM;
iov[num].iov_len = sizeof(struct create_posix);
@@ -827,7 +764,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
return -EIO;
}
- rc = smb2_plain_req_init(SMB2_NEGOTIATE, NULL, (void **) &req, &total_len);
+ rc = smb2_plain_req_init(SMB2_NEGOTIATE, NULL, server,
+ (void **) &req, &total_len);
if (rc)
return rc;
@@ -885,7 +823,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
rqst.rq_iov = iov;
rqst.rq_nvec = 1;
- rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
+ rc = cifs_send_recv(xid, ses, server,
+ &rqst, &resp_buftype, flags, &rsp_iov);
cifs_small_buf_release(req);
rsp = (struct smb2_negotiate_rsp *)rsp_iov.iov_base;
/*
@@ -893,9 +832,7 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
* cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]);
*/
if (rc == -EOPNOTSUPP) {
- cifs_server_dbg(VFS, "Dialect not supported by server. Consider "
- "specifying vers=1.0 or vers=2.0 on mount for accessing"
- " older servers\n");
+ cifs_server_dbg(VFS, "Dialect not supported by server. Consider specifying vers=1.0 or vers=2.0 on mount for accessing older servers\n");
goto neg_exit;
} else if (rc != 0)
goto neg_exit;
@@ -928,8 +865,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
} else if (le16_to_cpu(rsp->DialectRevision) !=
server->vals->protocol_id) {
/* if requested single dialect ensure returned dialect matched */
- cifs_server_dbg(VFS, "Illegal 0x%x dialect returned: not requested\n",
- le16_to_cpu(rsp->DialectRevision));
+ cifs_server_dbg(VFS, "Invalid 0x%x dialect returned: not requested\n",
+ le16_to_cpu(rsp->DialectRevision));
return -EIO;
}
@@ -946,8 +883,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
else if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID))
cifs_dbg(FYI, "negotiated smb3.1.1 dialect\n");
else {
- cifs_server_dbg(VFS, "Illegal dialect returned by server 0x%x\n",
- le16_to_cpu(rsp->DialectRevision));
+ cifs_server_dbg(VFS, "Invalid dialect returned by server 0x%x\n",
+ le16_to_cpu(rsp->DialectRevision));
rc = -EIO;
goto neg_exit;
}
@@ -1105,15 +1042,16 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
rc = 0;
goto out_free_inbuf;
} else if (rc != 0) {
- cifs_tcon_dbg(VFS, "validate protocol negotiate failed: %d\n", rc);
+ cifs_tcon_dbg(VFS, "validate protocol negotiate failed: %d\n",
+ rc);
rc = -EIO;
goto out_free_inbuf;
}
rc = -EIO;
if (rsplen != sizeof(*pneg_rsp)) {
- cifs_tcon_dbg(VFS, "invalid protocol negotiate response size: %d\n",
- rsplen);
+ cifs_tcon_dbg(VFS, "Invalid protocol negotiate response size: %d\n",
+ rsplen);
/* relax check since Mac returns max bufsize allowed on ioctl */
if (rsplen > CIFSMaxBufSize || rsplen < sizeof(*pneg_rsp))
@@ -1163,7 +1101,7 @@ smb2_select_sectype(struct TCP_Server_Info *server, enum securityEnum requested)
if ((server->sec_kerberos || server->sec_mskerberos) &&
(global_secflags & CIFSSEC_MAY_KRB5))
return Kerberos;
- /* Fallthrough */
+ fallthrough;
default:
return Unspecified;
}
@@ -1197,8 +1135,9 @@ SMB2_sess_alloc_buffer(struct SMB2_sess_data *sess_data)
struct TCP_Server_Info *server = cifs_ses_server(ses);
unsigned int total_len;
- rc = smb2_plain_req_init(SMB2_SESSION_SETUP, NULL, (void **) &req,
- &total_len);
+ rc = smb2_plain_req_init(SMB2_SESSION_SETUP, NULL, server,
+ (void **) &req,
+ &total_len);
if (rc)
return rc;
@@ -1275,6 +1214,7 @@ SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data)
/* BB add code to build os and lm fields */
rc = cifs_send_recv(sess_data->xid, sess_data->ses,
+ cifs_ses_server(sess_data->ses),
&rqst,
&sess_data->buf0_type,
CIFS_LOG_ERROR | CIFS_NEG_OP, &rsp_iov);
@@ -1336,6 +1276,8 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
spnego_key = cifs_get_spnego_key(ses);
if (IS_ERR(spnego_key)) {
rc = PTR_ERR(spnego_key);
+ if (rc == -ENOKEY)
+ cifs_dbg(VFS, "Verify user has a krb5 ticket and keyutils is installed\n");
spnego_key = NULL;
goto out;
}
@@ -1346,9 +1288,8 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
* 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);
+ cifs_dbg(VFS, "bad cifs.upcall version. Expected %d got %d\n",
+ CIFS_SPNEGO_UPCALL_VERSION, msg->version);
rc = -EKEYREJECTED;
goto out_put_spnego_key;
}
@@ -1358,8 +1299,7 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
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",
+ cifs_dbg(VFS, "Kerberos can't allocate (%u bytes) memory\n",
msg->sesskey_len);
rc = -ENOMEM;
goto out_put_spnego_key;
@@ -1541,6 +1481,21 @@ SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data)
}
rc = SMB2_sess_establish_session(sess_data);
+#ifdef CONFIG_CIFS_DEBUG_DUMP_KEYS
+ if (ses->server->dialect < SMB30_PROT_ID) {
+ cifs_dbg(VFS, "%s: dumping generated SMB2 session keys\n", __func__);
+ /*
+ * The session id is opaque in terms of endianness, so we can't
+ * print it as a long long. we dump it as we got it on the wire
+ */
+ cifs_dbg(VFS, "Session Id %*ph\n", (int)sizeof(ses->Suid),
+ &ses->Suid);
+ cifs_dbg(VFS, "Session Key %*ph\n",
+ SMB2_NTLMV2_SESSKEY_SIZE, ses->auth_key.response);
+ cifs_dbg(VFS, "Signing Key %*ph\n",
+ SMB3_SIGN_KEY_SIZE, ses->auth_key.response);
+ }
+#endif
out:
kfree(ntlmssp_blob);
SMB2_sess_free_buffer(sess_data);
@@ -1558,8 +1513,7 @@ SMB2_select_sec(struct cifs_ses *ses, struct SMB2_sess_data *sess_data)
type = smb2_select_sectype(cifs_ses_server(ses), ses->sectype);
cifs_dbg(FYI, "sess setup type %d\n", type);
if (type == Unspecified) {
- cifs_dbg(VFS,
- "Unable to select appropriate authentication method!");
+ cifs_dbg(VFS, "Unable to select appropriate authentication method!\n");
return -EINVAL;
}
@@ -1647,7 +1601,8 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
if (ses->need_reconnect)
goto smb2_session_already_dead;
- rc = smb2_plain_req_init(SMB2_LOGOFF, NULL, (void **) &req, &total_len);
+ rc = smb2_plain_req_init(SMB2_LOGOFF, NULL, ses->server,
+ (void **) &req, &total_len);
if (rc)
return rc;
@@ -1668,7 +1623,8 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
rqst.rq_iov = iov;
rqst.rq_nvec = 1;
- rc = cifs_send_recv(xid, ses, &rqst, &resp_buf_type, flags, &rsp_iov);
+ rc = cifs_send_recv(xid, ses, ses->server,
+ &rqst, &resp_buf_type, flags, &rsp_iov);
cifs_small_buf_release(req);
/*
* No tcon so can't do
@@ -1709,7 +1665,10 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
__le16 *unc_path = NULL;
int flags = 0;
unsigned int total_len;
- struct TCP_Server_Info *server = ses->server;
+ struct TCP_Server_Info *server;
+
+ /* always use master channel */
+ server = ses->server;
cifs_dbg(FYI, "TCON\n");
@@ -1730,8 +1689,8 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
/* SMB2 TREE_CONNECT request must be called with TreeId == 0 */
tcon->tid = 0;
atomic_set(&tcon->num_remote_opens, 0);
- rc = smb2_plain_req_init(SMB2_TREE_CONNECT, tcon, (void **) &req,
- &total_len);
+ rc = smb2_plain_req_init(SMB2_TREE_CONNECT, tcon, server,
+ (void **) &req, &total_len);
if (rc) {
kfree(unc_path);
return rc;
@@ -1770,7 +1729,8 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
/* Need 64 for max size write so ask for more in case not there yet */
req->sync_hdr.CreditRequest = cpu_to_le16(64);
- rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
+ rc = cifs_send_recv(xid, ses, server,
+ &rqst, &resp_buftype, flags, &rsp_iov);
cifs_small_buf_release(req);
rsp = (struct smb2_tree_connect_rsp *)rsp_iov.iov_base;
trace_smb3_tcon(xid, tcon->tid, ses->Suid, tree, rc);
@@ -1855,8 +1815,9 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
close_shroot_lease(&tcon->crfid);
- rc = smb2_plain_req_init(SMB2_TREE_DISCONNECT, tcon, (void **) &req,
- &total_len);
+ rc = smb2_plain_req_init(SMB2_TREE_DISCONNECT, tcon, ses->server,
+ (void **) &req,
+ &total_len);
if (rc)
return rc;
@@ -1872,7 +1833,8 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
rqst.rq_iov = iov;
rqst.rq_nvec = 1;
- rc = cifs_send_recv(xid, ses, &rqst, &resp_buf_type, flags, &rsp_iov);
+ rc = cifs_send_recv(xid, ses, ses->server,
+ &rqst, &resp_buf_type, flags, &rsp_iov);
cifs_small_buf_release(req);
if (rc)
cifs_stats_fail_inc(tcon, SMB2_TREE_DISCONNECT_HE);
@@ -1940,20 +1902,46 @@ parse_query_id_ctxt(struct create_context *cc, struct smb2_file_all_info *buf)
}
static void
-parse_posix_ctxt(struct create_context *cc, struct smb_posix_info *pposix_inf)
+parse_posix_ctxt(struct create_context *cc, struct smb2_file_all_info *info,
+ struct create_posix_rsp *posix)
{
- /* struct smb_posix_info *ppinf = (struct smb_posix_info *)cc; */
+ int sid_len;
+ u8 *beg = (u8 *)cc + le16_to_cpu(cc->DataOffset);
+ u8 *end = beg + le32_to_cpu(cc->DataLength);
+ u8 *sid;
+
+ memset(posix, 0, sizeof(*posix));
+
+ posix->nlink = le32_to_cpu(*(__le32 *)(beg + 0));
+ posix->reparse_tag = le32_to_cpu(*(__le32 *)(beg + 4));
+ posix->mode = le32_to_cpu(*(__le32 *)(beg + 8));
- /* TODO: Need to add parsing for the context and return */
- printk_once(KERN_WARNING
- "SMB3 3.11 POSIX response context not completed yet\n");
+ sid = beg + 12;
+ sid_len = posix_info_sid_size(sid, end);
+ if (sid_len < 0) {
+ cifs_dbg(VFS, "bad owner sid in posix create response\n");
+ return;
+ }
+ memcpy(&posix->owner, sid, sid_len);
+
+ sid = sid + sid_len;
+ sid_len = posix_info_sid_size(sid, end);
+ if (sid_len < 0) {
+ cifs_dbg(VFS, "bad group sid in posix create response\n");
+ return;
+ }
+ memcpy(&posix->group, sid, sid_len);
+
+ cifs_dbg(FYI, "nlink=%d mode=%o reparse_tag=%x\n",
+ posix->nlink, posix->mode, posix->reparse_tag);
}
void
smb2_parse_contexts(struct TCP_Server_Info *server,
- struct smb2_create_rsp *rsp,
- unsigned int *epoch, char *lease_key, __u8 *oplock,
- struct smb2_file_all_info *buf)
+ struct smb2_create_rsp *rsp,
+ unsigned int *epoch, char *lease_key, __u8 *oplock,
+ struct smb2_file_all_info *buf,
+ struct create_posix_rsp *posix)
{
char *data_offset;
struct create_context *cc;
@@ -1983,8 +1971,9 @@ smb2_parse_contexts(struct TCP_Server_Info *server,
strncmp(name, SMB2_CREATE_QUERY_ON_DISK_ID, 4) == 0)
parse_query_id_ctxt(cc, buf);
else if ((le16_to_cpu(cc->NameLength) == 16)) {
- if (memcmp(name, smb3_create_tag_posix, 16) == 0)
- parse_posix_ctxt(cc, NULL);
+ if (posix &&
+ memcmp(name, smb3_create_tag_posix, 16) == 0)
+ parse_posix_ctxt(cc, buf, posix);
}
/* else {
cifs_dbg(FYI, "Context not matched with len %d\n",
@@ -2219,28 +2208,75 @@ add_twarp_context(struct kvec *iov, unsigned int *num_iovec, __u64 timewarp)
return 0;
}
+/* See See http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx */
+static void setup_owner_group_sids(char *buf)
+{
+ struct owner_group_sids *sids = (struct owner_group_sids *)buf;
+
+ /* Populate the user ownership fields S-1-5-88-1 */
+ sids->owner.Revision = 1;
+ sids->owner.NumAuth = 3;
+ sids->owner.Authority[5] = 5;
+ sids->owner.SubAuthorities[0] = cpu_to_le32(88);
+ sids->owner.SubAuthorities[1] = cpu_to_le32(1);
+ sids->owner.SubAuthorities[2] = cpu_to_le32(current_fsuid().val);
+
+ /* Populate the group ownership fields S-1-5-88-2 */
+ sids->group.Revision = 1;
+ sids->group.NumAuth = 3;
+ sids->group.Authority[5] = 5;
+ sids->group.SubAuthorities[0] = cpu_to_le32(88);
+ sids->group.SubAuthorities[1] = cpu_to_le32(2);
+ sids->group.SubAuthorities[2] = cpu_to_le32(current_fsgid().val);
+
+ cifs_dbg(FYI, "owner S-1-5-88-1-%d, group S-1-5-88-2-%d\n", current_fsuid().val, current_fsgid().val);
+}
+
/* See MS-SMB2 2.2.13.2.2 and MS-DTYP 2.4.6 */
static struct crt_sd_ctxt *
-create_sd_buf(umode_t mode, unsigned int *len)
+create_sd_buf(umode_t mode, bool set_owner, unsigned int *len)
{
struct crt_sd_ctxt *buf;
struct cifs_ace *pace;
unsigned int sdlen, acelen;
+ unsigned int owner_offset = 0;
+ unsigned int group_offset = 0;
+
+ *len = roundup(sizeof(struct crt_sd_ctxt) + (sizeof(struct cifs_ace) * 2), 8);
+
+ if (set_owner) {
+ /* offset fields are from beginning of security descriptor not of create context */
+ owner_offset = sizeof(struct smb3_acl) + (sizeof(struct cifs_ace) * 2);
+
+ /* sizeof(struct owner_group_sids) is already multiple of 8 so no need to round */
+ *len += sizeof(struct owner_group_sids);
+ }
- *len = roundup(sizeof(struct crt_sd_ctxt) + sizeof(struct cifs_ace) * 2,
- 8);
buf = kzalloc(*len, GFP_KERNEL);
if (buf == NULL)
return buf;
+ if (set_owner) {
+ buf->sd.OffsetOwner = cpu_to_le32(owner_offset);
+ group_offset = owner_offset + sizeof(struct owner_sid);
+ buf->sd.OffsetGroup = cpu_to_le32(group_offset);
+ } else {
+ buf->sd.OffsetOwner = 0;
+ buf->sd.OffsetGroup = 0;
+ }
+
sdlen = sizeof(struct smb3_sd) + sizeof(struct smb3_acl) +
2 * sizeof(struct cifs_ace);
+ if (set_owner) {
+ sdlen += sizeof(struct owner_group_sids);
+ setup_owner_group_sids(owner_offset + sizeof(struct create_context) + 8 /* name */
+ + (char *)buf);
+ }
buf->ccontext.DataOffset = cpu_to_le16(offsetof
(struct crt_sd_ctxt, sd));
buf->ccontext.DataLength = cpu_to_le32(sdlen);
- buf->ccontext.NameOffset = cpu_to_le16(offsetof
- (struct crt_sd_ctxt, Name));
+ buf->ccontext.NameOffset = cpu_to_le16(offsetof(struct crt_sd_ctxt, Name));
buf->ccontext.NameLength = cpu_to_le16(4);
/* SMB2_CREATE_SD_BUFFER_TOKEN is "SecD" */
buf->Name[0] = 'S';
@@ -2261,23 +2297,34 @@ create_sd_buf(umode_t mode, unsigned int *len)
/* create one ACE to hold the mode embedded in reserved special SID */
pace = (struct cifs_ace *)(sizeof(struct crt_sd_ctxt) + (char *)buf);
acelen = setup_special_mode_ACE(pace, (__u64)mode);
+
+ if (set_owner) {
+ /* we do not need to reallocate buffer to add the two more ACEs. plenty of space */
+ pace = (struct cifs_ace *)(acelen + (sizeof(struct crt_sd_ctxt) + (char *)buf));
+ acelen += setup_special_user_owner_ACE(pace);
+ /* it does not appear necessary to add an ACE for the NFS group SID */
+ buf->acl.AceCount = cpu_to_le16(3);
+ } else
+ buf->acl.AceCount = cpu_to_le16(2);
+
/* and one more ACE to allow access for authenticated users */
pace = (struct cifs_ace *)(acelen + (sizeof(struct crt_sd_ctxt) +
(char *)buf));
acelen += setup_authusers_ACE(pace);
+
buf->acl.AclSize = cpu_to_le16(sizeof(struct cifs_acl) + acelen);
- buf->acl.AceCount = cpu_to_le16(2);
+
return buf;
}
static int
-add_sd_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode)
+add_sd_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode, bool set_owner)
{
struct smb2_create_req *req = iov[0].iov_base;
unsigned int num = *num_iovec;
unsigned int len = 0;
- iov[num].iov_base = create_sd_buf(mode, &len);
+ iov[num].iov_base = create_sd_buf(mode, set_owner, &len);
if (iov[num].iov_base == NULL)
return -ENOMEM;
iov[num].iov_len = len;
@@ -2399,6 +2446,7 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
int flags = 0;
unsigned int total_len;
__le16 *utf16_path = NULL;
+ struct TCP_Server_Info *server = cifs_pick_channel(ses);
cifs_dbg(FYI, "mkdir\n");
@@ -2407,13 +2455,14 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
if (!utf16_path)
return -ENOMEM;
- if (!ses || !(ses->server)) {
+ if (!ses || !server) {
rc = -EIO;
goto err_free_path;
}
/* resource #2: request */
- rc = smb2_plain_req_init(SMB2_CREATE, tcon, (void **) &req, &total_len);
+ rc = smb2_plain_req_init(SMB2_CREATE, tcon, server,
+ (void **) &req, &total_len);
if (rc)
goto err_free_path;
@@ -2499,7 +2548,8 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
trace_smb3_posix_mkdir_enter(xid, tcon->tid, ses->Suid, CREATE_NOT_FILE,
FILE_WRITE_ATTRIBUTES);
/* resource #4: response buffer */
- rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
+ rc = cifs_send_recv(xid, ses, server,
+ &rqst, &resp_buftype, flags, &rsp_iov);
if (rc) {
cifs_stats_fail_inc(tcon, SMB2_CREATE_HE);
trace_smb3_posix_mkdir_err(xid, tcon->tid, ses->Suid,
@@ -2528,10 +2578,10 @@ err_free_path:
}
int
-SMB2_open_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, __u8 *oplock,
+SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
+ struct smb_rqst *rqst, __u8 *oplock,
struct cifs_open_parms *oparms, __le16 *path)
{
- struct TCP_Server_Info *server = tcon->ses->server;
struct smb2_create_req *req;
unsigned int n_iov = 2;
__u32 file_attributes = 0;
@@ -2542,7 +2592,8 @@ SMB2_open_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, __u8 *oplock,
__le16 *copy_path;
int rc;
- rc = smb2_plain_req_init(SMB2_CREATE, tcon, (void **) &req, &total_len);
+ rc = smb2_plain_req_init(SMB2_CREATE, tcon, server,
+ (void **) &req, &total_len);
if (rc)
return rc;
@@ -2662,21 +2713,35 @@ SMB2_open_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, __u8 *oplock,
return rc;
}
- if ((oparms->disposition != FILE_OPEN) &&
- (oparms->cifs_sb) &&
- (oparms->cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) &&
- (oparms->mode != ACL_NO_MODE)) {
- if (n_iov > 2) {
- struct create_context *ccontext =
- (struct create_context *)iov[n_iov-1].iov_base;
- ccontext->Next =
- cpu_to_le32(iov[n_iov-1].iov_len);
+ if ((oparms->disposition != FILE_OPEN) && (oparms->cifs_sb)) {
+ bool set_mode;
+ bool set_owner;
+
+ if ((oparms->cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) &&
+ (oparms->mode != ACL_NO_MODE))
+ set_mode = true;
+ else {
+ set_mode = false;
+ oparms->mode = ACL_NO_MODE;
}
- cifs_dbg(FYI, "add sd with mode 0x%x\n", oparms->mode);
- rc = add_sd_context(iov, &n_iov, oparms->mode);
- if (rc)
- return rc;
+ if (oparms->cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL)
+ set_owner = true;
+ else
+ set_owner = false;
+
+ if (set_owner | set_mode) {
+ if (n_iov > 2) {
+ struct create_context *ccontext =
+ (struct create_context *)iov[n_iov-1].iov_base;
+ ccontext->Next = cpu_to_le32(iov[n_iov-1].iov_len);
+ }
+
+ cifs_dbg(FYI, "add sd with mode 0x%x\n", oparms->mode);
+ rc = add_sd_context(iov, &n_iov, oparms->mode, set_owner);
+ if (rc)
+ return rc;
+ }
}
if (n_iov > 2) {
@@ -2709,13 +2774,14 @@ SMB2_open_free(struct smb_rqst *rqst)
int
SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
__u8 *oplock, struct smb2_file_all_info *buf,
+ struct create_posix_rsp *posix,
struct kvec *err_iov, int *buftype)
{
struct smb_rqst rqst;
struct smb2_create_rsp *rsp = NULL;
- struct TCP_Server_Info *server;
struct cifs_tcon *tcon = oparms->tcon;
struct cifs_ses *ses = tcon->ses;
+ struct TCP_Server_Info *server = cifs_pick_channel(ses);
struct kvec iov[SMB2_CREATE_IOV_SIZE];
struct kvec rsp_iov = {NULL, 0};
int resp_buftype = CIFS_NO_BUFFER;
@@ -2723,9 +2789,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
int flags = 0;
cifs_dbg(FYI, "create/open\n");
- if (ses && (ses->server))
- server = ses->server;
- else
+ if (!ses || !server)
return -EIO;
if (smb3_encryption_required(tcon))
@@ -2736,14 +2800,16 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
rqst.rq_iov = iov;
rqst.rq_nvec = SMB2_CREATE_IOV_SIZE;
- rc = SMB2_open_init(tcon, &rqst, oplock, oparms, path);
+ rc = SMB2_open_init(tcon, server,
+ &rqst, oplock, oparms, path);
if (rc)
goto creat_exit;
trace_smb3_open_enter(xid, tcon->tid, tcon->ses->Suid,
oparms->create_options, oparms->desired_access);
- rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags,
+ rc = cifs_send_recv(xid, ses, server,
+ &rqst, &resp_buftype, flags,
&rsp_iov);
rsp = (struct smb2_create_rsp *)rsp_iov.iov_base;
@@ -2758,8 +2824,8 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
trace_smb3_open_err(xid, tcon->tid, ses->Suid,
oparms->create_options, oparms->desired_access, rc);
if (rc == -EREMCHG) {
- printk_once(KERN_WARNING "server share %s deleted\n",
- tcon->treeName);
+ pr_warn_once("server share %s deleted\n",
+ tcon->treeName);
tcon->need_reconnect = true;
}
goto creat_exit;
@@ -2787,7 +2853,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
smb2_parse_contexts(server, rsp, &oparms->fid->epoch,
- oparms->fid->lease_key, oplock, buf);
+ oparms->fid->lease_key, oplock, buf, posix);
creat_exit:
SMB2_open_free(&rqst);
free_rsp_buf(resp_buftype, rsp);
@@ -2795,7 +2861,8 @@ creat_exit:
}
int
-SMB2_ioctl_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
+SMB2_ioctl_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
+ struct smb_rqst *rqst,
u64 persistent_fid, u64 volatile_fid, u32 opcode,
bool is_fsctl, char *in_data, u32 indatalen,
__u32 max_response_size)
@@ -2806,7 +2873,8 @@ SMB2_ioctl_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
int rc;
char *in_data_buf;
- rc = smb2_ioctl_req_init(opcode, tcon, (void **) &req, &total_len);
+ rc = smb2_ioctl_req_init(opcode, tcon, server,
+ (void **) &req, &total_len);
if (rc)
return rc;
@@ -2868,7 +2936,9 @@ SMB2_ioctl_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
* response size smaller.
*/
req->MaxOutputResponse = cpu_to_le32(max_response_size);
-
+ req->sync_hdr.CreditCharge =
+ cpu_to_le16(DIV_ROUND_UP(max(indatalen, max_response_size),
+ SMB2_MAX_BUFFER_SIZE));
if (is_fsctl)
req->Flags = cpu_to_le32(SMB2_0_IOCTL_IS_FSCTL);
else
@@ -2906,12 +2976,12 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
struct smb_rqst rqst;
struct smb2_ioctl_rsp *rsp = NULL;
struct cifs_ses *ses;
+ struct TCP_Server_Info *server;
struct kvec iov[SMB2_IOCTL_IOV_SIZE];
struct kvec rsp_iov = {NULL, 0};
int resp_buftype = CIFS_NO_BUFFER;
int rc = 0;
int flags = 0;
- struct TCP_Server_Info *server;
cifs_dbg(FYI, "SMB2 IOCTL\n");
@@ -2922,14 +2992,14 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
if (plen)
*plen = 0;
- if (tcon)
- ses = tcon->ses;
- else
+ if (!tcon)
return -EIO;
+ ses = tcon->ses;
if (!ses)
return -EIO;
- server = ses->server;
+
+ server = cifs_pick_channel(ses);
if (!server)
return -EIO;
@@ -2941,12 +3011,14 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
rqst.rq_iov = iov;
rqst.rq_nvec = SMB2_IOCTL_IOV_SIZE;
- rc = SMB2_ioctl_init(tcon, &rqst, persistent_fid, volatile_fid, opcode,
+ rc = SMB2_ioctl_init(tcon, server,
+ &rqst, persistent_fid, volatile_fid, opcode,
is_fsctl, in_data, indatalen, max_out_data_len);
if (rc)
goto ioctl_exit;
- rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags,
+ rc = cifs_send_recv(xid, ses, server,
+ &rqst, &resp_buftype, flags,
&rsp_iov);
rsp = (struct smb2_ioctl_rsp *)rsp_iov.iov_base;
@@ -3034,7 +3106,8 @@ SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
}
int
-SMB2_close_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
+SMB2_close_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
+ struct smb_rqst *rqst,
u64 persistent_fid, u64 volatile_fid, bool query_attrs)
{
struct smb2_close_req *req;
@@ -3042,7 +3115,8 @@ SMB2_close_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
unsigned int total_len;
int rc;
- rc = smb2_plain_req_init(SMB2_CLOSE, tcon, (void **) &req, &total_len);
+ rc = smb2_plain_req_init(SMB2_CLOSE, tcon, server,
+ (void **) &req, &total_len);
if (rc)
return rc;
@@ -3073,6 +3147,7 @@ __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
struct smb_rqst rqst;
struct smb2_close_rsp *rsp = NULL;
struct cifs_ses *ses = tcon->ses;
+ struct TCP_Server_Info *server = cifs_pick_channel(ses);
struct kvec iov[1];
struct kvec rsp_iov;
int resp_buftype = CIFS_NO_BUFFER;
@@ -3082,7 +3157,7 @@ __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
cifs_dbg(FYI, "Close\n");
- if (!ses || !(ses->server))
+ if (!ses || !server)
return -EIO;
if (smb3_encryption_required(tcon))
@@ -3098,12 +3173,14 @@ __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
query_attrs = true;
trace_smb3_close_enter(xid, persistent_fid, tcon->tid, ses->Suid);
- rc = SMB2_close_init(tcon, &rqst, persistent_fid, volatile_fid,
+ rc = SMB2_close_init(tcon, server,
+ &rqst, persistent_fid, volatile_fid,
query_attrs);
if (rc)
goto close_exit;
- rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
+ rc = cifs_send_recv(xid, ses, server,
+ &rqst, &resp_buftype, flags, &rsp_iov);
rsp = (struct smb2_close_rsp *)rsp_iov.iov_base;
if (rc != 0) {
@@ -3171,7 +3248,7 @@ smb2_validate_iov(unsigned int offset, unsigned int buffer_length,
}
if ((begin_of_buf > end_of_smb) || (end_of_buf > end_of_smb)) {
- cifs_dbg(VFS, "illegal server response, bad offset to data\n");
+ cifs_dbg(VFS, "Invalid server response, bad offset to data\n");
return -EINVAL;
}
@@ -3203,7 +3280,8 @@ smb2_validate_and_copy_iov(unsigned int offset, unsigned int buffer_length,
}
int
-SMB2_query_info_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
+SMB2_query_info_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
+ struct smb_rqst *rqst,
u64 persistent_fid, u64 volatile_fid,
u8 info_class, u8 info_type, u32 additional_info,
size_t output_len, size_t input_len, void *input)
@@ -3213,8 +3291,8 @@ SMB2_query_info_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
unsigned int total_len;
int rc;
- rc = smb2_plain_req_init(SMB2_QUERY_INFO, tcon, (void **) &req,
- &total_len);
+ rc = smb2_plain_req_init(SMB2_QUERY_INFO, tcon, server,
+ (void **) &req, &total_len);
if (rc)
return rc;
@@ -3266,7 +3344,7 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
if (!ses)
return -EIO;
- server = ses->server;
+ server = cifs_pick_channel(ses);
if (!server)
return -EIO;
@@ -3278,7 +3356,8 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
rqst.rq_iov = iov;
rqst.rq_nvec = 1;
- rc = SMB2_query_info_init(tcon, &rqst, persistent_fid, volatile_fid,
+ rc = SMB2_query_info_init(tcon, server,
+ &rqst, persistent_fid, volatile_fid,
info_class, info_type, additional_info,
output_len, 0, NULL);
if (rc)
@@ -3287,7 +3366,8 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
trace_smb3_query_info_enter(xid, persistent_fid, tcon->tid,
ses->Suid, info_class, (__u32)info_type);
- rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
+ rc = cifs_send_recv(xid, ses, server,
+ &rqst, &resp_buftype, flags, &rsp_iov);
rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
if (rc) {
@@ -3342,6 +3422,19 @@ int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
}
int
+SMB311_posix_query_info(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid, struct smb311_posix_qinfo *data, u32 *plen)
+{
+ size_t output_len = sizeof(struct smb311_posix_qinfo *) +
+ (sizeof(struct cifs_sid) * 2) + (PATH_MAX * 2);
+ *plen = 0;
+
+ return query_info(xid, tcon, persistent_fid, volatile_fid,
+ SMB_FIND_FILE_POSIX_INFO, SMB2_O_INFO_FILE, 0,
+ output_len, sizeof(struct smb311_posix_qinfo), (void **)&data, plen);
+}
+
+int
SMB2_query_acl(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid,
void **data, u32 *plen)
@@ -3372,15 +3465,17 @@ SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
static int
SMB2_notify_init(const unsigned int xid, struct smb_rqst *rqst,
- struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid,
- u32 completion_filter, bool watch_tree)
+ struct cifs_tcon *tcon, struct TCP_Server_Info *server,
+ u64 persistent_fid, u64 volatile_fid,
+ u32 completion_filter, bool watch_tree)
{
struct smb2_change_notify_req *req;
struct kvec *iov = rqst->rq_iov;
unsigned int total_len;
int rc;
- rc = smb2_plain_req_init(SMB2_CHANGE_NOTIFY, tcon, (void **) &req, &total_len);
+ rc = smb2_plain_req_init(SMB2_CHANGE_NOTIFY, tcon, server,
+ (void **) &req, &total_len);
if (rc)
return rc;
@@ -3407,6 +3502,7 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
u32 completion_filter)
{
struct cifs_ses *ses = tcon->ses;
+ struct TCP_Server_Info *server = cifs_pick_channel(ses);
struct smb_rqst rqst;
struct kvec iov[1];
struct kvec rsp_iov = {NULL, 0};
@@ -3415,7 +3511,7 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
int rc = 0;
cifs_dbg(FYI, "change notify\n");
- if (!ses || !(ses->server))
+ if (!ses || !server)
return -EIO;
if (smb3_encryption_required(tcon))
@@ -3426,14 +3522,16 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
rqst.rq_iov = iov;
rqst.rq_nvec = 1;
- rc = SMB2_notify_init(xid, &rqst, tcon, persistent_fid, volatile_fid,
+ rc = SMB2_notify_init(xid, &rqst, tcon, server,
+ persistent_fid, volatile_fid,
completion_filter, watch_tree);
if (rc)
goto cnotify_exit;
trace_smb3_notify_enter(xid, persistent_fid, tcon->tid, ses->Suid,
(u8)watch_tree, completion_filter);
- rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
+ rc = cifs_send_recv(xid, ses, server,
+ &rqst, &resp_buftype, flags, &rsp_iov);
if (rc != 0) {
cifs_stats_fail_inc(tcon, SMB2_CHANGE_NOTIFY_HE);
@@ -3523,7 +3621,7 @@ void smb2_reconnect_server(struct work_struct *work)
spin_unlock(&cifs_tcp_ses_lock);
list_for_each_entry_safe(tcon, tcon2, &tmp_list, rlist) {
- rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon);
+ rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon, server);
if (!rc)
cifs_reopen_persistent_handles(tcon);
else
@@ -3559,11 +3657,12 @@ SMB2_echo(struct TCP_Server_Info *server)
if (server->tcpStatus == CifsNeedNegotiate) {
/* No need to send echo on newly established connections */
- queue_delayed_work(cifsiod_wq, &server->reconnect, 0);
+ mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
return rc;
}
- rc = smb2_plain_req_init(SMB2_ECHO, NULL, (void **)&req, &total_len);
+ rc = smb2_plain_req_init(SMB2_ECHO, NULL, server,
+ (void **)&req, &total_len);
if (rc)
return rc;
@@ -3590,14 +3689,16 @@ SMB2_flush_free(struct smb_rqst *rqst)
int
SMB2_flush_init(const unsigned int xid, struct smb_rqst *rqst,
- struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid)
+ struct cifs_tcon *tcon, struct TCP_Server_Info *server,
+ u64 persistent_fid, u64 volatile_fid)
{
struct smb2_flush_req *req;
struct kvec *iov = rqst->rq_iov;
unsigned int total_len;
int rc;
- rc = smb2_plain_req_init(SMB2_FLUSH, tcon, (void **) &req, &total_len);
+ rc = smb2_plain_req_init(SMB2_FLUSH, tcon, server,
+ (void **) &req, &total_len);
if (rc)
return rc;
@@ -3618,6 +3719,7 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
struct smb_rqst rqst;
struct kvec iov[1];
struct kvec rsp_iov = {NULL, 0};
+ struct TCP_Server_Info *server = cifs_pick_channel(ses);
int resp_buftype = CIFS_NO_BUFFER;
int flags = 0;
int rc = 0;
@@ -3634,12 +3736,14 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
rqst.rq_iov = iov;
rqst.rq_nvec = 1;
- rc = SMB2_flush_init(xid, &rqst, tcon, persistent_fid, volatile_fid);
+ rc = SMB2_flush_init(xid, &rqst, tcon, server,
+ persistent_fid, volatile_fid);
if (rc)
goto flush_exit;
trace_smb3_flush_enter(xid, persistent_fid, tcon->tid, ses->Suid);
- rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
+ rc = cifs_send_recv(xid, ses, server,
+ &rqst, &resp_buftype, flags, &rsp_iov);
if (rc != 0) {
cifs_stats_fail_inc(tcon, SMB2_FLUSH_HE);
@@ -3667,14 +3771,13 @@ smb2_new_read_req(void **buf, unsigned int *total_len,
int rc = -EACCES;
struct smb2_read_plain_req *req = NULL;
struct smb2_sync_hdr *shdr;
- struct TCP_Server_Info *server;
+ struct TCP_Server_Info *server = io_parms->server;
- rc = smb2_plain_req_init(SMB2_READ, io_parms->tcon, (void **) &req,
- total_len);
+ rc = smb2_plain_req_init(SMB2_READ, io_parms->tcon, server,
+ (void **) &req, total_len);
if (rc)
return rc;
- server = io_parms->tcon->ses->server;
if (server == NULL)
return -ECONNABORTED;
@@ -3703,8 +3806,7 @@ smb2_new_read_req(void **buf, unsigned int *total_len,
rdata->bytes >= server->smbd_conn->rdma_readwrite_threshold) {
struct smbd_buffer_descriptor_v1 *v1;
- bool need_invalidate =
- io_parms->tcon->ses->server->dialect == SMB30_PROT_ID;
+ bool need_invalidate = server->dialect == SMB30_PROT_ID;
rdata->mr = smbd_register_mr(
server->smbd_conn, rdata->pages,
@@ -3761,7 +3863,7 @@ smb2_readv_callback(struct mid_q_entry *mid)
{
struct cifs_readdata *rdata = mid->callback_data;
struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
- struct TCP_Server_Info *server = tcon->ses->server;
+ struct TCP_Server_Info *server = rdata->server;
struct smb2_sync_hdr *shdr =
(struct smb2_sync_hdr *)rdata->iov[0].iov_base;
struct cifs_credits credits = { .value = 0, .instance = 0 };
@@ -3773,6 +3875,10 @@ smb2_readv_callback(struct mid_q_entry *mid)
.rq_pagesz = rdata->pagesz,
.rq_tailsz = rdata->tailsz };
+ WARN_ONCE(rdata->server != mid->server,
+ "rdata server %p != mid server %p",
+ rdata->server, mid->server);
+
cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
__func__, mid->mid, mid->mid_state, rdata->result,
rdata->bytes);
@@ -3807,7 +3913,7 @@ smb2_readv_callback(struct mid_q_entry *mid)
case MID_RESPONSE_MALFORMED:
credits.value = le16_to_cpu(shdr->CreditRequest);
credits.instance = server->reconnect_instance;
- /* fall through */
+ fallthrough;
default:
rdata->result = -EIO;
}
@@ -3850,20 +3956,23 @@ smb2_async_readv(struct cifs_readdata *rdata)
struct smb_rqst rqst = { .rq_iov = rdata->iov,
.rq_nvec = 1 };
struct TCP_Server_Info *server;
+ struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
unsigned int total_len;
cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
__func__, rdata->offset, rdata->bytes);
+ if (!rdata->server)
+ rdata->server = cifs_pick_channel(tcon->ses);
+
io_parms.tcon = tlink_tcon(rdata->cfile->tlink);
+ io_parms.server = server = rdata->server;
io_parms.offset = rdata->offset;
io_parms.length = rdata->bytes;
io_parms.persistent_fid = rdata->cfile->fid.persistent_fid;
io_parms.volatile_fid = rdata->cfile->fid.volatile_fid;
io_parms.pid = rdata->pid;
- server = io_parms.tcon->ses->server;
-
rc = smb2_new_read_req(
(void **) &buf, &total_len, &io_parms, rdata, 0, 0);
if (rc)
@@ -3891,7 +4000,7 @@ smb2_async_readv(struct cifs_readdata *rdata)
}
kref_get(&rdata->refcount);
- rc = cifs_call_async(io_parms.tcon->ses->server, &rqst,
+ rc = cifs_call_async(server, &rqst,
cifs_readv_receive, smb2_readv_callback,
smb3_handle_read_data, rdata, flags,
&rdata->credits);
@@ -3923,6 +4032,9 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
int flags = CIFS_LOG_ERROR;
struct cifs_ses *ses = io_parms->tcon->ses;
+ if (!io_parms->server)
+ io_parms->server = cifs_pick_channel(io_parms->tcon->ses);
+
*nbytes = 0;
rc = smb2_new_read_req((void **)&req, &total_len, io_parms, NULL, 0, 0);
if (rc)
@@ -3938,7 +4050,8 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
rqst.rq_iov = iov;
rqst.rq_nvec = 1;
- rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
+ rc = cifs_send_recv(xid, ses, io_parms->server,
+ &rqst, &resp_buftype, flags, &rsp_iov);
rsp = (struct smb2_read_rsp *)rsp_iov.iov_base;
if (rc) {
@@ -3994,11 +4107,15 @@ smb2_writev_callback(struct mid_q_entry *mid)
{
struct cifs_writedata *wdata = mid->callback_data;
struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
- struct TCP_Server_Info *server = tcon->ses->server;
+ struct TCP_Server_Info *server = wdata->server;
unsigned int written;
struct smb2_write_rsp *rsp = (struct smb2_write_rsp *)mid->resp_buf;
struct cifs_credits credits = { .value = 0, .instance = 0 };
+ WARN_ONCE(wdata->server != mid->server,
+ "wdata server %p != mid server %p",
+ wdata->server, mid->server);
+
switch (mid->mid_state) {
case MID_RESPONSE_RECEIVED:
credits.value = le16_to_cpu(rsp->sync_hdr.CreditRequest);
@@ -4029,7 +4146,7 @@ smb2_writev_callback(struct mid_q_entry *mid)
case MID_RESPONSE_MALFORMED:
credits.value = le16_to_cpu(rsp->sync_hdr.CreditRequest);
credits.instance = server->reconnect_instance;
- /* fall through */
+ fallthrough;
default:
wdata->result = -EIO;
break;
@@ -4054,8 +4171,8 @@ smb2_writev_callback(struct mid_q_entry *mid)
tcon->tid, tcon->ses->Suid, wdata->offset,
wdata->bytes, wdata->result);
if (wdata->result == -ENOSPC)
- printk_once(KERN_WARNING "Out of space writing to %s\n",
- tcon->treeName);
+ pr_warn_once("Out of space writing to %s\n",
+ tcon->treeName);
} else
trace_smb3_write_done(0 /* no xid */,
wdata->cfile->fid.persistent_fid,
@@ -4076,12 +4193,16 @@ smb2_async_writev(struct cifs_writedata *wdata,
struct smb2_write_req *req = NULL;
struct smb2_sync_hdr *shdr;
struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
- struct TCP_Server_Info *server = tcon->ses->server;
+ struct TCP_Server_Info *server = wdata->server;
struct kvec iov[1];
struct smb_rqst rqst = { };
unsigned int total_len;
- rc = smb2_plain_req_init(SMB2_WRITE, tcon, (void **) &req, &total_len);
+ if (!wdata->server)
+ server = wdata->server = cifs_pick_channel(tcon->ses);
+
+ rc = smb2_plain_req_init(SMB2_WRITE, tcon, server,
+ (void **) &req, &total_len);
if (rc)
return rc;
@@ -4220,20 +4341,24 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
struct kvec rsp_iov;
int flags = 0;
unsigned int total_len;
+ struct TCP_Server_Info *server;
*nbytes = 0;
if (n_vec < 1)
return rc;
- rc = smb2_plain_req_init(SMB2_WRITE, io_parms->tcon, (void **) &req,
- &total_len);
+ if (!io_parms->server)
+ io_parms->server = cifs_pick_channel(io_parms->tcon->ses);
+ server = io_parms->server;
+ if (server == NULL)
+ return -ECONNABORTED;
+
+ rc = smb2_plain_req_init(SMB2_WRITE, io_parms->tcon, server,
+ (void **) &req, &total_len);
if (rc)
return rc;
- if (io_parms->tcon->ses->server == NULL)
- return -ECONNABORTED;
-
if (smb3_encryption_required(io_parms->tcon))
flags |= CIFS_TRANSFORM_REQ;
@@ -4262,7 +4387,8 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
rqst.rq_iov = iov;
rqst.rq_nvec = n_vec + 1;
- rc = cifs_send_recv(xid, io_parms->tcon->ses, &rqst,
+ rc = cifs_send_recv(xid, io_parms->tcon->ses, server,
+ &rqst,
&resp_buftype, flags, &rsp_iov);
rsp = (struct smb2_write_rsp *)rsp_iov.iov_base;
@@ -4286,8 +4412,104 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
return rc;
}
+int posix_info_sid_size(const void *beg, const void *end)
+{
+ size_t subauth;
+ int total;
+
+ if (beg + 1 > end)
+ return -1;
+
+ subauth = *(u8 *)(beg+1);
+ if (subauth < 1 || subauth > 15)
+ return -1;
+
+ total = 1 + 1 + 6 + 4*subauth;
+ if (beg + total > end)
+ return -1;
+
+ return total;
+}
+
+int posix_info_parse(const void *beg, const void *end,
+ struct smb2_posix_info_parsed *out)
+
+{
+ int total_len = 0;
+ int sid_len;
+ int name_len;
+ const void *owner_sid;
+ const void *group_sid;
+ const void *name;
+
+ /* if no end bound given, assume payload to be correct */
+ if (!end) {
+ const struct smb2_posix_info *p = beg;
+
+ end = beg + le32_to_cpu(p->NextEntryOffset);
+ /* last element will have a 0 offset, pick a sensible bound */
+ if (end == beg)
+ end += 0xFFFF;
+ }
+
+ /* check base buf */
+ if (beg + sizeof(struct smb2_posix_info) > end)
+ return -1;
+ total_len = sizeof(struct smb2_posix_info);
+
+ /* check owner sid */
+ owner_sid = beg + total_len;
+ sid_len = posix_info_sid_size(owner_sid, end);
+ if (sid_len < 0)
+ return -1;
+ total_len += sid_len;
+
+ /* check group sid */
+ group_sid = beg + total_len;
+ sid_len = posix_info_sid_size(group_sid, end);
+ if (sid_len < 0)
+ return -1;
+ total_len += sid_len;
+
+ /* check name len */
+ if (beg + total_len + 4 > end)
+ return -1;
+ name_len = le32_to_cpu(*(__le32 *)(beg + total_len));
+ if (name_len < 1 || name_len > 0xFFFF)
+ return -1;
+ total_len += 4;
+
+ /* check name */
+ name = beg + total_len;
+ if (name + name_len > end)
+ return -1;
+ total_len += name_len;
+
+ if (out) {
+ out->base = beg;
+ out->size = total_len;
+ out->name_len = name_len;
+ out->name = name;
+ memcpy(&out->owner, owner_sid,
+ posix_info_sid_size(owner_sid, end));
+ memcpy(&out->group, group_sid,
+ posix_info_sid_size(group_sid, end));
+ }
+ return total_len;
+}
+
+static int posix_info_extra_size(const void *beg, const void *end)
+{
+ int len = posix_info_parse(beg, end, NULL);
+
+ if (len < 0)
+ return -1;
+ return len - sizeof(struct smb2_posix_info);
+}
+
static unsigned int
-num_entries(char *bufstart, char *end_of_buf, char **lastentry, size_t size)
+num_entries(int infotype, char *bufstart, char *end_of_buf, char **lastentry,
+ size_t size)
{
int len;
unsigned int entrycount = 0;
@@ -4311,8 +4533,13 @@ num_entries(char *bufstart, char *end_of_buf, char **lastentry, size_t size)
entryptr = entryptr + next_offset;
dir_info = (FILE_DIRECTORY_INFO *)entryptr;
- len = le32_to_cpu(dir_info->FileNameLength);
- if (entryptr + len < entryptr ||
+ if (infotype == SMB_FIND_FILE_POSIX_INFO)
+ len = posix_info_extra_size(entryptr, end_of_buf);
+ else
+ len = le32_to_cpu(dir_info->FileNameLength);
+
+ if (len < 0 ||
+ entryptr + len < entryptr ||
entryptr + len > end_of_buf ||
entryptr + len + size > end_of_buf) {
cifs_dbg(VFS, "directory entry name would overflow frame end of buf %p\n",
@@ -4335,11 +4562,12 @@ num_entries(char *bufstart, char *end_of_buf, char **lastentry, size_t size)
* Readdir/FindFirst
*/
int SMB2_query_directory_init(const unsigned int xid,
- struct cifs_tcon *tcon, struct smb_rqst *rqst,
+ struct cifs_tcon *tcon,
+ struct TCP_Server_Info *server,
+ struct smb_rqst *rqst,
u64 persistent_fid, u64 volatile_fid,
int index, int info_level)
{
- struct TCP_Server_Info *server = tcon->ses->server;
struct smb2_query_directory_req *req;
unsigned char *bufptr;
__le16 asteriks = cpu_to_le16('*');
@@ -4350,8 +4578,8 @@ int SMB2_query_directory_init(const unsigned int xid,
struct kvec *iov = rqst->rq_iov;
int len, rc;
- rc = smb2_plain_req_init(SMB2_QUERY_DIRECTORY, tcon, (void **) &req,
- &total_len);
+ rc = smb2_plain_req_init(SMB2_QUERY_DIRECTORY, tcon, server,
+ (void **) &req, &total_len);
if (rc)
return rc;
@@ -4362,6 +4590,9 @@ int SMB2_query_directory_init(const unsigned int xid,
case SMB_FIND_FILE_ID_FULL_DIR_INFO:
req->FileInformationClass = FILEID_FULL_DIRECTORY_INFORMATION;
break;
+ case SMB_FIND_FILE_POSIX_INFO:
+ req->FileInformationClass = SMB_FIND_FILE_POSIX_INFO;
+ break;
default:
cifs_tcon_dbg(VFS, "info level %u isn't supported\n",
info_level);
@@ -4427,6 +4658,10 @@ smb2_parse_query_directory(struct cifs_tcon *tcon,
case SMB_FIND_FILE_ID_FULL_DIR_INFO:
info_buf_size = sizeof(SEARCH_ID_FULL_DIR_INFO) - 1;
break;
+ case SMB_FIND_FILE_POSIX_INFO:
+ /* note that posix payload are variable size */
+ info_buf_size = sizeof(struct smb2_posix_info);
+ break;
default:
cifs_tcon_dbg(VFS, "info level %u isn't supported\n",
srch_inf->info_level);
@@ -4436,8 +4671,10 @@ smb2_parse_query_directory(struct cifs_tcon *tcon,
rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset),
le32_to_cpu(rsp->OutputBufferLength), rsp_iov,
info_buf_size);
- if (rc)
+ if (rc) {
+ cifs_tcon_dbg(VFS, "bad info payload");
return rc;
+ }
srch_inf->unicode = true;
@@ -4451,9 +4688,14 @@ smb2_parse_query_directory(struct cifs_tcon *tcon,
srch_inf->srch_entries_start = srch_inf->last_entry =
(char *)rsp + le16_to_cpu(rsp->OutputBufferOffset);
end_of_smb = rsp_iov->iov_len + (char *)rsp;
- srch_inf->entries_in_buffer =
- num_entries(srch_inf->srch_entries_start, end_of_smb,
- &srch_inf->last_entry, info_buf_size);
+
+ srch_inf->entries_in_buffer = num_entries(
+ srch_inf->info_level,
+ srch_inf->srch_entries_start,
+ end_of_smb,
+ &srch_inf->last_entry,
+ info_buf_size);
+
srch_inf->index_of_last_entry += srch_inf->entries_in_buffer;
cifs_dbg(FYI, "num entries %d last_index %lld srch start %p srch end %p\n",
srch_inf->entries_in_buffer, srch_inf->index_of_last_entry,
@@ -4463,7 +4705,7 @@ smb2_parse_query_directory(struct cifs_tcon *tcon,
else if (resp_buftype == CIFS_SMALL_BUFFER)
srch_inf->smallBuf = true;
else
- cifs_tcon_dbg(VFS, "illegal search buffer type\n");
+ cifs_tcon_dbg(VFS, "Invalid search buffer type\n");
return 0;
}
@@ -4480,6 +4722,7 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
struct kvec rsp_iov;
int rc = 0;
struct cifs_ses *ses = tcon->ses;
+ struct TCP_Server_Info *server = cifs_pick_channel(ses);
int flags = 0;
if (!ses || !(ses->server))
@@ -4493,13 +4736,15 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
rqst.rq_iov = iov;
rqst.rq_nvec = SMB2_QUERY_DIRECTORY_IOV_SIZE;
- rc = SMB2_query_directory_init(xid, tcon, &rqst, persistent_fid,
+ rc = SMB2_query_directory_init(xid, tcon, server,
+ &rqst, persistent_fid,
volatile_fid, index,
srch_inf->info_level);
if (rc)
goto qdir_exit;
- rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
+ rc = cifs_send_recv(xid, ses, server,
+ &rqst, &resp_buftype, flags, &rsp_iov);
rsp = (struct smb2_query_directory_rsp *)rsp_iov.iov_base;
if (rc) {
@@ -4536,17 +4781,19 @@ qdir_exit:
}
int
-SMB2_set_info_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
- u64 persistent_fid, u64 volatile_fid, u32 pid, u8 info_class,
- u8 info_type, u32 additional_info,
- void **data, unsigned int *size)
+SMB2_set_info_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
+ struct smb_rqst *rqst,
+ u64 persistent_fid, u64 volatile_fid, u32 pid,
+ u8 info_class, u8 info_type, u32 additional_info,
+ void **data, unsigned int *size)
{
struct smb2_set_info_req *req;
struct kvec *iov = rqst->rq_iov;
unsigned int i, total_len;
int rc;
- rc = smb2_plain_req_init(SMB2_SET_INFO, tcon, (void **) &req, &total_len);
+ rc = smb2_plain_req_init(SMB2_SET_INFO, tcon, server,
+ (void **) &req, &total_len);
if (rc)
return rc;
@@ -4597,9 +4844,10 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
int rc = 0;
int resp_buftype;
struct cifs_ses *ses = tcon->ses;
+ struct TCP_Server_Info *server = cifs_pick_channel(ses);
int flags = 0;
- if (!ses || !(ses->server))
+ if (!ses || !server)
return -EIO;
if (!num)
@@ -4616,7 +4864,8 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
rqst.rq_iov = iov;
rqst.rq_nvec = num;
- rc = SMB2_set_info_init(tcon, &rqst, persistent_fid, volatile_fid, pid,
+ rc = SMB2_set_info_init(tcon, server,
+ &rqst, persistent_fid, volatile_fid, pid,
info_class, info_type, additional_info,
data, size);
if (rc) {
@@ -4625,7 +4874,8 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
}
- rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags,
+ rc = cifs_send_recv(xid, ses, server,
+ &rqst, &resp_buftype, flags,
&rsp_iov);
SMB2_set_info_free(&rqst);
rsp = (struct smb2_set_info_rsp *)rsp_iov.iov_base;
@@ -4688,6 +4938,7 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
int rc;
struct smb2_oplock_break *req = NULL;
struct cifs_ses *ses = tcon->ses;
+ struct TCP_Server_Info *server = cifs_pick_channel(ses);
int flags = CIFS_OBREAK_OP;
unsigned int total_len;
struct kvec iov[1];
@@ -4695,8 +4946,8 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
int resp_buf_type;
cifs_dbg(FYI, "SMB2_oplock_break\n");
- rc = smb2_plain_req_init(SMB2_OPLOCK_BREAK, tcon, (void **) &req,
- &total_len);
+ rc = smb2_plain_req_init(SMB2_OPLOCK_BREAK, tcon, server,
+ (void **) &req, &total_len);
if (rc)
return rc;
@@ -4717,7 +4968,8 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
rqst.rq_iov = iov;
rqst.rq_nvec = 1;
- rc = cifs_send_recv(xid, ses, &rqst, &resp_buf_type, flags, &rsp_iov);
+ rc = cifs_send_recv(xid, ses, server,
+ &rqst, &resp_buf_type, flags, &rsp_iov);
cifs_small_buf_release(req);
if (rc) {
@@ -4760,8 +5012,10 @@ copy_posix_fs_info_to_kstatfs(FILE_SYSTEM_POSIX_INFO *response_data,
}
static int
-build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level,
- int outbuf_len, u64 persistent_fid, u64 volatile_fid)
+build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon,
+ struct TCP_Server_Info *server,
+ int level, int outbuf_len, u64 persistent_fid,
+ u64 volatile_fid)
{
int rc;
struct smb2_query_info_req *req;
@@ -4769,11 +5023,11 @@ build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level,
cifs_dbg(FYI, "Query FSInfo level %d\n", level);
- if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
+ if ((tcon->ses == NULL) || server == NULL)
return -EIO;
- rc = smb2_plain_req_init(SMB2_QUERY_INFO, tcon, (void **) &req,
- &total_len);
+ rc = smb2_plain_req_init(SMB2_QUERY_INFO, tcon, server,
+ (void **) &req, &total_len);
if (rc)
return rc;
@@ -4803,10 +5057,12 @@ SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon,
int rc = 0;
int resp_buftype;
struct cifs_ses *ses = tcon->ses;
+ struct TCP_Server_Info *server = cifs_pick_channel(ses);
FILE_SYSTEM_POSIX_INFO *info = NULL;
int flags = 0;
- rc = build_qfs_info_req(&iov, tcon, FS_POSIX_INFORMATION,
+ rc = build_qfs_info_req(&iov, tcon, server,
+ FS_POSIX_INFORMATION,
sizeof(FILE_SYSTEM_POSIX_INFO),
persistent_fid, volatile_fid);
if (rc)
@@ -4819,7 +5075,8 @@ SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon,
rqst.rq_iov = &iov;
rqst.rq_nvec = 1;
- rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
+ rc = cifs_send_recv(xid, ses, server,
+ &rqst, &resp_buftype, flags, &rsp_iov);
cifs_small_buf_release(iov.iov_base);
if (rc) {
cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
@@ -4851,10 +5108,12 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
int rc = 0;
int resp_buftype;
struct cifs_ses *ses = tcon->ses;
+ struct TCP_Server_Info *server = cifs_pick_channel(ses);
struct smb2_fs_full_size_info *info = NULL;
int flags = 0;
- rc = build_qfs_info_req(&iov, tcon, FS_FULL_SIZE_INFORMATION,
+ rc = build_qfs_info_req(&iov, tcon, server,
+ FS_FULL_SIZE_INFORMATION,
sizeof(struct smb2_fs_full_size_info),
persistent_fid, volatile_fid);
if (rc)
@@ -4867,7 +5126,8 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
rqst.rq_iov = &iov;
rqst.rq_nvec = 1;
- rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
+ rc = cifs_send_recv(xid, ses, server,
+ &rqst, &resp_buftype, flags, &rsp_iov);
cifs_small_buf_release(iov.iov_base);
if (rc) {
cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
@@ -4899,6 +5159,7 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
int rc = 0;
int resp_buftype, max_len, min_len;
struct cifs_ses *ses = tcon->ses;
+ struct TCP_Server_Info *server = cifs_pick_channel(ses);
unsigned int rsp_len, offset;
int flags = 0;
@@ -4919,7 +5180,8 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
return -EINVAL;
}
- rc = build_qfs_info_req(&iov, tcon, level, max_len,
+ rc = build_qfs_info_req(&iov, tcon, server,
+ level, max_len,
persistent_fid, volatile_fid);
if (rc)
return rc;
@@ -4931,7 +5193,8 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
rqst.rq_iov = &iov;
rqst.rq_nvec = 1;
- rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
+ rc = cifs_send_recv(xid, ses, server,
+ &rqst, &resp_buftype, flags, &rsp_iov);
cifs_small_buf_release(iov.iov_base);
if (rc) {
cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
@@ -4984,10 +5247,12 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
unsigned int count;
int flags = CIFS_NO_RSP_BUF;
unsigned int total_len;
+ struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses);
cifs_dbg(FYI, "smb2_lockv num lock %d\n", num_lock);
- rc = smb2_plain_req_init(SMB2_LOCK, tcon, (void **) &req, &total_len);
+ rc = smb2_plain_req_init(SMB2_LOCK, tcon, server,
+ (void **) &req, &total_len);
if (rc)
return rc;
@@ -5013,7 +5278,8 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
rqst.rq_iov = iov;
rqst.rq_nvec = 2;
- rc = cifs_send_recv(xid, tcon->ses, &rqst, &resp_buf_type, flags,
+ rc = cifs_send_recv(xid, tcon->ses, server,
+ &rqst, &resp_buf_type, flags,
&rsp_iov);
cifs_small_buf_release(req);
if (rc) {
@@ -5058,10 +5324,11 @@ SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon,
int resp_buf_type;
__u64 *please_key_high;
__u64 *please_key_low;
+ struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses);
cifs_dbg(FYI, "SMB2_lease_break\n");
- rc = smb2_plain_req_init(SMB2_OPLOCK_BREAK, tcon, (void **) &req,
- &total_len);
+ rc = smb2_plain_req_init(SMB2_OPLOCK_BREAK, tcon, server,
+ (void **) &req, &total_len);
if (rc)
return rc;
@@ -5084,7 +5351,8 @@ SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon,
rqst.rq_iov = iov;
rqst.rq_nvec = 1;
- rc = cifs_send_recv(xid, ses, &rqst, &resp_buf_type, flags, &rsp_iov);
+ rc = cifs_send_recv(xid, ses, server,
+ &rqst, &resp_buf_type, flags, &rsp_iov);
cifs_small_buf_release(req);
please_key_low = (__u64 *)lease_key;