1/*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source.  A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12/*
13 * Copyright 2019 Nexenta Systems, Inc.  All rights reserved.
14 * Copyright 2020 RackTop Systems, Inc.
15 */
16
17
18#include <smbsrv/smb2_kproto.h>
19#include <smbsrv/smb_kstat.h>
20#include <smbsrv/smb2.h>
21
22#define	SMB2_ASYNCID(sr) (sr->smb2_messageid ^ (1ULL << 62))
23
24smb_sdrc_t smb2_invalid_cmd(smb_request_t *);
25static void smb2_tq_work(void *);
26static void smb2sr_run_postwork(smb_request_t *);
27static int smb3_decrypt_msg(smb_request_t *);
28
29static const smb_disp_entry_t
30smb2_disp_table[SMB2__NCMDS] = {
31
32	/* text-name, pre, func, post, cmd-code, dialect, flags */
33
34	{  "smb2_negotiate", NULL,
35	    smb2_negotiate, NULL, 0, 0,
36	    SDDF_SUPPRESS_TID | SDDF_SUPPRESS_UID },
37
38	{  "smb2_session_setup", NULL,
39	    smb2_session_setup, NULL, 0, 0,
40	    SDDF_SUPPRESS_TID | SDDF_SUPPRESS_UID },
41
42	{  "smb2_logoff", NULL,
43	    smb2_logoff, NULL, 0, 0,
44	    SDDF_SUPPRESS_TID },
45
46	{  "smb2_tree_connect", NULL,
47	    smb2_tree_connect, NULL, 0, 0,
48	    SDDF_SUPPRESS_TID },
49
50	{  "smb2_tree_disconn", NULL,
51	    smb2_tree_disconn, NULL, 0, 0 },
52
53	{  "smb2_create", NULL,
54	    smb2_create, NULL, 0, 0 },
55
56	{  "smb2_close", NULL,
57	    smb2_close, NULL, 0, 0 },
58
59	{  "smb2_flush", NULL,
60	    smb2_flush, NULL, 0, 0 },
61
62	{  "smb2_read", NULL,
63	    smb2_read, NULL, 0, 0 },
64
65	{  "smb2_write", NULL,
66	    smb2_write, NULL, 0, 0 },
67
68	{  "smb2_lock", NULL,
69	    smb2_lock, NULL, 0, 0 },
70
71	{  "smb2_ioctl", NULL,
72	    smb2_ioctl, NULL, 0, 0 },
73
74	{  "smb2_cancel", NULL,
75	    smb2_cancel, NULL, 0, 0,
76	    SDDF_SUPPRESS_UID | SDDF_SUPPRESS_TID },
77
78	{  "smb2_echo", NULL,
79	    smb2_echo, NULL, 0, 0,
80	    SDDF_SUPPRESS_UID | SDDF_SUPPRESS_TID },
81
82	{  "smb2_query_dir", NULL,
83	    smb2_query_dir, NULL, 0, 0 },
84
85	{  "smb2_change_notify", NULL,
86	    smb2_change_notify, NULL, 0, 0 },
87
88	{  "smb2_query_info", NULL,
89	    smb2_query_info, NULL, 0, 0 },
90
91	{  "smb2_set_info", NULL,
92	    smb2_set_info, NULL, 0, 0 },
93
94	{  "smb2_oplock_break_ack", NULL,
95	    smb2_oplock_break_ack, NULL, 0, 0 },
96
97	{  "smb2_invalid_cmd", NULL,
98	    smb2_invalid_cmd, NULL, 0, 0,
99	    SDDF_SUPPRESS_UID | SDDF_SUPPRESS_TID },
100};
101
102smb_sdrc_t
103smb2_invalid_cmd(smb_request_t *sr)
104{
105#ifdef	DEBUG
106	cmn_err(CE_NOTE, "clnt %s bad SMB2 cmd code",
107	    sr->session->ip_addr_str);
108#endif
109	sr->smb2_status = NT_STATUS_INVALID_PARAMETER;
110	return (SDRC_DROP_VC);
111}
112
113/*
114 * This is the SMB2 handler for new smb requests, called from
115 * smb_session_reader after SMB negotiate is done.  For most SMB2
116 * requests, we just enqueue them for the smb_session_worker to
117 * execute via the task queue, so they can block for resources
118 * without stopping the reader thread.  A few protocol messages
119 * are special cases and are handled directly here in the reader
120 * thread so they don't wait for taskq scheduling.
121 *
122 * This function must either enqueue the new request for
123 * execution via the task queue, or execute it directly
124 * and then free it.  If this returns non-zero, the caller
125 * will drop the session.
126 */
127int
128smb2sr_newrq(smb_request_t *sr)
129{
130	struct mbuf_chain *mbc = &sr->command;
131	uint32_t magic;
132	int rc, skip;
133
134	if (smb_mbc_peek(mbc, 0, "l", &magic) != 0)
135		goto drop;
136
137	/* 0xFD S M B */
138	if (magic == SMB3_ENCRYPTED_MAGIC) {
139		if (smb3_decrypt_msg(sr) != 0)
140			goto drop;
141		/*
142		 * Should now be looking at an un-encrypted
143		 * SMB2 message header.
144		 */
145		if (smb_mbc_peek(mbc, 0, "l", &magic) != 0)
146			goto drop;
147	}
148
149	if (magic != SMB2_PROTOCOL_MAGIC)
150		goto drop;
151
152	/*
153	 * Walk the SMB2 commands in this compound message and
154	 * keep track of the range of message IDs it uses.
155	 */
156	for (;;) {
157		if (smb2_decode_header(sr) != 0)
158			goto drop;
159
160		/*
161		 * Cancel requests are special:  They refer to
162		 * an earlier message ID (or an async. ID),
163		 * never a new ID, and are never compounded.
164		 * This is intentionally not "goto drop"
165		 * because rc may be zero (success).
166		 */
167		if (sr->smb2_cmd_code == SMB2_CANCEL) {
168			rc = smb2_newrq_cancel(sr);
169			smb_request_free(sr);
170			return (rc);
171		}
172
173		/*
174		 * Keep track of the total credits in this compound
175		 * and the first (real) message ID (not: 0, -1)
176		 * While we're looking, verify that all (real) IDs
177		 * are (first <= ID < (first + msg_credits))
178		 */
179		if (sr->smb2_credit_charge == 0)
180			sr->smb2_credit_charge = 1;
181		sr->smb2_total_credits += sr->smb2_credit_charge;
182
183		if (sr->smb2_messageid != 0 &&
184		    sr->smb2_messageid != UINT64_MAX) {
185
186			if (sr->smb2_first_msgid == 0)
187				sr->smb2_first_msgid = sr->smb2_messageid;
188
189			if (sr->smb2_messageid < sr->smb2_first_msgid ||
190			    sr->smb2_messageid >= (sr->smb2_first_msgid +
191			    sr->smb2_total_credits)) {
192				long long id = (long long) sr->smb2_messageid;
193				cmn_err(CE_WARN, "clnt %s msg ID 0x%llx "
194				    "out of sequence in compound",
195				    sr->session->ip_addr_str, id);
196			}
197		}
198
199		/* Normal loop exit on next == zero */
200		if (sr->smb2_next_command == 0)
201			break;
202
203		/* Abundance of caution... */
204		if (sr->smb2_next_command < SMB2_HDR_SIZE)
205			goto drop;
206
207		/* Advance to the next header. */
208		skip = sr->smb2_next_command - SMB2_HDR_SIZE;
209		if (MBC_ROOM_FOR(mbc, skip) == 0)
210			goto drop;
211		mbc->chain_offset += skip;
212	}
213	/* Rewind back to the top. */
214	mbc->chain_offset = 0;
215
216	/*
217	 * Submit the request to the task queue, which calls
218	 * smb2_tq_work when the workload permits.
219	 */
220	sr->sr_time_submitted = gethrtime();
221	sr->sr_state = SMB_REQ_STATE_SUBMITTED;
222	smb_srqueue_waitq_enter(sr->session->s_srqueue);
223	(void) taskq_dispatch(sr->sr_server->sv_worker_pool,
224	    smb2_tq_work, sr, TQ_SLEEP);
225	return (0);
226
227drop:
228	smb_request_free(sr);
229	return (-1);
230}
231
232static void
233smb2_tq_work(void *arg)
234{
235	smb_request_t	*sr;
236	smb_srqueue_t	*srq;
237
238	sr = (smb_request_t *)arg;
239	SMB_REQ_VALID(sr);
240
241	srq = sr->session->s_srqueue;
242	smb_srqueue_waitq_to_runq(srq);
243	sr->sr_worker = curthread;
244	sr->sr_time_active = gethrtime();
245
246	/*
247	 * Always dispatch to the work function, because cancelled
248	 * requests need an error reply (NT_STATUS_CANCELLED).
249	 */
250	mutex_enter(&sr->sr_mutex);
251	if (sr->sr_state == SMB_REQ_STATE_SUBMITTED)
252		sr->sr_state = SMB_REQ_STATE_ACTIVE;
253	mutex_exit(&sr->sr_mutex);
254
255	smb2sr_work(sr);
256
257	smb_srqueue_runq_exit(srq);
258}
259
260static int
261smb3_decrypt_msg(smb_request_t *sr)
262{
263	int save_offset;
264
265	if (sr->session->dialect < SMB_VERS_3_0) {
266		cmn_err(CE_WARN, "encrypted message in SMB 2.x");
267		return (-1);
268	}
269
270	sr->encrypted = B_TRUE;
271	save_offset = sr->command.chain_offset;
272	if (smb3_decode_tform_header(sr) != 0) {
273		cmn_err(CE_WARN, "bad transform header");
274		return (-1);
275	}
276	sr->command.chain_offset = save_offset;
277
278	sr->tform_ssn = smb_session_lookup_ssnid(sr->session,
279	    sr->smb3_tform_ssnid);
280	if (sr->tform_ssn == NULL) {
281		cmn_err(CE_WARN, "transform header: session not found");
282		return (-1);
283	}
284
285	if (smb3_decrypt_sr(sr) != 0) {
286		cmn_err(CE_WARN, "smb3 decryption failed");
287		return (-1);
288	}
289
290	return (0);
291}
292
293/*
294 * SMB2 credits determine how many simultaneous commands the
295 * client may issue, and bounds the range of message IDs those
296 * commands may use.  With multi-credit support, commands may
297 * use ranges of message IDs, where the credits used by each
298 * command are proportional to their data transfer size.
299 *
300 * Every command may request an increase or decrease of
301 * the currently granted credits, based on the difference
302 * between the credit request and the credit charge.
303 * [MS-SMB2] 3.3.1.2 Algorithm for the Granting of Credits
304 *
305 * Most commands have credit_request=1, credit_charge=1,
306 * which keeps the credit grant unchanged.
307 *
308 * All we're really doing here (for now) is reducing the
309 * credit_response if the client requests a credit increase
310 * that would take their credit over the maximum, and
311 * limiting the decrease so they don't run out of credits.
312 *
313 * Later, this could do something dynamic based on load.
314 *
315 * One other non-obvious bit about credits: We keep the
316 * session s_max_credits low until the 1st authentication,
317 * at which point we'll set the normal maximum_credits.
318 * Some clients ask for more credits with session setup,
319 * and we need to handle that requested increase _after_
320 * the command-specific handler returns so it won't be
321 * restricted to the lower (pre-auth) limit.
322 */
323static inline void
324smb2_credit_decrease(smb_request_t *sr)
325{
326	smb_session_t *session = sr->session;
327	uint16_t cur, d;
328
329	mutex_enter(&session->s_credits_mutex);
330	cur = session->s_cur_credits;
331
332	/* Handle credit decrease. */
333	d = sr->smb2_credit_charge - sr->smb2_credit_request;
334	cur -= d;
335	if (cur & 0x8000) {
336		/*
337		 * underflow (bad credit charge or request)
338		 * leave credits unchanged (response=charge)
339		 */
340		cur = session->s_cur_credits;
341		sr->smb2_credit_response = sr->smb2_credit_charge;
342		DTRACE_PROBE1(smb2__credit__neg, smb_request_t *, sr);
343	}
344
345	/*
346	 * The server MUST ensure that the number of credits
347	 * held by the client is never reduced to zero.
348	 * [MS-SMB2] 3.3.1.2
349	 */
350	if (cur == 0) {
351		cur = 1;
352		sr->smb2_credit_response += 1;
353		DTRACE_PROBE1(smb2__credit__min, smb_request_t *, sr);
354	}
355
356	DTRACE_PROBE3(smb2__credit__decrease,
357	    smb_request_t *, sr, int, (int)cur,
358	    int, (int)session->s_cur_credits);
359
360	session->s_cur_credits = cur;
361	mutex_exit(&session->s_credits_mutex);
362}
363
364/*
365 * Second half of SMB2 credit handling (increases)
366 */
367static inline void
368smb2_credit_increase(smb_request_t *sr)
369{
370	smb_session_t *session = sr->session;
371	uint16_t cur, d;
372
373	mutex_enter(&session->s_credits_mutex);
374	cur = session->s_cur_credits;
375
376	/* Handle credit increase. */
377	d = sr->smb2_credit_request - sr->smb2_credit_charge;
378	cur += d;
379
380	/*
381	 * If new credits would be above max,
382	 * reduce the credit grant.
383	 */
384	if (cur > session->s_max_credits) {
385		d = cur - session->s_max_credits;
386		cur = session->s_max_credits;
387		sr->smb2_credit_response -= d;
388		DTRACE_PROBE1(smb2__credit__max, smb_request_t, sr);
389	}
390
391	DTRACE_PROBE3(smb2__credit__increase,
392	    smb_request_t *, sr, int, (int)cur,
393	    int, (int)session->s_cur_credits);
394
395	session->s_cur_credits = cur;
396	mutex_exit(&session->s_credits_mutex);
397}
398
399/*
400 * Record some statistics:  latency, rx bytes, tx bytes
401 * per:  server, session & kshare.
402 */
403static inline void
404smb2_record_stats(smb_request_t *sr, smb_disp_stats_t *sds, boolean_t tx_only)
405{
406	hrtime_t	dt;
407	int64_t		rxb;
408	int64_t		txb;
409
410	dt = gethrtime() - sr->sr_time_start;
411	rxb = (int64_t)(sr->command.chain_offset - sr->smb2_cmd_hdr);
412	txb = (int64_t)(sr->reply.chain_offset - sr->smb2_reply_hdr);
413
414	if (!tx_only) {
415		smb_server_inc_req(sr->sr_server);
416		smb_latency_add_sample(&sds->sdt_lat, dt);
417		atomic_add_64(&sds->sdt_rxb, rxb);
418	}
419	atomic_add_64(&sds->sdt_txb, txb);
420}
421
422/*
423 * smb2sr_work
424 *
425 * This function processes each SMB command in the current request
426 * (which may be a compound request) building a reply containing
427 * SMB reply messages, one-to-one with the SMB commands.  Some SMB
428 * commands (change notify, blocking locks) may require both an
429 * "interim response" and a later "async response" at completion.
430 * In such cases, we'll encode the interim response in the reply
431 * compound we're building, and put the (now async) command on a
432 * list of commands that need further processing.  After we've
433 * finished processing the commands in this compound and building
434 * the compound reply, we'll send the compound reply, and finally
435 * process the list of async commands.
436 *
437 * As we work our way through the compound request and reply,
438 * we need to keep track of the bounds of the current request
439 * and reply.  For the request, this uses an MBC_SHADOW_CHAIN
440 * that begins at smb2_cmd_hdr.  The reply is appended to the
441 * sr->reply chain starting at smb2_reply_hdr.
442 *
443 * This function must always free the smb request, or arrange
444 * for it to be completed and free'd later (if SDRC_SR_KEPT).
445 */
446void
447smb2sr_work(struct smb_request *sr)
448{
449	const smb_disp_entry_t	*sdd;
450	smb_disp_stats_t	*sds;
451	smb_session_t		*session;
452	uint32_t		msg_len;
453	uint16_t		cmd_idx;
454	int			rc = 0;
455	boolean_t		disconnect = B_FALSE;
456	boolean_t		related;
457
458	session = sr->session;
459
460	ASSERT(sr->smb2_async == B_FALSE);
461	ASSERT(sr->tid_tree == 0);
462	ASSERT(sr->uid_user == 0);
463	ASSERT(sr->fid_ofile == 0);
464	sr->smb_fid = (uint16_t)-1;
465	sr->smb2_status = 0;
466
467	/* temporary until we identify a user */
468	sr->user_cr = zone_kcred();
469
470cmd_start:
471	/*
472	 * Note that we don't check sr_state here and abort the
473	 * compound if cancelled (etc.) because some SMB2 command
474	 * handlers need to do work even when cancelled.
475	 *
476	 * We treat some status codes as if "sticky", meaning
477	 * once they're set after some command handler returns,
478	 * all remaining commands get this status without even
479	 * calling the command-specific handler.
480	 */
481	if (sr->smb2_status != NT_STATUS_CANCELLED &&
482	    sr->smb2_status != NT_STATUS_INSUFFICIENT_RESOURCES)
483		sr->smb2_status = 0;
484
485	/*
486	 * Decode the request header
487	 *
488	 * Most problems with decoding will result in the error
489	 * STATUS_INVALID_PARAMETER.  If the decoding problem
490	 * prevents continuing, we'll close the connection.
491	 * [MS-SMB2] 3.3.5.2.6 Handling Incorrectly Formatted...
492	 */
493	sr->smb2_cmd_hdr = sr->command.chain_offset;
494	if ((rc = smb2_decode_header(sr)) != 0) {
495		cmn_err(CE_WARN, "clnt %s bad SMB2 header",
496		    session->ip_addr_str);
497		disconnect = B_TRUE;
498		goto cleanup;
499	}
500
501	/*
502	 * The SMB2_FLAGS_SERVER_TO_REDIR should only appear
503	 * in messages from the server back to the client.
504	 */
505	if ((sr->smb2_hdr_flags & SMB2_FLAGS_SERVER_TO_REDIR) != 0) {
506		cmn_err(CE_WARN, "clnt %s bad SMB2 flags",
507		    session->ip_addr_str);
508		disconnect = B_TRUE;
509		goto cleanup;
510	}
511	related = (sr->smb2_hdr_flags & SMB2_FLAGS_RELATED_OPERATIONS);
512	sr->smb2_hdr_flags |= SMB2_FLAGS_SERVER_TO_REDIR;
513	if (sr->smb2_hdr_flags & SMB2_FLAGS_ASYNC_COMMAND) {
514		/* Probably an async cancel. */
515		DTRACE_PROBE1(smb2__dispatch__async, smb_request_t *, sr);
516	} else if (sr->smb2_async) {
517		/* Previous command in compound went async. */
518		sr->smb2_hdr_flags |= SMB2_FLAGS_ASYNC_COMMAND;
519		sr->smb2_async_id = SMB2_ASYNCID(sr);
520	}
521
522	/*
523	 * In case we bail out with an error before we get to the
524	 * section that computes the credit grant, initialize the
525	 * response header fields so that credits won't change.
526	 * Note: SMB 2.02 clients may send credit charge zero.
527	 */
528	if (sr->smb2_credit_charge == 0)
529		sr->smb2_credit_charge = 1;
530	sr->smb2_credit_response = sr->smb2_credit_charge;
531
532	/*
533	 * Write a tentative reply header.
534	 *
535	 * We could just leave this blank, but if we're using the
536	 * mdb module feature that extracts packets, it's useful
537	 * to have the header mostly correct here.
538	 *
539	 * If we have already exhausted the output space, then the
540	 * client is trying something funny.  Log it and kill 'em.
541	 */
542	sr->smb2_next_reply = 0;
543	ASSERT((sr->reply.chain_offset & 7) == 0);
544	sr->smb2_reply_hdr = sr->reply.chain_offset;
545	if ((rc = smb2_encode_header(sr, B_FALSE)) != 0) {
546		cmn_err(CE_WARN, "clnt %s excessive reply",
547		    session->ip_addr_str);
548		disconnect = B_TRUE;
549		goto cleanup;
550	}
551
552	/*
553	 * Figure out the length of data following the SMB2 header.
554	 * It ends at either the next SMB2 header if there is one
555	 * (smb2_next_command != 0) or at the end of the message.
556	 */
557	if (sr->smb2_next_command != 0) {
558		/* [MS-SMB2] says this is 8-byte aligned */
559		msg_len = sr->smb2_next_command;
560		if ((msg_len & 7) != 0 || (msg_len < SMB2_HDR_SIZE) ||
561		    ((sr->smb2_cmd_hdr + msg_len) > sr->command.max_bytes)) {
562			cmn_err(CE_WARN, "clnt %s bad SMB2 next cmd",
563			    session->ip_addr_str);
564			disconnect = B_TRUE;
565			goto cleanup;
566		}
567	} else {
568		msg_len = sr->command.max_bytes - sr->smb2_cmd_hdr;
569	}
570
571	/*
572	 * Setup a shadow chain for this SMB2 command, starting
573	 * with the header and ending at either the next command
574	 * or the end of the message.  The signing check below
575	 * needs the entire SMB2 command.  After that's done, we
576	 * advance chain_offset to the end of the header where
577	 * the command specific handlers continue decoding.
578	 */
579	(void) MBC_SHADOW_CHAIN(&sr->smb_data, &sr->command,
580	    sr->smb2_cmd_hdr, msg_len);
581
582	/*
583	 * We will consume the data for this request from smb_data.
584	 * That effectively consumes msg_len bytes from sr->command
585	 * but doesn't update its chain_offset, so we need to update
586	 * that here to make later received bytes accounting work.
587	 */
588	sr->command.chain_offset = sr->smb2_cmd_hdr + msg_len;
589	ASSERT(sr->command.chain_offset <= sr->command.max_bytes);
590
591	/*
592	 * Validate the commmand code, get dispatch table entries.
593	 * [MS-SMB2] 3.3.5.2.6 Handling Incorrectly Formatted...
594	 *
595	 * The last slot in the dispatch table is used to handle
596	 * invalid commands.  Same for statistics.
597	 */
598	if (sr->smb2_cmd_code < SMB2_INVALID_CMD)
599		cmd_idx = sr->smb2_cmd_code;
600	else
601		cmd_idx = SMB2_INVALID_CMD;
602	sdd = &smb2_disp_table[cmd_idx];
603	sds = &session->s_server->sv_disp_stats2[cmd_idx];
604
605	/*
606	 * If this command is NOT "related" to the previous,
607	 * clear out the UID, TID, FID state that might be
608	 * left over from the previous command.
609	 *
610	 * If the command IS related, any new IDs are ignored,
611	 * and we simply continue with the previous user, tree,
612	 * and open file.
613	 */
614	if (!related) {
615		/*
616		 * Drop user, tree, file; carefully ordered to
617		 * avoid dangling references: file, tree, user
618		 */
619		if (sr->fid_ofile != NULL) {
620			smb_ofile_release(sr->fid_ofile);
621			sr->fid_ofile = NULL;
622		}
623		if (sr->tid_tree != NULL) {
624			smb_tree_release(sr->tid_tree);
625			sr->tid_tree = NULL;
626		}
627		if (sr->uid_user != NULL) {
628			smb_user_release(sr->uid_user);
629			sr->uid_user = NULL;
630			sr->user_cr = zone_kcred();
631		}
632	}
633
634	/*
635	 * Make sure we have a user and tree as needed
636	 * according to the flags for the this command.
637	 * Note that we may have inherited these.
638	 */
639	if ((sdd->sdt_flags & SDDF_SUPPRESS_UID) == 0) {
640		/*
641		 * This command requires a user session.
642		 */
643		if (related) {
644			/*
645			 * Previous command should have given us a user.
646			 * [MS-SMB2] 3.3.5.2 Handling Related Requests
647			 */
648			if (sr->uid_user == NULL) {
649				smb2sr_put_error(sr,
650				    NT_STATUS_INVALID_PARAMETER);
651				goto cmd_done;
652			}
653			sr->smb2_ssnid = sr->uid_user->u_ssnid;
654		} else {
655			/*
656			 * Lookup the UID
657			 * [MS-SMB2] 3.3.5.2 Verifying the Session
658			 */
659			ASSERT(sr->uid_user == NULL);
660			/*
661			 * [MS-SMB2] 3.3.5.2.7 Handling Compounded Requests
662			 *
663			 * If this is an encrypted compound request,
664			 * ensure that the ssnid in the request
665			 * is the same as the tform ssnid if this
666			 * message is not related.
667			 *
668			 * The reasons this is done seem to apply equally
669			 * to uncompounded requests, so we apply it to all.
670			 */
671
672			if (sr->encrypted &&
673			    sr->smb2_ssnid != sr->smb3_tform_ssnid) {
674				disconnect = B_TRUE;
675				goto cleanup; /* just do this for now */
676			}
677
678			sr->uid_user = smb_session_lookup_ssnid(session,
679			    sr->smb2_ssnid);
680			if (sr->uid_user == NULL) {
681				smb2sr_put_error(sr,
682				    NT_STATUS_USER_SESSION_DELETED);
683				goto cmd_done;
684			}
685
686			/*
687			 * [MS-SMB2] 3.3.5.2.9 Verifying the Session
688			 *
689			 * If we're talking 3.x,
690			 * RejectUnencryptedAccess is TRUE,
691			 * Session.EncryptData is TRUE,
692			 * and the message wasn't encrypted,
693			 * return ACCESS_DENIED.
694			 *
695			 * Note that Session.EncryptData can only be TRUE when
696			 * we're talking 3.x.
697			 */
698
699			if (sr->uid_user->u_encrypt ==
700			    SMB_CONFIG_REQUIRED &&
701			    !sr->encrypted) {
702				smb2sr_put_error(sr,
703				    NT_STATUS_ACCESS_DENIED);
704				goto cmd_done;
705			}
706
707			sr->user_cr = smb_user_getcred(sr->uid_user);
708		}
709		ASSERT(sr->uid_user != NULL);
710
711		/*
712		 * Encrypt if:
713		 * - The cmd is not SESSION_SETUP or NEGOTIATE; AND
714		 * - Session.EncryptData is TRUE
715		 *
716		 * Those commands suppress UID, so they can't be the cmd here.
717		 */
718		if (sr->uid_user->u_encrypt != SMB_CONFIG_DISABLED &&
719		    sr->tform_ssn == NULL) {
720			smb_user_hold_internal(sr->uid_user);
721			sr->tform_ssn = sr->uid_user;
722			sr->smb3_tform_ssnid = sr->smb2_ssnid;
723		}
724	}
725
726	if ((sdd->sdt_flags & SDDF_SUPPRESS_TID) == 0) {
727		/*
728		 * This command requires a tree connection.
729		 */
730		if (related) {
731			/*
732			 * Previous command should have given us a tree.
733			 * [MS-SMB2] 3.3.5.2 Handling Related Requests
734			 */
735			if (sr->tid_tree == NULL) {
736				smb2sr_put_error(sr,
737				    NT_STATUS_INVALID_PARAMETER);
738				goto cmd_done;
739			}
740			sr->smb_tid = sr->tid_tree->t_tid;
741		} else {
742			/*
743			 * Lookup the TID
744			 * [MS-SMB2] 3.3.5.2 Verifying the Tree Connect
745			 */
746			ASSERT(sr->tid_tree == NULL);
747			sr->tid_tree = smb_session_lookup_tree(session,
748			    sr->smb_tid);
749			if (sr->tid_tree == NULL) {
750				smb2sr_put_error(sr,
751				    NT_STATUS_NETWORK_NAME_DELETED);
752				goto cmd_done;
753			}
754
755			/*
756			 * [MS-SMB2] 3.3.5.2.11 Verifying the Tree Connect
757			 *
758			 * If we support 3.x, RejectUnencryptedAccess is TRUE,
759			 * if Tcon.EncryptData is TRUE or
760			 * global EncryptData is TRUE and
761			 * the message wasn't encrypted, or
762			 * if Tcon.EncryptData is TRUE or
763			 * global EncryptData is TRUE or
764			 * the request was encrypted and
765			 * the connection doesn't support encryption,
766			 * return ACCESS_DENIED.
767			 *
768			 * If RejectUnencryptedAccess is TRUE, we force
769			 * max_protocol to at least 3.0. Additionally,
770			 * if the tree requires encryption, we don't care
771			 * what we support, we still enforce encryption.
772			 */
773			if (sr->tid_tree->t_encrypt == SMB_CONFIG_REQUIRED &&
774			    (!sr->encrypted ||
775			    (session->srv_cap & SMB2_CAP_ENCRYPTION) == 0)) {
776				smb2sr_put_error(sr,
777				    NT_STATUS_ACCESS_DENIED);
778				goto cmd_done;
779			}
780		}
781		ASSERT(sr->tid_tree != NULL);
782
783		/*
784		 * Encrypt if:
785		 * - The cmd is not TREE_CONNECT; AND
786		 * - Tree.EncryptData is TRUE
787		 *
788		 * TREE_CONNECT suppresses TID, so that can't be the cmd here.
789		 * NOTE: assumes we can't have a tree without a user
790		 */
791		if (sr->tid_tree->t_encrypt != SMB_CONFIG_DISABLED &&
792		    sr->tform_ssn == NULL) {
793			smb_user_hold_internal(sr->uid_user);
794			sr->tform_ssn = sr->uid_user;
795			sr->smb3_tform_ssnid = sr->smb2_ssnid;
796		}
797	}
798
799	/*
800	 * SMB2 signature verification, two parts:
801	 * (a) Require SMB2_FLAGS_SIGNED (for most request types)
802	 * (b) If SMB2_FLAGS_SIGNED is set, check the signature.
803	 * [MS-SMB2] 3.3.5.2.4 Verifying the Signature
804	 */
805
806	/*
807	 * No user session means no signature check.  That's OK,
808	 * i.e. for commands marked SDDF_SUPPRESS_UID above.
809	 * Note, this also means we won't sign the reply.
810	 */
811	if (sr->uid_user == NULL)
812		sr->smb2_hdr_flags &= ~SMB2_FLAGS_SIGNED;
813
814	/*
815	 * The SDDF_SUPPRESS_UID dispatch is set for requests that
816	 * don't need a UID (user).  These also don't require a
817	 * signature check here.
818	 *
819	 * [MS-SMB2] 3.3.5.2.4 Verifying the Signature
820	 *
821	 * If the packet was successfully decrypted, the message
822	 * signature has already been verified, so we can skip this.
823	 */
824	if ((sdd->sdt_flags & SDDF_SUPPRESS_UID) == 0 &&
825	    !sr->encrypted && sr->uid_user != NULL &&
826	    (sr->uid_user->u_sign_flags & SMB_SIGNING_ENABLED) != 0) {
827		/*
828		 * If the request is signed, check the signature.
829		 * Otherwise, if signing is required, deny access.
830		 */
831		if ((sr->smb2_hdr_flags & SMB2_FLAGS_SIGNED) != 0) {
832			rc = smb2_sign_check_request(sr);
833			if (rc != 0) {
834				DTRACE_PROBE1(smb2__sign__check,
835				    smb_request_t *, sr);
836				smb2sr_put_error(sr, NT_STATUS_ACCESS_DENIED);
837				goto cmd_done;
838			}
839		} else if (
840		    (sr->uid_user->u_sign_flags & SMB_SIGNING_CHECK) != 0) {
841			smb2sr_put_error(sr, NT_STATUS_ACCESS_DENIED);
842			goto cmd_done;
843		}
844	}
845
846	/*
847	 * Now that the signing check is done with smb_data,
848	 * advance past the SMB2 header we decoded earlier.
849	 * This leaves sr->smb_data correctly positioned
850	 * for command-specific decoding in the dispatch
851	 * function called next.
852	 */
853	sr->smb_data.chain_offset = sr->smb2_cmd_hdr + SMB2_HDR_SIZE;
854
855	/*
856	 * Credit adjustments (decrease)
857	 *
858	 * If we've gone async, credit adjustments were done
859	 * when we sent the interim reply.
860	 */
861	if (!sr->smb2_async) {
862		sr->smb2_credit_response = sr->smb2_credit_request;
863		if (sr->smb2_credit_request < sr->smb2_credit_charge) {
864			smb2_credit_decrease(sr);
865		}
866	}
867
868	/*
869	 * The real work: call the SMB2 command handler
870	 * (except for "sticky" smb2_status - see above)
871	 */
872	sr->sr_time_start = gethrtime();
873	rc = SDRC_SUCCESS;
874	if (sr->smb2_status == 0) {
875		/* NB: not using pre_op */
876		rc = (*sdd->sdt_function)(sr);
877		/* NB: not using post_op */
878	} else {
879		smb2sr_put_error(sr, sr->smb2_status);
880	}
881
882	/*
883	 * When the sdt_function returns SDRC_SR_KEPT, it means
884	 * this SR may have been passed to another thread so we
885	 * MUST NOT touch it anymore.
886	 */
887	if (rc == SDRC_SR_KEPT)
888		return;
889
890	MBC_FLUSH(&sr->raw_data);
891
892	/*
893	 * Credit adjustments (increase)
894	 */
895	if (!sr->smb2_async) {
896		if (sr->smb2_credit_request > sr->smb2_credit_charge) {
897			smb2_credit_increase(sr);
898		}
899	}
900
901cmd_done:
902	switch (rc) {
903	case SDRC_SUCCESS:
904		break;
905	default:
906		/*
907		 * SMB2 does not use the other dispatch return codes.
908		 * If we see something else, log an event so we'll
909		 * know something is returning bogus status codes.
910		 * If you see these in the log, use dtrace to find
911		 * the code returning something else.
912		 */
913#ifdef	DEBUG
914		cmn_err(CE_NOTE, "handler for %u returned 0x%x",
915		    sr->smb2_cmd_code, rc);
916#endif
917		smb2sr_put_error(sr, NT_STATUS_INTERNAL_ERROR);
918		break;
919	case SDRC_ERROR:
920		/*
921		 * Many command handlers return SDRC_ERROR for any
922		 * problems decoding the request, and don't bother
923		 * setting smb2_status.  For those cases, the best
924		 * status return would be "invalid parameter".
925		 */
926		if (sr->smb2_status == 0)
927			sr->smb2_status = NT_STATUS_INVALID_PARAMETER;
928		smb2sr_put_error(sr, sr->smb2_status);
929		break;
930	case SDRC_DROP_VC:
931		disconnect = B_TRUE;
932		goto cleanup;
933
934	case SDRC_NO_REPLY:
935		/* will free sr */
936		goto cleanup;
937	}
938
939	/*
940	 * Pad the reply to align(8) if there will be another.
941	 * (We don't compound async replies.)
942	 */
943	if (!sr->smb2_async && sr->smb2_next_command != 0)
944		(void) smb_mbc_put_align(&sr->reply, 8);
945
946	/*
947	 * Record some statistics.  Uses:
948	 *   rxb = command.chain_offset - smb2_cmd_hdr;
949	 *   txb = reply.chain_offset - smb2_reply_hdr;
950	 * which at this point represent the current cmd/reply.
951	 *
952	 * Note: If async, this does txb only, and
953	 * skips the smb_latency_add_sample() calls.
954	 */
955	smb2_record_stats(sr, sds, sr->smb2_async);
956
957	/*
958	 * If there's a next command, figure out where it starts,
959	 * and fill in the next header offset for the reply.
960	 * Note: We sanity checked smb2_next_command above.
961	 */
962	if (sr->smb2_next_command != 0) {
963		sr->command.chain_offset =
964		    sr->smb2_cmd_hdr + sr->smb2_next_command;
965		sr->smb2_next_reply =
966		    sr->reply.chain_offset - sr->smb2_reply_hdr;
967	} else {
968		ASSERT(sr->smb2_next_reply == 0);
969	}
970
971	/*
972	 * Overwrite the (now final) SMB2 header for this response.
973	 */
974	(void) smb2_encode_header(sr, B_TRUE);
975
976	/*
977	 * Cannot move this into smb2_session_setup() - encoded header required.
978	 */
979	if (session->dialect >= SMB_VERS_3_11 &&
980	    sr->smb2_cmd_code == SMB2_SESSION_SETUP &&
981	    sr->smb2_status == NT_STATUS_MORE_PROCESSING_REQUIRED) {
982		if (smb31_preauth_sha512_calc(sr, &sr->reply,
983		    sr->uid_user->u_preauth_hashval,
984		    sr->uid_user->u_preauth_hashval) != 0)
985			cmn_err(CE_WARN, "(3) Preauth hash calculation "
986			    "failed");
987	}
988
989	/* Don't sign if we're going to encrypt */
990	if (sr->tform_ssn == NULL &&
991	    (sr->smb2_hdr_flags & SMB2_FLAGS_SIGNED) != 0)
992		smb2_sign_reply(sr);
993
994	/*
995	 * Non-async runs the whole compound before send.
996	 * When we've gone async, send each individually.
997	 */
998	if (!sr->smb2_async && sr->smb2_next_command != 0)
999		goto cmd_start;
1000
1001	/*
1002	 * If we have a durable handle, and this operation updated
1003	 * the nvlist, write it out (before smb2_send_reply).
1004	 */
1005	if (sr->dh_nvl_dirty) {
1006		sr->dh_nvl_dirty = B_FALSE;
1007		smb2_dh_update_nvfile(sr);
1008	}
1009
1010	smb2_send_reply(sr);
1011	if (sr->smb2_async && sr->smb2_next_command != 0) {
1012		MBC_FLUSH(&sr->reply);	/* New reply buffer. */
1013		ASSERT(sr->reply.max_bytes == sr->session->reply_max_bytes);
1014		goto cmd_start;
1015	}
1016
1017cleanup:
1018	if (disconnect)
1019		smb_session_disconnect(session);
1020
1021	/*
1022	 * Do "postwork" for oplock (and maybe other things)
1023	 */
1024	if (sr->sr_postwork != NULL)
1025		smb2sr_run_postwork(sr);
1026
1027	mutex_enter(&sr->sr_mutex);
1028	sr->sr_state = SMB_REQ_STATE_COMPLETED;
1029	mutex_exit(&sr->sr_mutex);
1030
1031	smb_request_free(sr);
1032}
1033
1034/*
1035 * Build interim responses for the current and all following
1036 * requests in this compound, then send the compound response,
1037 * leaving the SR state so that smb2sr_work() can continue its
1038 * processing of this compound in "async mode".
1039 *
1040 * If we agree to "go async", this should return STATUS_SUCCESS.
1041 * Otherwise return STATUS_INSUFFICIENT_RESOURCES for this and
1042 * all requests following this request.  (See the comments re.
1043 * "sticky" smb2_status values in smb2sr_work).
1044 *
1045 * Note: the Async ID we assign here is arbitrary, and need only
1046 * be unique among pending async responses on this connection, so
1047 * this just uses a modified messageID, which is already unique.
1048 *
1049 * Credits:  All credit changes should happen via the interim
1050 * responses, so we have to manage credits here.  After this
1051 * returns to smb2sr_work, the final replies for all these
1052 * commands will have smb2_credit_response = smb2_credit_charge
1053 * (meaning no further changes to the clients' credits).
1054 */
1055uint32_t
1056smb2sr_go_async(smb_request_t *sr)
1057{
1058	smb_session_t *session;
1059	smb_disp_stats_t *sds;
1060	uint16_t cmd_idx;
1061	int32_t saved_com_offset;
1062	uint32_t saved_cmd_hdr;
1063	uint16_t saved_cred_resp;
1064	uint32_t saved_hdr_flags;
1065	uint32_t saved_reply_hdr;
1066	uint32_t msg_len;
1067	boolean_t disconnect = B_FALSE;
1068
1069	if (sr->smb2_async) {
1070		/* already went async in some previous cmd. */
1071		return (NT_STATUS_SUCCESS);
1072	}
1073	sr->smb2_async = B_TRUE;
1074
1075	/* The "server" session always runs async. */
1076	session = sr->session;
1077	if (session->sock == NULL)
1078		return (NT_STATUS_SUCCESS);
1079
1080	sds = NULL;
1081	saved_com_offset = sr->command.chain_offset;
1082	saved_cmd_hdr = sr->smb2_cmd_hdr;
1083	saved_cred_resp = sr->smb2_credit_response;
1084	saved_hdr_flags = sr->smb2_hdr_flags;
1085	saved_reply_hdr = sr->smb2_reply_hdr;
1086
1087	/*
1088	 * The command-specific handler should not yet have put any
1089	 * data in the reply except for the (place holder) header.
1090	 */
1091	if (sr->reply.chain_offset != sr->smb2_reply_hdr + SMB2_HDR_SIZE) {
1092		ASSERT3U(sr->reply.chain_offset, ==,
1093		    sr->smb2_reply_hdr + SMB2_HDR_SIZE);
1094		return (NT_STATUS_INTERNAL_ERROR);
1095	}
1096
1097	/*
1098	 * Rewind to the start of the current header in both the
1099	 * command and reply bufers, so the loop below can just
1100	 * decode/encode just in every pass.  This means the
1101	 * current command header is decoded again, but that
1102	 * avoids having to special-case the first loop pass.
1103	 */
1104	sr->command.chain_offset = sr->smb2_cmd_hdr;
1105	sr->reply.chain_offset = sr->smb2_reply_hdr;
1106
1107	/*
1108	 * This command processing loop is a simplified version of
1109	 * smb2sr_work() that just puts an "interim response" for
1110	 * every command in the compound (NT_STATUS_PENDING).
1111	 */
1112cmd_start:
1113	sr->smb2_status = NT_STATUS_PENDING;
1114
1115	/*
1116	 * Decode the request header
1117	 */
1118	sr->smb2_cmd_hdr = sr->command.chain_offset;
1119	if ((smb2_decode_header(sr)) != 0) {
1120		cmn_err(CE_WARN, "clnt %s bad SMB2 header",
1121		    session->ip_addr_str);
1122		disconnect = B_TRUE;
1123		goto cleanup;
1124	}
1125	sr->smb2_hdr_flags |= (SMB2_FLAGS_SERVER_TO_REDIR |
1126	    SMB2_FLAGS_ASYNC_COMMAND);
1127	sr->smb2_async_id = SMB2_ASYNCID(sr);
1128
1129	/*
1130	 * In case we bail out...
1131	 */
1132	if (sr->smb2_credit_charge == 0)
1133		sr->smb2_credit_charge = 1;
1134	sr->smb2_credit_response = sr->smb2_credit_charge;
1135
1136	/*
1137	 * Write a tentative reply header.
1138	 */
1139	sr->smb2_next_reply = 0;
1140	ASSERT((sr->reply.chain_offset & 7) == 0);
1141	sr->smb2_reply_hdr = sr->reply.chain_offset;
1142	if ((smb2_encode_header(sr, B_FALSE)) != 0) {
1143		cmn_err(CE_WARN, "clnt %s excessive reply",
1144		    session->ip_addr_str);
1145		disconnect = B_TRUE;
1146		goto cleanup;
1147	}
1148
1149	/*
1150	 * Figure out the length of data...
1151	 */
1152	if (sr->smb2_next_command != 0) {
1153		/* [MS-SMB2] says this is 8-byte aligned */
1154		msg_len = sr->smb2_next_command;
1155		if ((msg_len & 7) != 0 || (msg_len < SMB2_HDR_SIZE) ||
1156		    ((sr->smb2_cmd_hdr + msg_len) > sr->command.max_bytes)) {
1157			cmn_err(CE_WARN, "clnt %s bad SMB2 next cmd",
1158			    session->ip_addr_str);
1159			disconnect = B_TRUE;
1160			goto cleanup;
1161		}
1162	} else {
1163		msg_len = sr->command.max_bytes - sr->smb2_cmd_hdr;
1164	}
1165
1166	/*
1167	 * We just skip any data, so no shadow chain etc.
1168	 */
1169	sr->command.chain_offset = sr->smb2_cmd_hdr + msg_len;
1170	ASSERT(sr->command.chain_offset <= sr->command.max_bytes);
1171
1172	/*
1173	 * Validate the commmand code...
1174	 */
1175	if (sr->smb2_cmd_code < SMB2_INVALID_CMD)
1176		cmd_idx = sr->smb2_cmd_code;
1177	else
1178		cmd_idx = SMB2_INVALID_CMD;
1179	sds = &session->s_server->sv_disp_stats2[cmd_idx];
1180
1181	/*
1182	 * Don't change (user, tree, file) because we want them
1183	 * exactly as they were when we entered.  That also means
1184	 * we may not have the right user in sr->uid_user for
1185	 * signature checks, so leave that until smb2sr_work
1186	 * runs these commands "for real".  Therefore, here
1187	 * we behave as if: (sr->uid_user == NULL)
1188	 */
1189	sr->smb2_hdr_flags &= ~SMB2_FLAGS_SIGNED;
1190
1191	/*
1192	 * Credit adjustments (decrease)
1193	 *
1194	 * NOTE: interim responses are not signed.
1195	 * Any attacker can modify the credit grant
1196	 * in the response. Because of this property,
1197	 * it is no worse to assume the credit charge and grant
1198	 * are sane without verifying the signature,
1199	 * and that saves us a whole lot of work.
1200	 * If the credits WERE modified, we'll find out
1201	 * when we verify the signature later,
1202	 * which nullifies any changes caused here.
1203	 *
1204	 * Skip this on the first command, because the
1205	 * credit decrease was done by the caller.
1206	 */
1207	if (sr->smb2_cmd_hdr != saved_cmd_hdr) {
1208		sr->smb2_credit_response = sr->smb2_credit_request;
1209		if (sr->smb2_credit_request < sr->smb2_credit_charge) {
1210			smb2_credit_decrease(sr);
1211		}
1212	}
1213
1214	/*
1215	 * The real work: ... (would be here)
1216	 */
1217	smb2sr_put_error(sr, sr->smb2_status);
1218
1219	/*
1220	 * Credit adjustments (increase)
1221	 */
1222	if (sr->smb2_credit_request > sr->smb2_credit_charge) {
1223		smb2_credit_increase(sr);
1224	}
1225
1226	/* cmd_done: label */
1227
1228	/*
1229	 * Pad the reply to align(8) if there will be another.
1230	 * This (interim) reply uses compounding.
1231	 */
1232	if (sr->smb2_next_command != 0)
1233		(void) smb_mbc_put_align(&sr->reply, 8);
1234
1235	/*
1236	 * Record some statistics.  Uses:
1237	 *   rxb = command.chain_offset - smb2_cmd_hdr;
1238	 *   txb = reply.chain_offset - smb2_reply_hdr;
1239	 * which at this point represent the current cmd/reply.
1240	 *
1241	 * Note: We're doing smb_latency_add_sample() for all
1242	 * remaining commands NOW, which means we won't include
1243	 * the async part of their work in latency statistics.
1244	 * That's intentional, as the async part of a command
1245	 * would otherwise skew our latency statistics.
1246	 */
1247	smb2_record_stats(sr, sds, B_FALSE);
1248
1249	/*
1250	 * If there's a next command, figure out where it starts,
1251	 * and fill in the next header offset for the reply.
1252	 * Note: We sanity checked smb2_next_command above.
1253	 */
1254	if (sr->smb2_next_command != 0) {
1255		sr->command.chain_offset =
1256		    sr->smb2_cmd_hdr + sr->smb2_next_command;
1257		sr->smb2_next_reply =
1258		    sr->reply.chain_offset - sr->smb2_reply_hdr;
1259	} else {
1260		ASSERT(sr->smb2_next_reply == 0);
1261	}
1262
1263	/*
1264	 * Overwrite the (now final) SMB2 header for this response.
1265	 */
1266	(void) smb2_encode_header(sr, B_TRUE);
1267
1268	/*
1269	 * Process whole compound before sending.
1270	 */
1271	if (sr->smb2_next_command != 0)
1272		goto cmd_start;
1273	smb2_send_reply(sr);
1274
1275	ASSERT(!disconnect);
1276
1277cleanup:
1278	/*
1279	 * Restore caller's command processing state.
1280	 */
1281	sr->smb2_cmd_hdr = saved_cmd_hdr;
1282	sr->command.chain_offset = saved_cmd_hdr;
1283	(void) smb2_decode_header(sr);
1284	sr->command.chain_offset = saved_com_offset;
1285
1286	sr->smb2_credit_response = saved_cred_resp;
1287	sr->smb2_hdr_flags = saved_hdr_flags;
1288	sr->smb2_status = NT_STATUS_SUCCESS;
1289
1290	/*
1291	 * In here, the "disconnect" flag just means we had an
1292	 * error decoding or encoding something.  Rather than
1293	 * actually disconnect here, let's assume whatever
1294	 * problem we encountered will be seen by the caller
1295	 * as they continue processing the compound, and just
1296	 * restore everything and return an error.
1297	 */
1298	if (disconnect) {
1299		sr->smb2_async = B_FALSE;
1300		sr->smb2_reply_hdr = saved_reply_hdr;
1301		sr->reply.chain_offset = sr->smb2_reply_hdr;
1302		(void) smb2_encode_header(sr, B_FALSE);
1303		return (NT_STATUS_INVALID_PARAMETER);
1304	}
1305
1306	/*
1307	 * The compound reply buffer we sent is now gone.
1308	 * Setup a new reply buffer for the caller.
1309	 */
1310	sr->smb2_hdr_flags |= SMB2_FLAGS_ASYNC_COMMAND;
1311	sr->smb2_async_id = SMB2_ASYNCID(sr);
1312	sr->smb2_next_reply = 0;
1313	MBC_FLUSH(&sr->reply);
1314	ASSERT(sr->reply.max_bytes == sr->session->reply_max_bytes);
1315	ASSERT(sr->reply.chain_offset == 0);
1316	sr->smb2_reply_hdr = 0;
1317	(void) smb2_encode_header(sr, B_FALSE);
1318
1319	return (NT_STATUS_SUCCESS);
1320}
1321
1322int
1323smb3_decode_tform_header(smb_request_t *sr)
1324{
1325	uint16_t flags;
1326	int rc;
1327	uint32_t protocolid;
1328
1329	rc = smb_mbc_decodef(
1330	    &sr->command, "l16c16cl..wq",
1331	    &protocolid,	/*  l  */
1332	    sr->smb2_sig,	/* 16c */
1333	    sr->nonce,	/* 16c */
1334	    &sr->msgsize,	/* l */
1335	    /* reserved	  .. */
1336	    &flags,		/* w */
1337	    &sr->smb3_tform_ssnid); /* q */
1338	if (rc)
1339		return (rc);
1340
1341	ASSERT3U(protocolid, ==, SMB3_ENCRYPTED_MAGIC);
1342
1343	if (flags != 1) {
1344#ifdef DEBUG
1345		cmn_err(CE_NOTE, "flags field not 1: %x", flags);
1346#endif
1347		return (-1);
1348	}
1349
1350	/*
1351	 * MsgSize is the amount of data the client tell us to decrypt.
1352	 * Make sure this value is not too big and not too small.
1353	 */
1354	if (sr->msgsize < SMB2_HDR_SIZE ||
1355	    sr->msgsize > sr->session->cmd_max_bytes ||
1356	    sr->msgsize > sr->command.max_bytes - SMB3_TFORM_HDR_SIZE)
1357		return (-1);
1358
1359	return (rc);
1360}
1361
1362int
1363smb3_encode_tform_header(smb_request_t *sr, struct mbuf_chain *mbc)
1364{
1365	int rc;
1366
1367	/* Signature and Nonce are added in smb3_encrypt_sr */
1368	rc = smb_mbc_encodef(
1369	    mbc, "l32.lwwq",
1370	    SMB3_ENCRYPTED_MAGIC, /* l */
1371	    /* signature(16), nonce(16) 32. */
1372	    sr->msgsize,	/* l */
1373	    0, /* reserved	   w */
1374	    1, /* flags		   w */
1375	    sr->smb3_tform_ssnid); /* q */
1376
1377	return (rc);
1378}
1379
1380int
1381smb2_decode_header(smb_request_t *sr)
1382{
1383	uint32_t pid, tid;
1384	uint16_t hdr_len;
1385	int rc;
1386
1387	rc = smb_mbc_decodef(
1388	    &sr->command, "Nwww..wwllqllq16c",
1389	    &hdr_len,			/* w */
1390	    &sr->smb2_credit_charge,	/* w */
1391	    &sr->smb2_chan_seq,		/* w */
1392	    /* reserved			  .. */
1393	    &sr->smb2_cmd_code,		/* w */
1394	    &sr->smb2_credit_request,	/* w */
1395	    &sr->smb2_hdr_flags,	/* l */
1396	    &sr->smb2_next_command,	/* l */
1397	    &sr->smb2_messageid,	/* q */
1398	    &pid,			/* l */
1399	    &tid,			/* l */
1400	    &sr->smb2_ssnid,		/* q */
1401	    sr->smb2_sig);		/* 16c */
1402	if (rc)
1403		return (rc);
1404
1405	if (hdr_len != SMB2_HDR_SIZE)
1406		return (-1);
1407
1408	if (sr->smb2_hdr_flags & SMB2_FLAGS_ASYNC_COMMAND) {
1409		sr->smb2_async_id = pid |
1410		    ((uint64_t)tid) << 32;
1411		sr->smb_pid = 0;
1412		sr->smb_tid = 0;
1413	} else {
1414		sr->smb2_async_id = 0;
1415		sr->smb_pid = pid;
1416		sr->smb_tid = (uint16_t)tid; /* XXX wide TIDs */
1417	}
1418
1419	return (rc);
1420}
1421
1422int
1423smb2_encode_header(smb_request_t *sr, boolean_t overwrite)
1424{
1425	uint64_t pid_tid_aid; /* pid+tid, or async id */
1426	int rc;
1427
1428	if (sr->smb2_hdr_flags & SMB2_FLAGS_ASYNC_COMMAND) {
1429		pid_tid_aid = sr->smb2_async_id;
1430	} else {
1431		pid_tid_aid = sr->smb_pid |
1432		    ((uint64_t)sr->smb_tid) << 32;
1433	}
1434
1435	if (overwrite) {
1436		rc = smb_mbc_poke(&sr->reply,
1437		    sr->smb2_reply_hdr,
1438		    "Nwwlwwllqqq16c",
1439		    SMB2_HDR_SIZE,		/* w */
1440		    sr->smb2_credit_charge,	/* w */
1441		    sr->smb2_status,		/* l */
1442		    sr->smb2_cmd_code,		/* w */
1443		    sr->smb2_credit_response,	/* w */
1444		    sr->smb2_hdr_flags,		/* l */
1445		    sr->smb2_next_reply,	/* l */
1446		    sr->smb2_messageid,		/* q */
1447		    pid_tid_aid,		/* q */
1448		    sr->smb2_ssnid,		/* q */
1449		    sr->smb2_sig);		/* 16c */
1450	} else {
1451		rc = smb_mbc_encodef(&sr->reply,
1452		    "Nwwlwwllqqq16c",
1453		    SMB2_HDR_SIZE,		/* w */
1454		    sr->smb2_credit_charge,	/* w */
1455		    sr->smb2_status,		/* l */
1456		    sr->smb2_cmd_code,		/* w */
1457		    sr->smb2_credit_response,	/* w */
1458		    sr->smb2_hdr_flags,		/* l */
1459		    sr->smb2_next_reply,	/* l */
1460		    sr->smb2_messageid,		/* q */
1461		    pid_tid_aid,		/* q */
1462		    sr->smb2_ssnid,		/* q */
1463		    sr->smb2_sig);		/* 16c */
1464	}
1465
1466	return (rc);
1467}
1468
1469void
1470smb2_send_reply(smb_request_t *sr)
1471{
1472	struct mbuf_chain enc_reply;
1473	smb_session_t *session = sr->session;
1474	void *tmpbuf;
1475	size_t buflen;
1476	struct mbuf_chain tmp;
1477
1478	/*
1479	 * [MS-SMB2] 3.3.4.1.4 Encrypting the Message
1480	 *
1481	 * When the connection supports encryption and the dialect
1482	 * is 3.x, encrypt if:
1483	 * - The request was encrypted OR
1484	 * - The cmd is not SESSION_SETUP or NEGOTIATE AND
1485	 * -- Session.EncryptData is TRUE OR
1486	 * -- The cmd is not TREE_CONNECT AND
1487	 * --- Tree.EncryptData is TRUE
1488	 *
1489	 * This boils down to sr->tform_ssn != NULL, and the rest
1490	 * is enforced when tform_ssn is set.
1491	 */
1492
1493	if ((session->capabilities & SMB2_CAP_ENCRYPTION) == 0 ||
1494	    sr->tform_ssn == NULL) {
1495		(void) smb_session_send(sr->session, 0, &sr->reply);
1496		return;
1497	}
1498
1499	sr->msgsize = sr->reply.chain_offset;
1500	(void) MBC_SHADOW_CHAIN(&tmp, &sr->reply,
1501	    0, sr->msgsize);
1502
1503	buflen = SMB3_TFORM_HDR_SIZE + sr->msgsize;
1504
1505	/* taken from smb_request_init_command_mbuf */
1506	tmpbuf = kmem_alloc(buflen, KM_SLEEP);
1507	MBC_ATTACH_BUF(&enc_reply, tmpbuf, buflen);
1508	enc_reply.flags = 0;
1509	enc_reply.shadow_of = NULL;
1510
1511	if (smb3_encode_tform_header(sr, &enc_reply) != 0) {
1512		cmn_err(CE_WARN, "couldn't encode transform header");
1513		goto errout;
1514	}
1515	if (smb3_encrypt_sr(sr, &tmp, &enc_reply) != 0) {
1516		cmn_err(CE_WARN, "smb3 encryption failed");
1517		goto errout;
1518	}
1519
1520	(void) smb_session_send(sr->session, 0, &enc_reply);
1521	kmem_free(tmpbuf, buflen);
1522	return;
1523
1524errout:
1525	kmem_free(tmpbuf, buflen);
1526	smb_session_disconnect(sr->session);
1527}
1528
1529/*
1530 * This wrapper function exists to help catch calls to smbsr_status()
1531 * (which is SMB1-specific) in common code.  See smbsr_status().
1532 * If the log message below is seen, put a dtrace probe on this
1533 * function with a stack() action to see who is calling the SMB1
1534 * "put error" from common code, and fix it.
1535 */
1536void
1537smbsr_status_smb2(smb_request_t *sr, DWORD status)
1538{
1539	const char *name;
1540
1541	if (sr->smb2_cmd_code < SMB2__NCMDS)
1542		name = smb2_disp_table[sr->smb2_cmd_code].sdt_name;
1543	else
1544		name = "<unknown>";
1545#ifdef	DEBUG
1546	cmn_err(CE_NOTE, "smbsr_status called for %s", name);
1547#endif
1548
1549	smb2sr_put_error_data(sr, status, NULL);
1550}
1551
1552void
1553smb2sr_put_errno(struct smb_request *sr, int errnum)
1554{
1555	uint32_t status = smb_errno2status(errnum);
1556	smb2sr_put_error_data(sr, status, NULL);
1557}
1558
1559void
1560smb2sr_put_error(smb_request_t *sr, uint32_t status)
1561{
1562	smb2sr_put_error_data(sr, status, NULL);
1563}
1564
1565/*
1566 * Build an SMB2 error response.  [MS-SMB2] 2.2.2
1567 */
1568void
1569smb2sr_put_error_data(smb_request_t *sr, uint32_t status, mbuf_chain_t *mbc)
1570{
1571	DWORD len;
1572
1573	/*
1574	 * The common dispatch code writes this when it
1575	 * updates the SMB2 header before sending.
1576	 */
1577	sr->smb2_status = status;
1578
1579	/* Rewind to the end of the SMB header. */
1580	sr->reply.chain_offset = sr->smb2_reply_hdr + SMB2_HDR_SIZE;
1581
1582	/*
1583	 * NB: Must provide at least one byte of error data,
1584	 * per [MS-SMB2] 2.2.2
1585	 */
1586	if (mbc != NULL && (len = MBC_LENGTH(mbc)) != 0) {
1587		(void) smb_mbc_encodef(
1588		    &sr->reply,
1589		    "wwlC",
1590		    9,	/* StructSize */	/* w */
1591		    0,	/* reserved */		/* w */
1592		    len,			/* l */
1593		    mbc);			/* C */
1594	} else {
1595		(void) smb_mbc_encodef(
1596		    &sr->reply,
1597		    "wwl.",
1598		    9,	/* StructSize */	/* w */
1599		    0,	/* reserved */		/* w */
1600		    0);				/* l. */
1601	}
1602}
1603
1604/*
1605 * Build an SMB2 error context response (dialect 3.1.1).
1606 */
1607void
1608smb2sr_put_error_ctx(smb_request_t *sr, uint32_t status, uint32_t errid,
1609    mbuf_chain_t *mbc)
1610{
1611	DWORD len;
1612
1613	/*
1614	 * The common dispatch code writes this when it
1615	 * updates the SMB2 header before sending.
1616	 */
1617	sr->smb2_status = status;
1618
1619	/* Rewind to the end of the SMB header. */
1620	sr->reply.chain_offset = sr->smb2_reply_hdr + SMB2_HDR_SIZE;
1621
1622	/*
1623	 *  Error Context is 8-byte header plus encaps. data (ErrorContextData),
1624	 *  which can be zero-length.
1625	 */
1626	if (mbc != NULL && (len = MBC_LENGTH(mbc)) != 0) {
1627		(void) smb_mbc_encodef(
1628		    &sr->reply,
1629		    "wbblllC",
1630		    9,		/* StructSize */	/* w */
1631		    1,		/* ErrorContextCount */	/* b */
1632		    0,		/* reserved */		/* b */
1633		    8+len,	/* ByteCount */		/* l */
1634		    len,	/* ErrorDataLength */	/* l */
1635		    errid,	/* ErrorId */		/* l */
1636		    mbc);				/* C */
1637	} else {
1638		(void) smb_mbc_encodef(
1639		    &sr->reply,
1640		    "wbblll",
1641		    9,		/* StructSize */	/* w */
1642		    1,		/* ErrorContextCount */	/* b */
1643		    0,		/* reserved */		/* b */
1644		    8,		/* ByteCount */		/* l */
1645		    0,		/* ErrorDataLength */	/* l */
1646		    errid);	/* ErrorId */		/* l */
1647	}
1648}
1649
1650/*
1651 * Build an SMB2 error context response with SMB2_ERROR_ID_DEFAULT ErrorId.
1652 *
1653 * This only handles the case we currently need, encapsulating a
1654 * single error data section inside an SMB2_ERROR_ID_DEFAULT
1655 * error context type (which is type zero, and that's what
1656 * the zero on the end of this function name refers to).
1657 */
1658void
1659smb2sr_put_error_ctx0(smb_request_t *sr, uint32_t status, mbuf_chain_t *mbc)
1660{
1661	return (smb2sr_put_error_ctx(sr, status, SMB2_ERROR_ID_DEFAULT, mbc));
1662}
1663
1664/*
1665 * smb2sr_lookup_fid
1666 *
1667 * Setup sr->fid_ofile, either inherited from a related command,
1668 * or obtained via FID lookup.  Similar inheritance logic as in
1669 * smb2sr_work.
1670 */
1671uint32_t
1672smb2sr_lookup_fid(smb_request_t *sr, smb2fid_t *fid)
1673{
1674	boolean_t related = sr->smb2_hdr_flags &
1675	    SMB2_FLAGS_RELATED_OPERATIONS;
1676
1677	if (related) {
1678		if (sr->fid_ofile == NULL)
1679			return (NT_STATUS_INVALID_PARAMETER);
1680		sr->smb_fid = sr->fid_ofile->f_fid;
1681		return (0);
1682	}
1683
1684	/*
1685	 * If we could be sure this is called only once per cmd,
1686	 * we could simply ASSERT(sr->fid_ofile == NULL) here.
1687	 * However, there are cases where it can be called again
1688	 * handling the same command, so let's tolerate that.
1689	 */
1690	if (sr->fid_ofile == NULL) {
1691		sr->smb_fid = (uint16_t)fid->temporal;
1692		sr->fid_ofile = smb_ofile_lookup_by_fid(sr, sr->smb_fid);
1693	}
1694	if (sr->fid_ofile == NULL ||
1695	    sr->fid_ofile->f_persistid != fid->persistent)
1696		return (NT_STATUS_FILE_CLOSED);
1697
1698	return (0);
1699}
1700
1701/*
1702 * smb2_dispatch_stats_init
1703 *
1704 * Initializes dispatch statistics for SMB2.
1705 * See also smb_dispatch_stats_init(), which fills in
1706 * the lower part of the statistics array, from zero
1707 * through SMB_COM_NUM;
1708 */
1709void
1710smb2_dispatch_stats_init(smb_server_t *sv)
1711{
1712	smb_disp_stats_t *sds = sv->sv_disp_stats2;
1713	smb_kstat_req_t *ksr;
1714	int		i;
1715
1716	ksr = ((smbsrv_kstats_t *)sv->sv_ksp->ks_data)->ks_reqs2;
1717
1718	for (i = 0; i < SMB2__NCMDS; i++, ksr++) {
1719		smb_latency_init(&sds[i].sdt_lat);
1720		(void) strlcpy(ksr->kr_name, smb2_disp_table[i].sdt_name,
1721		    sizeof (ksr->kr_name));
1722	}
1723}
1724
1725/*
1726 * smb2_dispatch_stats_fini
1727 *
1728 * Frees and destroyes the resources used for statistics.
1729 */
1730void
1731smb2_dispatch_stats_fini(smb_server_t *sv)
1732{
1733	smb_disp_stats_t *sds = sv->sv_disp_stats2;
1734	int	i;
1735
1736	for (i = 0; i < SMB2__NCMDS; i++)
1737		smb_latency_destroy(&sds[i].sdt_lat);
1738}
1739
1740void
1741smb2_dispatch_stats_update(smb_server_t *sv,
1742    smb_kstat_req_t *ksr, int first, int nreq)
1743{
1744	smb_disp_stats_t *sds = sv->sv_disp_stats2;
1745	int	i;
1746	int	last;
1747
1748	last = first + nreq - 1;
1749
1750	if ((first < SMB2__NCMDS) && (last < SMB2__NCMDS))  {
1751		for (i = first; i <= last; i++, ksr++) {
1752			ksr->kr_rxb = sds[i].sdt_rxb;
1753			ksr->kr_txb = sds[i].sdt_txb;
1754			mutex_enter(&sds[i].sdt_lat.ly_mutex);
1755			ksr->kr_nreq = sds[i].sdt_lat.ly_a_nreq;
1756			ksr->kr_sum = sds[i].sdt_lat.ly_a_sum;
1757			ksr->kr_a_mean = sds[i].sdt_lat.ly_a_mean;
1758			ksr->kr_a_stddev =
1759			    sds[i].sdt_lat.ly_a_stddev;
1760			ksr->kr_d_mean = sds[i].sdt_lat.ly_d_mean;
1761			ksr->kr_d_stddev =
1762			    sds[i].sdt_lat.ly_d_stddev;
1763			sds[i].sdt_lat.ly_d_mean = 0;
1764			sds[i].sdt_lat.ly_d_nreq = 0;
1765			sds[i].sdt_lat.ly_d_stddev = 0;
1766			sds[i].sdt_lat.ly_d_sum = 0;
1767			mutex_exit(&sds[i].sdt_lat.ly_mutex);
1768		}
1769	}
1770}
1771
1772/*
1773 * Append new_sr to the postwork queue.  sr->smb2_cmd_code encodes
1774 * the action that should be run by this sr.
1775 *
1776 * This queue is rarely used (and normally empty) so we're OK
1777 * using a simple "walk to tail and insert" here.
1778 */
1779void
1780smb2sr_append_postwork(smb_request_t *top_sr, smb_request_t *new_sr)
1781{
1782	smb_request_t *last_sr;
1783
1784	ASSERT(top_sr->session->dialect >= SMB_VERS_2_BASE);
1785
1786	last_sr = top_sr;
1787	while (last_sr->sr_postwork != NULL)
1788		last_sr = last_sr->sr_postwork;
1789
1790	last_sr->sr_postwork = new_sr;
1791}
1792
1793/*
1794 * Run any "post work" that was appended to the main SR while it
1795 * was running.  This is called after the request has been sent
1796 * for the main SR, and used in cases i.e. the oplock code, where
1797 * we need to send something to the client only _after_ the main
1798 * sr request has gone out.
1799 */
1800static void
1801smb2sr_run_postwork(smb_request_t *top_sr)
1802{
1803	smb_request_t *post_sr;	/* the one we're running */
1804	smb_request_t *next_sr;
1805
1806	while ((post_sr = top_sr->sr_postwork) != NULL) {
1807		next_sr = post_sr->sr_postwork;
1808		top_sr->sr_postwork = next_sr;
1809		post_sr->sr_postwork = NULL;
1810
1811		post_sr->sr_worker = top_sr->sr_worker;
1812		post_sr->sr_state = SMB_REQ_STATE_ACTIVE;
1813
1814		switch (post_sr->smb2_cmd_code) {
1815		case SMB2_OPLOCK_BREAK:
1816			smb_oplock_send_brk(post_sr);
1817			break;
1818		default:
1819			ASSERT(0);
1820		}
1821
1822		/*
1823		 * If we have a durable handle, and this operation
1824		 * updated the nvlist, write it out.
1825		 */
1826		if (post_sr->dh_nvl_dirty) {
1827			post_sr->dh_nvl_dirty = B_FALSE;
1828			smb2_dh_update_nvfile(post_sr);
1829		}
1830
1831		post_sr->sr_state = SMB_REQ_STATE_COMPLETED;
1832		smb_request_free(post_sr);
1833	}
1834}
1835