smb2_dispatch.c revision adb064afeb48ec687de5e8bd683ac74fbe19d656
1a90cf9fGordon Ross/*
2a90cf9fGordon Ross * This file and its contents are supplied under the terms of the
3a90cf9fGordon Ross * Common Development and Distribution License ("CDDL"), version 1.0.
4a90cf9fGordon Ross * You may only use this file in accordance with the terms of version
5a90cf9fGordon Ross * 1.0 of the CDDL.
6a90cf9fGordon Ross *
7a90cf9fGordon Ross * A full copy of the text of the CDDL should have accompanied this
8a90cf9fGordon Ross * source.  A copy of the CDDL is also available via the Internet at
9a90cf9fGordon Ross *
10a90cf9fGordon Ross */
11a90cf9fGordon Ross
12a90cf9fGordon Ross/*
13a90cf9fGordon Ross * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
14a90cf9fGordon Ross */
15a90cf9fGordon Ross
16a90cf9fGordon Ross
17a90cf9fGordon Ross#include <smbsrv/smb2_kproto.h>
18a90cf9fGordon Ross#include <smbsrv/smb_kstat.h>
19a90cf9fGordon Ross#include <smbsrv/smb2.h>
20a90cf9fGordon Ross
21a90cf9fGordon Ross/*
22a90cf9fGordon Ross * Saved state for a command that "goes async".  When a compound request
23a90cf9fGordon Ross * contains a command that may block indefinitely, the compound reply is
24a90cf9fGordon Ross * composed with an "interim response" for that command, and information
25a90cf9fGordon Ross * needed to actually dispatch that command is saved on a list of "async"
26a90cf9fGordon Ross * commands for this compound request.  After the compound reply is sent,
27a90cf9fGordon Ross * the list of async commands is processed, and those may block as long
28a90cf9fGordon Ross * as they need to without affecting the initial compound request.
29a90cf9fGordon Ross *
30a90cf9fGordon Ross * Now interestingly, this "async" mechanism is not used with the full
31a90cf9fGordon Ross * range of asynchrony that one might imagine.  The design of async
32a90cf9fGordon Ross * request processing can be drastically simplified if we can assume
33a90cf9fGordon Ross * that there's no need to run more than one async command at a time.
34a90cf9fGordon Ross * With that simplifying assumption, we can continue using the current
35a90cf9fGordon Ross * "one worker thread per request message" model, which has very simple
36a90cf9fGordon Ross * locking rules etc.  The same worker thread that handles the initial
37a90cf9fGordon Ross * compound request can handle the list of async requests.
38a90cf9fGordon Ross *
39a90cf9fGordon Ross * As it turns out, SMB2 clients do not try to use more than one "async"
40a90cf9fGordon Ross * command in a compound.  If they were to do so, the [MS-SMB2] spec.
41a90cf9fGordon Ross * allows us to decline additional async requests with an error.
42a90cf9fGordon Ross *
43a90cf9fGordon Ross * smb_async_req_t is the struct used to save an "async" request on
44a90cf9fGordon Ross * the list of requests that had an interim reply in the initial
45a90cf9fGordon Ross * compound reply.  This includes everything needed to restart
46a90cf9fGordon Ross * processing at the async command.
47a90cf9fGordon Ross */
48a90cf9fGordon Ross
49a90cf9fGordon Rosstypedef struct smb2_async_req {
50a90cf9fGordon Ross
51a90cf9fGordon Ross	smb_sdrc_t		(*ar_func)(smb_request_t *);
52a90cf9fGordon Ross
53a90cf9fGordon Ross	int ar_cmd_hdr;		/* smb2_cmd_hdr offset */
54a90cf9fGordon Ross	int ar_cmd_len;		/* length from hdr */
55a90cf9fGordon Ross
56a90cf9fGordon Ross	/*
57a90cf9fGordon Ross	 * SMB2 header fields.
58a90cf9fGordon Ross	 */
59a90cf9fGordon Ross	uint16_t		ar_cmd_code;
60a90cf9fGordon Ross	uint16_t		ar_uid;
61a90cf9fGordon Ross	uint16_t		ar_tid;
62a90cf9fGordon Ross	uint32_t		ar_pid;
63a90cf9fGordon Ross	uint32_t		ar_hdr_flags;
64a90cf9fGordon Ross	uint64_t		ar_messageid;
65a90cf9fGordon Ross} smb2_async_req_t;
66a90cf9fGordon Ross
67a90cf9fGordon Rossvoid smb2sr_do_async(smb_request_t *);
68a90cf9fGordon Rosssmb_sdrc_t smb2_invalid_cmd(smb_request_t *);
69a90cf9fGordon Rossstatic void smb2_tq_work(void *);
70a90cf9fGordon Ross
71adb064aToomas Soomestatic const smb_disp_entry_t
72a90cf9fGordon Rosssmb2_disp_table[SMB2__NCMDS] = {
73a90cf9fGordon Ross
74a90cf9fGordon Ross	/* text-name, pre, func, post, cmd-code, dialect, flags */
75a90cf9fGordon Ross
76a90cf9fGordon Ross	{  "smb2_negotiate", NULL,
77a90cf9fGordon Ross	    smb2_negotiate, NULL, 0, 0,
78a90cf9fGordon Ross	    SDDF_SUPPRESS_TID | SDDF_SUPPRESS_UID },
79a90cf9fGordon Ross
80a90cf9fGordon Ross	{  "smb2_session_setup", NULL,
81a90cf9fGordon Ross	    smb2_session_setup, NULL, 0, 0,
82a90cf9fGordon Ross	    SDDF_SUPPRESS_TID | SDDF_SUPPRESS_UID },
83a90cf9fGordon Ross
84a90cf9fGordon Ross	{  "smb2_logoff", NULL,
85a90cf9fGordon Ross	    smb2_logoff, NULL, 0, 0,
86a90cf9fGordon Ross	    SDDF_SUPPRESS_TID },
87a90cf9fGordon Ross
88a90cf9fGordon Ross	{  "smb2_tree_connect", NULL,
89a90cf9fGordon Ross	    smb2_tree_connect, NULL, 0, 0,
90a90cf9fGordon Ross	    SDDF_SUPPRESS_TID },
91a90cf9fGordon Ross
92a90cf9fGordon Ross	{  "smb2_tree_disconn", NULL,
93a90cf9fGordon Ross	    smb2_tree_disconn, NULL, 0, 0 },
94a90cf9fGordon Ross
95a90cf9fGordon Ross	{  "smb2_create", NULL,
96a90cf9fGordon Ross	    smb2_create, NULL, 0, 0 },
97a90cf9fGordon Ross
98a90cf9fGordon Ross	{  "smb2_close", NULL,
99a90cf9fGordon Ross	    smb2_close, NULL, 0, 0 },
100a90cf9fGordon Ross
101a90cf9fGordon Ross	{  "smb2_flush", NULL,
102a90cf9fGordon Ross	    smb2_flush, NULL, 0, 0 },
103a90cf9fGordon Ross
104a90cf9fGordon Ross	{  "smb2_read", NULL,
105a90cf9fGordon Ross	    smb2_read, NULL, 0, 0 },
106a90cf9fGordon Ross
107a90cf9fGordon Ross	{  "smb2_write", NULL,
108a90cf9fGordon Ross	    smb2_write, NULL, 0, 0 },
109a90cf9fGordon Ross
110a90cf9fGordon Ross	{  "smb2_lock", NULL,
111a90cf9fGordon Ross	    smb2_lock, NULL, 0, 0 },
112a90cf9fGordon Ross
113a90cf9fGordon Ross	{  "smb2_ioctl", NULL,
114a90cf9fGordon Ross	    smb2_ioctl, NULL, 0, 0 },
115a90cf9fGordon Ross
116a90cf9fGordon Ross	/*
117a90cf9fGordon Ross	 * Note: Cancel gets the "invalid command" handler because
118a90cf9fGordon Ross	 * that's always handled directly in the reader.  We should
119a90cf9fGordon Ross	 * never get to the function using this table, but note:
120a90cf9fGordon Ross	 * We CAN get here if a nasty client adds cancel to some
121a90cf9fGordon Ross	 * compound message, which is a protocol violation.
122a90cf9fGordon Ross	 */
123a90cf9fGordon Ross	{  "smb2_cancel", NULL,
124a90cf9fGordon Ross	    smb2_invalid_cmd, NULL, 0, 0 },
125a90cf9fGordon Ross
126a90cf9fGordon Ross	{  "smb2_echo", NULL,
127a90cf9fGordon Ross	    smb2_echo, NULL, 0, 0,
128a90cf9fGordon Ross	    SDDF_SUPPRESS_UID | SDDF_SUPPRESS_TID },
129a90cf9fGordon Ross
130a90cf9fGordon Ross	{  "smb2_query_dir", NULL,
131a90cf9fGordon Ross	    smb2_query_dir, NULL, 0, 0 },
132a90cf9fGordon Ross
133a90cf9fGordon Ross	{  "smb2_change_notify", NULL,
134a90cf9fGordon Ross	    smb2_change_notify, NULL, 0, 0 },
135a90cf9fGordon Ross
136a90cf9fGordon Ross	{  "smb2_query_info", NULL,
137a90cf9fGordon Ross	    smb2_query_info, NULL, 0, 0 },
138a90cf9fGordon Ross
139a90cf9fGordon Ross	{  "smb2_set_info", NULL,
140a90cf9fGordon Ross	    smb2_set_info, NULL, 0, 0 },
141a90cf9fGordon Ross
142a90cf9fGordon Ross	{  "smb2_oplock_break_ack", NULL,
143a90cf9fGordon Ross	    smb2_oplock_break_ack, NULL, 0, 0 },
144a90cf9fGordon Ross
145a90cf9fGordon Ross	{  "smb2_invalid_cmd", NULL,
146a90cf9fGordon Ross	    smb2_invalid_cmd, NULL, 0, 0,
147a90cf9fGordon Ross	    SDDF_SUPPRESS_UID | SDDF_SUPPRESS_TID },
148a90cf9fGordon Ross};
149a90cf9fGordon Ross
150a90cf9fGordon Rosssmb_sdrc_t
151a90cf9fGordon Rosssmb2_invalid_cmd(smb_request_t *sr)
152a90cf9fGordon Ross{
153a90cf9fGordon Ross#ifdef	DEBUG
154a90cf9fGordon Ross	cmn_err(CE_NOTE, "clnt %s bad SMB2 cmd code",
155a90cf9fGordon Ross	    sr->session->ip_addr_str);
156a90cf9fGordon Ross#endif
157a90cf9fGordon Ross	sr->smb2_status = NT_STATUS_INVALID_PARAMETER;
158a90cf9fGordon Ross	return (SDRC_DROP_VC);
159a90cf9fGordon Ross}
160a90cf9fGordon Ross
161a90cf9fGordon Ross/*
162a90cf9fGordon Ross * This is the SMB2 handler for new smb requests, called from
163a90cf9fGordon Ross * smb_session_reader after SMB negotiate is done.  For most SMB2
164a90cf9fGordon Ross * requests, we just enqueue them for the smb_session_worker to
165a90cf9fGordon Ross * execute via the task queue, so they can block for resources
166a90cf9fGordon Ross * without stopping the reader thread.  A few protocol messages
167a90cf9fGordon Ross * are special cases and are handled directly here in the reader
168a90cf9fGordon Ross * thread so they don't wait for taskq scheduling.
169a90cf9fGordon Ross *
170a90cf9fGordon Ross * This function must either enqueue the new request for
171a90cf9fGordon Ross * execution via the task queue, or execute it directly
172a90cf9fGordon Ross * and then free it.  If this returns non-zero, the caller
173a90cf9fGordon Ross * will drop the session.
174a90cf9fGordon Ross */
175a90cf9fGordon Rossint
176a90cf9fGordon Rosssmb2sr_newrq(smb_request_t *sr)
177a90cf9fGordon Ross{
178a90cf9fGordon Ross	uint32_t magic;
179a90cf9fGordon Ross	uint16_t command;
180a90cf9fGordon Ross	int rc;
181a90cf9fGordon Ross
182a90cf9fGordon Ross	magic = LE_IN32(sr->sr_request_buf);
183a90cf9fGordon Ross	if (magic != SMB2_PROTOCOL_MAGIC) {
184a90cf9fGordon Ross		smb_request_free(sr);
185a90cf9fGordon Ross		/* will drop the connection */
186a90cf9fGordon Ross		return (EPROTO);
187a90cf9fGordon Ross	}
188a90cf9fGordon Ross
189a90cf9fGordon Ross	/*
190a90cf9fGordon Ross	 * Execute Cancel requests immediately, (here in the
191a90cf9fGordon Ross	 * reader thread) so they won't wait for any other
192a90cf9fGordon Ross	 * commands we might already have in the task queue.
193a90cf9fGordon Ross	 * Cancel also skips signature verification and
194a90cf9fGordon Ross	 * does not consume a sequence number.
195a90cf9fGordon Ross	 * [MS-SMB2] Cancellation...
196a90cf9fGordon Ross	 */
197a90cf9fGordon Ross	command = LE_IN16((uint8_t *)sr->sr_request_buf + 12);
198a90cf9fGordon Ross	if (command == SMB2_CANCEL) {
199a90cf9fGordon Ross		rc = smb2sr_newrq_cancel(sr);
200a90cf9fGordon Ross		smb_request_free(sr);
201a90cf9fGordon Ross		return (rc);
202a90cf9fGordon Ross	}
203a90cf9fGordon Ross
204a90cf9fGordon Ross	/*
205a90cf9fGordon Ross	 * Submit the request to the task queue, which calls
206a90cf9fGordon Ross	 * smb2_tq_work when the workload permits.
207a90cf9fGordon Ross	 */
208a90cf9fGordon Ross	sr->sr_time_submitted = gethrtime();
209a90cf9fGordon Ross	sr->sr_state = SMB_REQ_STATE_SUBMITTED;
210a90cf9fGordon Ross	smb_srqueue_waitq_enter(sr->session->s_srqueue);
211a90cf9fGordon Ross	(void) taskq_dispatch(sr->sr_server->sv_worker_pool,
212a90cf9fGordon Ross	    smb2_tq_work, sr, TQ_SLEEP);
213a90cf9fGordon Ross
214a90cf9fGordon Ross	return (0);
215a90cf9fGordon Ross}
216a90cf9fGordon Ross
217a90cf9fGordon Rossstatic void
218a90cf9fGordon Rosssmb2_tq_work(void *arg)
219a90cf9fGordon Ross{
220a90cf9fGordon Ross	smb_request_t	*sr;
221a90cf9fGordon Ross	smb_srqueue_t	*srq;
222a90cf9fGordon Ross
223a90cf9fGordon Ross	sr = (smb_request_t *)arg;
224a90cf9fGordon Ross	SMB_REQ_VALID(sr);
225a90cf9fGordon Ross
226a90cf9fGordon Ross	srq = sr->session->s_srqueue;
227a90cf9fGordon Ross	smb_srqueue_waitq_to_runq(srq);
228a90cf9fGordon Ross	sr->sr_worker = curthread;
229a90cf9fGordon Ross	sr->sr_time_active = gethrtime();
230a90cf9fGordon Ross
231a90cf9fGordon Ross	/*
232a90cf9fGordon Ross	 * In contrast with SMB1, SMB2 must _always_ dispatch to
233a90cf9fGordon Ross	 * the handler function, because cancelled requests need
234a90cf9fGordon Ross	 * an error reply (NT_STATUS_CANCELLED).
235a90cf9fGordon Ross	 */
236a90cf9fGordon Ross	smb2sr_work(sr);
237a90cf9fGordon Ross
238a90cf9fGordon Ross	smb_srqueue_runq_exit(srq);
239a90cf9fGordon Ross}
240a90cf9fGordon Ross
241a90cf9fGordon Ross/*
242a90cf9fGordon Ross * smb2sr_work
243a90cf9fGordon Ross *
244a90cf9fGordon Ross * This function processes each SMB command in the current request
245a90cf9fGordon Ross * (which may be a compound request) building a reply containing
246a90cf9fGordon Ross * SMB reply messages, one-to-one with the SMB commands.  Some SMB
247a90cf9fGordon Ross * commands (change notify, blocking locks) may require both an
248a90cf9fGordon Ross * "interim response" and a later "async response" at completion.
249a90cf9fGordon Ross * In such cases, we'll encode the interim response in the reply
250a90cf9fGordon Ross * compound we're building, and put the (now async) command on a
251a90cf9fGordon Ross * list of commands that need further processing.  After we've
252a90cf9fGordon Ross * finished processing the commands in this compound and building
253a90cf9fGordon Ross * the compound reply, we'll send the compound reply, and finally
254a90cf9fGordon Ross * process the list of async commands.
255a90cf9fGordon Ross *
256a90cf9fGordon Ross * As we work our way through the compound request and reply,
257a90cf9fGordon Ross * we need to keep track of the bounds of the current request
258a90cf9fGordon Ross * and reply.  For the request, this uses an MBC_SHADOW_CHAIN
259a90cf9fGordon Ross * that begins at smb2_cmd_hdr.  The reply is appended to the
260a90cf9fGordon Ross * sr->reply chain starting at smb2_reply_hdr.
261a90cf9fGordon Ross *
262a90cf9fGordon Ross * This function must always free the smb request.
263a90cf9fGordon Ross */
264a90cf9fGordon Rossvoid
265a90cf9fGordon Rosssmb2sr_work(struct smb_request *sr)
266a90cf9fGordon Ross{
267a90cf9fGordon Ross	const smb_disp_entry_t	*sdd;
268a90cf9fGordon Ross	smb_disp_stats_t	*sds;
269a90cf9fGordon Ross	smb_session_t		*session;
270a90cf9fGordon Ross	uint32_t		msg_len;
271a90cf9fGordon Ross	uint16_t		cmd_idx;
272a90cf9fGordon Ross	int			rc = 0;
273a90cf9fGordon Ross	boolean_t		disconnect = B_FALSE;
274a90cf9fGordon Ross	boolean_t		related;
275a90cf9fGordon Ross
276a90cf9fGordon Ross	session = sr->session;
277a90cf9fGordon Ross
278a90cf9fGordon Ross	ASSERT(sr->tid_tree == 0);
279a90cf9fGordon Ross	ASSERT(sr->uid_user == 0);
280a90cf9fGordon Ross	ASSERT(sr->fid_ofile == 0);
281a90cf9fGordon Ross	sr->smb_fid = (uint16_t)-1;
282a90cf9fGordon Ross	sr->smb2_status = 0;
283a90cf9fGordon Ross
284a90cf9fGordon Ross	/* temporary until we identify a user */
285a90cf9fGordon Ross	sr->user_cr = zone_kcred();
286a90cf9fGordon Ross
287a90cf9fGordon Ross	mutex_enter(&sr->sr_mutex);
288a90cf9fGordon Ross	switch (sr->sr_state) {
289a90cf9fGordon Ross	case SMB_REQ_STATE_SUBMITTED:
290a90cf9fGordon Ross	case SMB_REQ_STATE_CLEANED_UP:
291a90cf9fGordon Ross		sr->sr_state = SMB_REQ_STATE_ACTIVE;
292a90cf9fGordon Ross		break;
293a90cf9fGordon Ross	default:
294a90cf9fGordon Ross		ASSERT(0);
295a90cf9fGordon Ross		/* FALLTHROUGH */
296a90cf9fGordon Ross	case SMB_REQ_STATE_CANCELED:
297a90cf9fGordon Ross		sr->smb2_status = NT_STATUS_CANCELLED;
298a90cf9fGordon Ross		break;
299a90cf9fGordon Ross	}
300a90cf9fGordon Ross	mutex_exit(&sr->sr_mutex);
301a90cf9fGordon Ross
302a90cf9fGordon Rosscmd_start:
303a90cf9fGordon Ross	/*
304a90cf9fGordon Ross	 * Decode the request header
305a90cf9fGordon Ross	 *
306a90cf9fGordon Ross	 * Most problems with decoding will result in the error
307a90cf9fGordon Ross	 * STATUS_INVALID_PARAMETER.  If the decoding problem
308a90cf9fGordon Ross	 * prevents continuing, we'll close the connection.
309a90cf9fGordon Ross	 * [MS-SMB2] Handling Incorrectly Formatted...
310a90cf9fGordon Ross	 *
311a90cf9fGordon Ross	 * We treat some status codes as if "sticky", meaning
312a90cf9fGordon Ross	 * once they're set after some command handler returns,
313a90cf9fGordon Ross	 * all remaining commands get this status without even
314a90cf9fGordon Ross	 * calling the command-specific handler. The cancelled
315a90cf9fGordon Ross	 * status is used above, and insufficient_resources is
316a90cf9fGordon Ross	 * used when smb2sr_go_async declines to "go async".
317a90cf9fGordon Ross	 * Otherwise initialize to zero (success).
318a90cf9fGordon Ross	 */
319a90cf9fGordon Ross	if (sr->smb2_status != NT_STATUS_CANCELLED &&
320a90cf9fGordon Ross	    sr->smb2_status != NT_STATUS_INSUFFICIENT_RESOURCES)
321a90cf9fGordon Ross		sr->smb2_status = 0;
322a90cf9fGordon Ross
323a90cf9fGordon Ross	sr->smb2_cmd_hdr = sr->command.chain_offset;
324a90cf9fGordon Ross	if ((rc = smb2_decode_header(sr)) != 0) {
325a90cf9fGordon Ross		cmn_err(CE_WARN, "clnt %s bad SMB2 header",
326a90cf9fGordon Ross		    session->ip_addr_str);
327a90cf9fGordon Ross		disconnect = B_TRUE;
328a90cf9fGordon Ross		goto cleanup;
329a90cf9fGordon Ross	}
330a90cf9fGordon Ross
331a90cf9fGordon Ross	/*
332a90cf9fGordon Ross	 * The SMB2_FLAGS_SERVER_TO_REDIR should only appear
333a90cf9fGordon Ross	 * in messages from the server back to the client.
334a90cf9fGordon Ross	 */
335a90cf9fGordon Ross	if ((sr->smb2_hdr_flags & SMB2_FLAGS_SERVER_TO_REDIR) != 0) {
336a90cf9fGordon Ross		cmn_err(CE_WARN, "clnt %s bad SMB2 flags",
337a90cf9fGordon Ross		    session->ip_addr_str);
338a90cf9fGordon Ross		disconnect = B_TRUE;
339a90cf9fGordon Ross		goto cleanup;
340a90cf9fGordon Ross	}
341a90cf9fGordon Ross	related = (sr->smb2_hdr_flags & SMB2_FLAGS_RELATED_OPERATIONS);
342a90cf9fGordon Ross
343a90cf9fGordon Ross	/*
344a90cf9fGordon Ross	 * In case we bail out with an error before we get to the
345a90cf9fGordon Ross	 * section that computes the credit grant, initialize the
346a90cf9fGordon Ross	 * response header fields so that credits won't change.
347a90cf9fGordon Ross	 * Note: SMB 2.02 clients may send credit charge zero.
348a90cf9fGordon Ross	 */
349a90cf9fGordon Ross	if (sr->smb2_credit_charge == 0)
350a90cf9fGordon Ross		sr->smb2_credit_charge = 1;
351a90cf9fGordon Ross	sr->smb2_credit_response = sr->smb2_credit_charge;
352a90cf9fGordon Ross
353a90cf9fGordon Ross	/*
354a90cf9fGordon Ross	 * Reserve space for the reply header, and save the offset.
355a90cf9fGordon Ross	 * The reply header will be overwritten later.  If we have
356a90cf9fGordon Ross	 * already exhausted the output space, then this client is
357a90cf9fGordon Ross	 * trying something funny.  Log it and kill 'em.
358a90cf9fGordon Ross	 */
359a90cf9fGordon Ross	sr->smb2_reply_hdr = sr->reply.chain_offset;
360a90cf9fGordon Ross	if ((rc = smb2_encode_header(sr, B_FALSE)) != 0) {
361a90cf9fGordon Ross		cmn_err(CE_WARN, "clnt %s excessive reply",
362a90cf9fGordon Ross		    session->ip_addr_str);
363a90cf9fGordon Ross		disconnect = B_TRUE;
364a90cf9fGordon Ross		goto cleanup;
365a90cf9fGordon Ross	}
366a90cf9fGordon Ross
367a90cf9fGordon Ross	/*
368a90cf9fGordon Ross	 * Figure out the length of data following the SMB2 header.
369a90cf9fGordon Ross	 * It ends at either the next SMB2 header if there is one
370a90cf9fGordon Ross	 * (smb2_next_command != 0) or at the end of the message.
371a90cf9fGordon Ross	 */
372a90cf9fGordon Ross	if (sr->smb2_next_command != 0) {
373a90cf9fGordon Ross		/* [MS-SMB2] says this is 8-byte aligned */
374a90cf9fGordon Ross		msg_len = sr->smb2_next_command;
375a90cf9fGordon Ross		if ((msg_len & 7) != 0 || (msg_len < SMB2_HDR_SIZE) ||
376a90cf9fGordon Ross		    ((sr->smb2_cmd_hdr + msg_len) > sr->command.max_bytes)) {
377a90cf9fGordon Ross			cmn_err(CE_WARN, "clnt %s bad SMB2 next cmd",
378a90cf9fGordon Ross			    session->ip_addr_str);
379a90cf9fGordon Ross			disconnect = B_TRUE;
380a90cf9fGordon Ross			goto cleanup;
381a90cf9fGordon Ross		}
382a90cf9fGordon Ross	} else {
383a90cf9fGordon Ross		msg_len = sr->command.max_bytes - sr->smb2_cmd_hdr;
384a90cf9fGordon Ross	}
385a90cf9fGordon Ross
386a90cf9fGordon Ross	/*
387a90cf9fGordon Ross	 * Setup a shadow chain for this SMB2 command, starting
388a90cf9fGordon Ross	 * with the header and ending at either the next command
389a90cf9fGordon Ross	 * or the end of the message.  The signing check below
390a90cf9fGordon Ross	 * needs the entire SMB2 command.  After that's done, we
391a90cf9fGordon Ross	 * advance chain_offset to the end of the header where
392a90cf9fGordon Ross	 * the command specific handlers continue decoding.
393a90cf9fGordon Ross	 */
394a90cf9fGordon Ross	(void) MBC_SHADOW_CHAIN(&sr->smb_data, &sr->command,
395a90cf9fGordon Ross	    sr->smb2_cmd_hdr, msg_len);
396a90cf9fGordon Ross
397a90cf9fGordon Ross	/*
398a90cf9fGordon Ross	 * Validate the commmand code, get dispatch table entries.
399a90cf9fGordon Ross	 * [MS-SMB2] Handling Incorrectly Formatted...
400a90cf9fGordon Ross	 *
401a90cf9fGordon Ross	 * The last slot in the dispatch table is used to handle
402a90cf9fGordon Ross	 * invalid commands.  Same for statistics.
403a90cf9fGordon Ross	 */
404a90cf9fGordon Ross	if (sr->smb2_cmd_code < SMB2_INVALID_CMD)
405a90cf9fGordon Ross		cmd_idx = sr->smb2_cmd_code;
406a90cf9fGordon Ross	else
407a90cf9fGordon Ross		cmd_idx = SMB2_INVALID_CMD;
408a90cf9fGordon Ross	sdd = &smb2_disp_table[cmd_idx];
409a90cf9fGordon Ross	sds = &session->s_server->sv_disp_stats2[cmd_idx];
410a90cf9fGordon Ross
411a90cf9fGordon Ross	/*
412a90cf9fGordon Ross	 * If this command is NOT "related" to the previous,
413a90cf9fGordon Ross	 * clear out the UID, TID, FID state that might be
414a90cf9fGordon Ross	 * left over from the previous command.
415a90cf9fGordon Ross	 *
416a90cf9fGordon Ross	 * If the command IS related, any new IDs are ignored,
417a90cf9fGordon Ross	 * and we simply continue with the previous user, tree,
418a90cf9fGordon Ross	 * and open file.
419a90cf9fGordon Ross	 */
420a90cf9fGordon Ross	if (!related) {
421a90cf9fGordon Ross		/*
422a90cf9fGordon Ross		 * Drop user, tree, file; carefully ordered to
423a90cf9fGordon Ross		 * avoid dangling references: file, tree, user
424a90cf9fGordon Ross		 */
425a90cf9fGordon Ross		if (sr->fid_ofile != NULL) {
426a90cf9fGordon Ross			smb_ofile_request_complete(sr->fid_ofile);
427a90cf9fGordon Ross			smb_ofile_release(sr->fid_ofile);
428a90cf9fGordon Ross			sr->fid_ofile = NULL;
429a90cf9fGordon Ross		}
430a90cf9fGordon Ross		if (sr->tid_tree != NULL) {
431a90cf9fGordon Ross			smb_tree_release(sr->tid_tree);
432a90cf9fGordon Ross			sr->tid_tree = NULL;
433a90cf9fGordon Ross		}
434a90cf9fGordon Ross		if (sr->uid_user != NULL) {
435a90cf9fGordon Ross			smb_user_release(sr->uid_user);
436a90cf9fGordon Ross			sr->uid_user = NULL;
437a90cf9fGordon Ross			sr->user_cr = zone_kcred();
438a90cf9fGordon Ross		}
439a90cf9fGordon Ross	}
440a90cf9fGordon Ross
441a90cf9fGordon Ross	/*
442a90cf9fGordon Ross	 * Make sure we have a user and tree as needed
443a90cf9fGordon Ross	 * according to the flags for the this command.
444a90cf9fGordon Ross	 * Note that we may have inherited these.
445a90cf9fGordon Ross	 */
446a90cf9fGordon Ross	if ((sdd->sdt_flags & SDDF_SUPPRESS_UID) == 0) {
447a90cf9fGordon Ross		/*
448a90cf9fGordon Ross		 * This command requires a user session.
449a90cf9fGordon Ross		 */
450a90cf9fGordon Ross		if (related) {
451a90cf9fGordon Ross			/*
452a90cf9fGordon Ross			 * Previous command should have given us a user.
453a90cf9fGordon Ross			 * [MS-SMB2] Handling Related Requests
454a90cf9fGordon Ross			 */
455a90cf9fGordon Ross			if (sr->uid_user == NULL) {
456a90cf9fGordon Ross				smb2sr_put_error(sr,
457a90cf9fGordon Ross				    NT_STATUS_INVALID_PARAMETER);
458a90cf9fGordon Ross				goto cmd_done;
459a90cf9fGordon Ross			}
460a90cf9fGordon Ross			sr->smb_uid = sr->uid_user->u_uid;
461a90cf9fGordon Ross		} else {
462a90cf9fGordon Ross			/*
463a90cf9fGordon Ross			 * Lookup the UID
464a90cf9fGordon Ross			 * [MS-SMB2] Verifying the Session
465a90cf9fGordon Ross			 */
466a90cf9fGordon Ross			ASSERT(sr->uid_user == NULL);
467a90cf9fGordon Ross			sr->uid_user = smb_session_lookup_uid(session,
468a90cf9fGordon Ross			    sr->smb_uid);
469a90cf9fGordon Ross			if (sr->uid_user == NULL) {
470a90cf9fGordon Ross				smb2sr_put_error(sr,
471a90cf9fGordon Ross				    NT_STATUS_USER_SESSION_DELETED);
472a90cf9fGordon Ross				goto cmd_done;
473a90cf9fGordon Ross			}
474a90cf9fGordon Ross			sr->user_cr = smb_user_getcred(sr->uid_user);
475a90cf9fGordon Ross		}
476a90cf9fGordon Ross		ASSERT(sr->uid_user != NULL);
477a90cf9fGordon Ross	}
478a90cf9fGordon Ross
479a90cf9fGordon Ross	if ((sdd->sdt_flags & SDDF_SUPPRESS_TID) == 0) {
480a90cf9fGordon Ross		/*
481a90cf9fGordon Ross		 * This command requires a tree connection.
482a90cf9fGordon Ross		 */
483a90cf9fGordon Ross		if (related) {
484a90cf9fGordon Ross			/*
485a90cf9fGordon Ross			 * Previous command should have given us a tree.
486a90cf9fGordon Ross			 * [MS-SMB2] Handling Related Requests
487a90cf9fGordon Ross			 */
488a90cf9fGordon Ross			if (sr->tid_tree == NULL) {
489a90cf9fGordon Ross				smb2sr_put_error(sr,
490a90cf9fGordon Ross				    NT_STATUS_INVALID_PARAMETER);
491a90cf9fGordon Ross				goto cmd_done;
492a90cf9fGordon Ross			}
493a90cf9fGordon Ross			sr->smb_tid = sr->tid_tree->t_tid;
494a90cf9fGordon Ross		} else {
495a90cf9fGordon Ross			/*
496a90cf9fGordon Ross			 * Lookup the TID
497a90cf9fGordon Ross			 * [MS-SMB2] Verifying the Tree Connect
498a90cf9fGordon Ross			 */
499a90cf9fGordon Ross			ASSERT(sr->tid_tree == NULL);
500a90cf9fGordon Ross			sr->tid_tree = smb_session_lookup_tree(session,
501a90cf9fGordon Ross			    sr->smb_tid);
502a90cf9fGordon Ross			if (sr->tid_tree == NULL) {
503a90cf9fGordon Ross				smb2sr_put_error(sr,
504a90cf9fGordon Ross				    NT_STATUS_NETWORK_NAME_DELETED);
505a90cf9fGordon Ross				goto cmd_done;
506a90cf9fGordon Ross			}
507a90cf9fGordon Ross		}
508a90cf9fGordon Ross		ASSERT(sr->tid_tree != NULL);
509a90cf9fGordon Ross	}
510a90cf9fGordon Ross
511a90cf9fGordon Ross	/*
512a90cf9fGordon Ross	 * SMB2 signature verification, two parts:
513a90cf9fGordon Ross	 * (a) Require SMB2_FLAGS_SIGNED (for most request types)
514a90cf9fGordon Ross	 * (b) If SMB2_FLAGS_SIGNED is set, check the signature.
515a90cf9fGordon Ross	 * [MS-SMB2] Verifying the Signature
516a90cf9fGordon Ross	 */
517a90cf9fGordon Ross
518a90cf9fGordon Ross	/*
519a90cf9fGordon Ross	 * No user session means no signature check.  That's OK,
520a90cf9fGordon Ross	 * i.e. for commands marked SDDF_SUPPRESS_UID above.
521a90cf9fGordon Ross	 * Note, this also means we won't sign the reply.
522a90cf9fGordon Ross	 */
523a90cf9fGordon Ross	if (sr->uid_user == NULL)
524a90cf9fGordon Ross		sr->smb2_hdr_flags &= ~SMB2_FLAGS_SIGNED;