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 2019 RackTop Systems.
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	/* Don't sign if we're going to encrypt */
977	if (sr->tform_ssn == NULL &&
978	    (sr->smb2_hdr_flags & SMB2_FLAGS_SIGNED) != 0)
979		smb2_sign_reply(sr);
980
981	/*
982	 * Non-async runs the whole compound before send.
983	 * When we've gone async, send each individually.
984	 */
985	if (!sr->smb2_async && sr->smb2_next_command != 0)
986		goto cmd_start;
987
988	/*
989	 * If we have a durable handle, and this operation updated
990	 * the nvlist, write it out (before smb2_send_reply).
991	 */
992	if (sr->dh_nvl_dirty) {
993		sr->dh_nvl_dirty = B_FALSE;
994		smb2_dh_update_nvfile(sr);
995	}
996
997	smb2_send_reply(sr);
998	if (sr->smb2_async && sr->smb2_next_command != 0) {
999		MBC_FLUSH(&sr->reply);	/* New reply buffer. */
1000		ASSERT(sr->reply.max_bytes == sr->session->reply_max_bytes);
1001		goto cmd_start;
1002	}
1003
1004cleanup:
1005	if (disconnect)
1006		smb_session_disconnect(session);
1007
1008	/*
1009	 * Do "postwork" for oplock (and maybe other things)
1010	 */
1011	if (sr->sr_postwork != NULL)
1012		smb2sr_run_postwork(sr);
1013
1014	mutex_enter(&sr->sr_mutex);
1015	sr->sr_state = SMB_REQ_STATE_COMPLETED;
1016	mutex_exit(&sr->sr_mutex);
1017
1018	smb_request_free(sr);
1019}
1020
1021/*
1022 * Build interim responses for the current and all following
1023 * requests in this compound, then send the compound response,
1024 * leaving the SR state so that smb2sr_work() can continue its
1025 * processing of this compound in "async mode".
1026 *
1027 * If we agree to "go async", this should return STATUS_SUCCESS.
1028 * Otherwise return STATUS_INSUFFICIENT_RESOURCES for this and
1029 * all requests following this request.  (See the comments re.
1030 * "sticky" smb2_status values in smb2sr_work).
1031 *
1032 * Note: the Async ID we assign here is arbitrary, and need only
1033 * be unique among pending async responses on this connection, so
1034 * this just uses a modified messageID, which is already unique.
1035 *
1036 * Credits:  All credit changes should happen via the interim
1037 * responses, so we have to manage credits here.  After this
1038 * returns to smb2sr_work, the final replies for all these
1039 * commands will have smb2_credit_response = smb2_credit_charge
1040 * (meaning no further changes to the clients' credits).
1041 */
1042uint32_t
1043smb2sr_go_async(smb_request_t *sr)
1044{
1045	smb_session_t *session;
1046	smb_disp_stats_t *sds;
1047	uint16_t cmd_idx;
1048	int32_t saved_com_offset;
1049	uint32_t saved_cmd_hdr;
1050	uint16_t saved_cred_resp;
1051	uint32_t saved_hdr_flags;
1052	uint32_t saved_reply_hdr;
1053	uint32_t msg_len;
1054	boolean_t disconnect = B_FALSE;
1055
1056	if (sr->smb2_async) {
1057		/* already went async in some previous cmd. */
1058		return (NT_STATUS_SUCCESS);
1059	}
1060	sr->smb2_async = B_TRUE;
1061
1062	/* The "server" session always runs async. */
1063	session = sr->session;
1064	if (session->sock == NULL)
1065		return (NT_STATUS_SUCCESS);
1066
1067	sds = NULL;
1068	saved_com_offset = sr->command.chain_offset;
1069	saved_cmd_hdr = sr->smb2_cmd_hdr;
1070	saved_cred_resp = sr->smb2_credit_response;
1071	saved_hdr_flags = sr->smb2_hdr_flags;
1072	saved_reply_hdr = sr->smb2_reply_hdr;
1073
1074	/*
1075	 * The command-specific handler should not yet have put any
1076	 * data in the reply except for the (place holder) header.
1077	 */
1078	if (sr->reply.chain_offset != sr->smb2_reply_hdr + SMB2_HDR_SIZE) {
1079		ASSERT3U(sr->reply.chain_offset, ==,
1080		    sr->smb2_reply_hdr + SMB2_HDR_SIZE);
1081		return (NT_STATUS_INTERNAL_ERROR);
1082	}
1083
1084	/*
1085	 * Rewind to the start of the current header in both the
1086	 * command and reply bufers, so the loop below can just
1087	 * decode/encode just in every pass.  This means the
1088	 * current command header is decoded again, but that
1089	 * avoids having to special-case the first loop pass.
1090	 */
1091	sr->command.chain_offset = sr->smb2_cmd_hdr;
1092	sr->reply.chain_offset = sr->smb2_reply_hdr;
1093
1094	/*
1095	 * This command processing loop is a simplified version of
1096	 * smb2sr_work() that just puts an "interim response" for
1097	 * every command in the compound (NT_STATUS_PENDING).
1098	 */
1099cmd_start:
1100	sr->smb2_status = NT_STATUS_PENDING;
1101
1102	/*
1103	 * Decode the request header
1104	 */
1105	sr->smb2_cmd_hdr = sr->command.chain_offset;
1106	if ((smb2_decode_header(sr)) != 0) {
1107		cmn_err(CE_WARN, "clnt %s bad SMB2 header",
1108		    session->ip_addr_str);
1109		disconnect = B_TRUE;
1110		goto cleanup;
1111	}
1112	sr->smb2_hdr_flags |=  (SMB2_FLAGS_SERVER_TO_REDIR |
1113				SMB2_FLAGS_ASYNC_COMMAND);
1114	sr->smb2_async_id = SMB2_ASYNCID(sr);
1115
1116	/*
1117	 * In case we bail out...
1118	 */
1119	if (sr->smb2_credit_charge == 0)
1120		sr->smb2_credit_charge = 1;
1121	sr->smb2_credit_response = sr->smb2_credit_charge;
1122
1123	/*
1124	 * Write a tentative reply header.
1125	 */
1126	sr->smb2_next_reply = 0;
1127	ASSERT((sr->reply.chain_offset & 7) == 0);
1128	sr->smb2_reply_hdr = sr->reply.chain_offset;
1129	if ((smb2_encode_header(sr, B_FALSE)) != 0) {
1130		cmn_err(CE_WARN, "clnt %s excessive reply",
1131		    session->ip_addr_str);
1132		disconnect = B_TRUE;
1133		goto cleanup;
1134	}
1135
1136	/*
1137	 * Figure out the length of data...
1138	 */
1139	if (sr->smb2_next_command != 0) {
1140		/* [MS-SMB2] says this is 8-byte aligned */
1141		msg_len = sr->smb2_next_command;
1142		if ((msg_len & 7) != 0 || (msg_len < SMB2_HDR_SIZE) ||
1143		    ((sr->smb2_cmd_hdr + msg_len) > sr->command.max_bytes)) {
1144			cmn_err(CE_WARN, "clnt %s bad SMB2 next cmd",
1145			    session->ip_addr_str);
1146			disconnect = B_TRUE;
1147			goto cleanup;
1148		}
1149	} else {
1150		msg_len = sr->command.max_bytes - sr->smb2_cmd_hdr;
1151	}
1152
1153	/*
1154	 * We just skip any data, so no shadow chain etc.
1155	 */
1156	sr->command.chain_offset = sr->smb2_cmd_hdr + msg_len;
1157	ASSERT(sr->command.chain_offset <= sr->command.max_bytes);
1158
1159	/*
1160	 * Validate the commmand code...
1161	 */
1162	if (sr->smb2_cmd_code < SMB2_INVALID_CMD)
1163		cmd_idx = sr->smb2_cmd_code;
1164	else
1165		cmd_idx = SMB2_INVALID_CMD;
1166	sds = &session->s_server->sv_disp_stats2[cmd_idx];
1167
1168	/*
1169	 * Don't change (user, tree, file) because we want them
1170	 * exactly as they were when we entered.  That also means
1171	 * we may not have the right user in sr->uid_user for
1172	 * signature checks, so leave that until smb2sr_work
1173	 * runs these commands "for real".  Therefore, here
1174	 * we behave as if: (sr->uid_user == NULL)
1175	 */
1176	sr->smb2_hdr_flags &= ~SMB2_FLAGS_SIGNED;
1177
1178	/*
1179	 * Credit adjustments (decrease)
1180	 *
1181	 * NOTE: interim responses are not signed.
1182	 * Any attacker can modify the credit grant
1183	 * in the response. Because of this property,
1184	 * it is no worse to assume the credit charge and grant
1185	 * are sane without verifying the signature,
1186	 * and that saves us a whole lot of work.
1187	 * If the credits WERE modified, we'll find out
1188	 * when we verify the signature later,
1189	 * which nullifies any changes caused here.
1190	 *
1191	 * Skip this on the first command, because the
1192	 * credit decrease was done by the caller.
1193	 */
1194	if (sr->smb2_cmd_hdr != saved_cmd_hdr) {
1195		sr->smb2_credit_response = sr->smb2_credit_request;
1196		if (sr->smb2_credit_request < sr->smb2_credit_charge) {
1197			smb2_credit_decrease(sr);
1198		}
1199	}
1200
1201	/*
1202	 * The real work: ... (would be here)
1203	 */
1204	smb2sr_put_error(sr, sr->smb2_status);
1205
1206	/*
1207	 * Credit adjustments (increase)
1208	 */
1209	if (sr->smb2_credit_request > sr->smb2_credit_charge) {
1210		smb2_credit_increase(sr);
1211	}
1212
1213	/* cmd_done: label */
1214
1215	/*
1216	 * Pad the reply to align(8) if there will be another.
1217	 * This (interim) reply uses compounding.
1218	 */
1219	if (sr->smb2_next_command != 0)
1220		(void) smb_mbc_put_align(&sr->reply, 8);
1221
1222	/*
1223	 * Record some statistics.  Uses:
1224	 *   rxb = command.chain_offset - smb2_cmd_hdr;
1225	 *   txb = reply.chain_offset - smb2_reply_hdr;
1226	 * which at this point represent the current cmd/reply.
1227	 *
1228	 * Note: We're doing smb_latency_add_sample() for all
1229	 * remaining commands NOW, which means we won't include
1230	 * the async part of their work in latency statistics.
1231	 * That's intentional, as the async part of a command
1232	 * would otherwise skew our latency statistics.
1233	 */
1234	smb2_record_stats(sr, sds, B_FALSE);
1235
1236	/*
1237	 * If there's a next command, figure out where it starts,
1238	 * and fill in the next header offset for the reply.
1239	 * Note: We sanity checked smb2_next_command above.
1240	 */
1241	if (sr->smb2_next_command != 0) {
1242		sr->command.chain_offset =
1243		    sr->smb2_cmd_hdr + sr->smb2_next_command;
1244		sr->smb2_next_reply =
1245		    sr->reply.chain_offset - sr->smb2_reply_hdr;
1246	} else {
1247		ASSERT(sr->smb2_next_reply == 0);
1248	}
1249
1250	/*
1251	 * Overwrite the (now final) SMB2 header for this response.
1252	 */
1253	(void) smb2_encode_header(sr, B_TRUE);
1254
1255	/*
1256	 * Process whole compound before sending.
1257	 */
1258	if (sr->smb2_next_command != 0)
1259		goto cmd_start;
1260	smb2_send_reply(sr);
1261
1262	ASSERT(!disconnect);
1263
1264cleanup:
1265	/*
1266	 * Restore caller's command processing state.
1267	 */
1268	sr->smb2_cmd_hdr = saved_cmd_hdr;
1269	sr->command.chain_offset = saved_cmd_hdr;
1270	(void) smb2_decode_header(sr);
1271	sr->command.chain_offset = saved_com_offset;
1272
1273	sr->smb2_credit_response = saved_cred_resp;
1274	sr->smb2_hdr_flags = saved_hdr_flags;
1275	sr->smb2_status = NT_STATUS_SUCCESS;
1276
1277	/*
1278	 * In here, the "disconnect" flag just means we had an
1279	 * error decoding or encoding something.  Rather than
1280	 * actually disconnect here, let's assume whatever
1281	 * problem we encountered will be seen by the caller
1282	 * as they continue processing the compound, and just
1283	 * restore everything and return an error.
1284	 */
1285	if (disconnect) {
1286		sr->smb2_async = B_FALSE;
1287		sr->smb2_reply_hdr = saved_reply_hdr;
1288		sr->reply.chain_offset = sr->smb2_reply_hdr;
1289		(void) smb2_encode_header(sr, B_FALSE);
1290		return (NT_STATUS_INVALID_PARAMETER);
1291	}
1292
1293	/*
1294	 * The compound reply buffer we sent is now gone.
1295	 * Setup a new reply buffer for the caller.
1296	 */
1297	sr->smb2_hdr_flags |= SMB2_FLAGS_ASYNC_COMMAND;
1298	sr->smb2_async_id = SMB2_ASYNCID(sr);
1299	sr->smb2_next_reply = 0;
1300	MBC_FLUSH(&sr->reply);
1301	ASSERT(sr->reply.max_bytes == sr->session->reply_max_bytes);
1302	ASSERT(sr->reply.chain_offset == 0);
1303	sr->smb2_reply_hdr = 0;
1304	(void) smb2_encode_header(sr, B_FALSE);
1305
1306	return (NT_STATUS_SUCCESS);
1307}
1308
1309int
1310smb3_decode_tform_header(smb_request_t *sr)
1311{
1312	uint16_t flags;
1313	int rc;
1314	uint32_t protocolid;
1315
1316	rc = smb_mbc_decodef(
1317	    &sr->command, "l16c16cl..wq",
1318	    &protocolid,	/*  l  */
1319	    sr->smb2_sig,	/* 16c */
1320	    sr->nonce,	/* 16c */
1321	    &sr->msgsize,	/* l */
1322	    /* reserved	  .. */
1323	    &flags,		/* w */
1324	    &sr->smb3_tform_ssnid); /* q */
1325	if (rc)
1326		return (rc);
1327
1328	ASSERT3U(protocolid, ==, SMB3_ENCRYPTED_MAGIC);
1329
1330	if (flags != 1) {
1331#ifdef DEBUG
1332		cmn_err(CE_NOTE, "flags field not 1: %x", flags);
1333#endif
1334		return (-1);
1335	}
1336
1337	/*
1338	 * MsgSize is the amount of data the client tell us to decrypt.
1339	 * Make sure this value is not too big and not too small.
1340	 */
1341	if (sr->msgsize < SMB2_HDR_SIZE ||
1342	    sr->msgsize > sr->session->cmd_max_bytes ||
1343	    sr->msgsize > sr->command.max_bytes - SMB3_TFORM_HDR_SIZE)
1344		return (-1);
1345
1346	return (rc);
1347}
1348
1349int
1350smb3_encode_tform_header(smb_request_t *sr, struct mbuf_chain *mbc)
1351{
1352	int rc;
1353
1354	/* Signature and Nonce are added in smb3_encrypt_sr */
1355	rc = smb_mbc_encodef(
1356	    mbc, "l32.lwwq",
1357	    SMB3_ENCRYPTED_MAGIC, /* l */
1358	    /* signature(16), nonce(16) 32. */
1359	    sr->msgsize,	/* l */
1360	    0, /* reserved	   w */
1361	    1, /* flags		   w */
1362	    sr->smb3_tform_ssnid); /* q */
1363
1364	return (rc);
1365}
1366
1367int
1368smb2_decode_header(smb_request_t *sr)
1369{
1370	uint32_t pid, tid;
1371	uint16_t hdr_len;
1372	int rc;
1373
1374	rc = smb_mbc_decodef(
1375	    &sr->command, "Nwww..wwllqllq16c",
1376	    &hdr_len,			/* w */
1377	    &sr->smb2_credit_charge,	/* w */
1378	    &sr->smb2_chan_seq,		/* w */
1379	    /* reserved			  .. */
1380	    &sr->smb2_cmd_code,		/* w */
1381	    &sr->smb2_credit_request,	/* w */
1382	    &sr->smb2_hdr_flags,	/* l */
1383	    &sr->smb2_next_command,	/* l */
1384	    &sr->smb2_messageid,	/* q */
1385	    &pid,			/* l */
1386	    &tid,			/* l */
1387	    &sr->smb2_ssnid,		/* q */
1388	    sr->smb2_sig);		/* 16c */
1389	if (rc)
1390		return (rc);
1391
1392	if (hdr_len != SMB2_HDR_SIZE)
1393		return (-1);
1394
1395	if (sr->smb2_hdr_flags & SMB2_FLAGS_ASYNC_COMMAND) {
1396		sr->smb2_async_id = pid |
1397		    ((uint64_t)tid) << 32;
1398		sr->smb_pid = 0;
1399		sr->smb_tid = 0;
1400	} else {
1401		sr->smb2_async_id = 0;
1402		sr->smb_pid = pid;
1403		sr->smb_tid = (uint16_t)tid; /* XXX wide TIDs */
1404	}
1405
1406	return (rc);
1407}
1408
1409int
1410smb2_encode_header(smb_request_t *sr, boolean_t overwrite)
1411{
1412	uint64_t pid_tid_aid; /* pid+tid, or async id */
1413	int rc;
1414
1415	if (sr->smb2_hdr_flags & SMB2_FLAGS_ASYNC_COMMAND) {
1416		pid_tid_aid = sr->smb2_async_id;
1417	} else {
1418		pid_tid_aid = sr->smb_pid |
1419		    ((uint64_t)sr->smb_tid) << 32;
1420	}
1421
1422	if (overwrite) {
1423		rc = smb_mbc_poke(&sr->reply,
1424		    sr->smb2_reply_hdr,
1425		    "Nwwlwwllqqq16c",
1426		    SMB2_HDR_SIZE,		/* w */
1427		    sr->smb2_credit_charge,	/* w */
1428		    sr->smb2_status,		/* l */
1429		    sr->smb2_cmd_code,		/* w */
1430		    sr->smb2_credit_response,	/* w */
1431		    sr->smb2_hdr_flags,		/* l */
1432		    sr->smb2_next_reply,	/* l */
1433		    sr->smb2_messageid,		/* q */
1434		    pid_tid_aid,		/* q */
1435		    sr->smb2_ssnid,		/* q */
1436		    sr->smb2_sig);		/* 16c */
1437	} else {
1438		rc = smb_mbc_encodef(&sr->reply,
1439		    "Nwwlwwllqqq16c",
1440		    SMB2_HDR_SIZE,		/* w */
1441		    sr->smb2_credit_charge,	/* w */
1442		    sr->smb2_status,		/* l */
1443		    sr->smb2_cmd_code,		/* w */
1444		    sr->smb2_credit_response,	/* w */
1445		    sr->smb2_hdr_flags,		/* l */
1446		    sr->smb2_next_reply,	/* l */
1447		    sr->smb2_messageid,		/* q */
1448		    pid_tid_aid,		/* q */
1449		    sr->smb2_ssnid,		/* q */
1450		    sr->smb2_sig);		/* 16c */
1451	}
1452
1453	return (rc);
1454}
1455
1456void
1457smb2_send_reply(smb_request_t *sr)
1458{
1459	struct mbuf_chain enc_reply;
1460	smb_session_t *session = sr->session;
1461	void *tmpbuf;
1462	size_t buflen;
1463	struct mbuf_chain tmp;
1464
1465	/*
1466	 * [MS-SMB2] 3.3.4.1.4 Encrypting the Message
1467	 *
1468	 * When the connection supports encryption and the dialect
1469	 * is 3.x, encrypt if:
1470	 * - The request was encrypted OR
1471	 * - The cmd is not SESSION_SETUP or NEGOTIATE AND
1472	 * -- Session.EncryptData is TRUE OR
1473	 * -- The cmd is not TREE_CONNECT AND
1474	 * --- Tree.EncryptData is TRUE
1475	 *
1476	 * This boils down to sr->tform_ssn != NULL, and the rest
1477	 * is enforced when tform_ssn is set.
1478	 */
1479
1480	if ((session->capabilities & SMB2_CAP_ENCRYPTION) == 0 ||
1481	    sr->tform_ssn == NULL) {
1482		if (smb_session_send(sr->session, 0, &sr->reply) == 0)
1483			sr->reply.chain = 0;
1484		return;
1485	}
1486
1487	sr->msgsize = sr->reply.chain_offset;
1488	(void) MBC_SHADOW_CHAIN(&tmp, &sr->reply,
1489	    0, sr->msgsize);
1490
1491	buflen = SMB3_TFORM_HDR_SIZE + sr->msgsize;
1492
1493	/* taken from smb_request_init_command_mbuf */
1494	tmpbuf = kmem_alloc(buflen, KM_SLEEP);
1495	MBC_ATTACH_BUF(&enc_reply, tmpbuf, buflen);
1496	enc_reply.flags = 0;
1497	enc_reply.shadow_of = NULL;
1498
1499	if (smb3_encode_tform_header(sr, &enc_reply) != 0) {
1500		cmn_err(CE_WARN, "couldn't encode transform header");
1501		goto errout;
1502	}
1503	if (smb3_encrypt_sr(sr, &tmp, &enc_reply) != 0) {
1504		cmn_err(CE_WARN, "smb3 encryption failed");
1505		goto errout;
1506	}
1507
1508	if (smb_session_send(sr->session, 0, &enc_reply) == 0)
1509		enc_reply.chain = 0;
1510	return;
1511
1512errout:
1513	kmem_free(tmpbuf, buflen);
1514	smb_session_disconnect(sr->session);
1515}
1516
1517/*
1518 * This wrapper function exists to help catch calls to smbsr_status()
1519 * (which is SMB1-specific) in common code.  See smbsr_status().
1520 * If the log message below is seen, put a dtrace probe on this
1521 * function with a stack() action to see who is calling the SMB1
1522 * "put error" from common code, and fix it.
1523 */
1524void
1525smbsr_status_smb2(smb_request_t *sr, DWORD status)
1526{
1527	const char *name;
1528
1529	if (sr->smb2_cmd_code < SMB2__NCMDS)
1530		name = smb2_disp_table[sr->smb2_cmd_code].sdt_name;
1531	else
1532		name = "<unknown>";
1533#ifdef	DEBUG
1534	cmn_err(CE_NOTE, "smbsr_status called for %s", name);
1535#endif
1536
1537	smb2sr_put_error_data(sr, status, NULL);
1538}
1539
1540void
1541smb2sr_put_errno(struct smb_request *sr, int errnum)
1542{
1543	uint32_t status = smb_errno2status(errnum);
1544	smb2sr_put_error_data(sr, status, NULL);
1545}
1546
1547void
1548smb2sr_put_error(smb_request_t *sr, uint32_t status)
1549{
1550	smb2sr_put_error_data(sr, status, NULL);
1551}
1552
1553/*
1554 * Build an SMB2 error response.  [MS-SMB2] 2.2.2
1555 */
1556void
1557smb2sr_put_error_data(smb_request_t *sr, uint32_t status, mbuf_chain_t *mbc)
1558{
1559	DWORD len;
1560
1561	/*
1562	 * The common dispatch code writes this when it
1563	 * updates the SMB2 header before sending.
1564	 */
1565	sr->smb2_status = status;
1566
1567	/* Rewind to the end of the SMB header. */
1568	sr->reply.chain_offset = sr->smb2_reply_hdr + SMB2_HDR_SIZE;
1569
1570	/*
1571	 * NB: Must provide at least one byte of error data,
1572	 * per [MS-SMB2] 2.2.2
1573	 */
1574	if (mbc != NULL && (len = MBC_LENGTH(mbc)) != 0) {
1575		(void) smb_mbc_encodef(
1576		    &sr->reply,
1577		    "wwlC",
1578		    9,	/* StructSize */	/* w */
1579		    0,	/* reserved */		/* w */
1580		    len,			/* l */
1581		    mbc);			/* C */
1582	} else {
1583		(void) smb_mbc_encodef(
1584		    &sr->reply,
1585		    "wwl.",
1586		    9,	/* StructSize */	/* w */
1587		    0,	/* reserved */		/* w */
1588		    0);				/* l. */
1589	}
1590}
1591
1592/*
1593 * smb2sr_lookup_fid
1594 *
1595 * Setup sr->fid_ofile, either inherited from a related command,
1596 * or obtained via FID lookup.  Similar inheritance logic as in
1597 * smb2sr_work.
1598 */
1599uint32_t
1600smb2sr_lookup_fid(smb_request_t *sr, smb2fid_t *fid)
1601{
1602	boolean_t related = sr->smb2_hdr_flags &
1603	    SMB2_FLAGS_RELATED_OPERATIONS;
1604
1605	if (related) {
1606		if (sr->fid_ofile == NULL)
1607			return (NT_STATUS_INVALID_PARAMETER);
1608		sr->smb_fid = sr->fid_ofile->f_fid;
1609		return (0);
1610	}
1611
1612	/*
1613	 * If we could be sure this is called only once per cmd,
1614	 * we could simply ASSERT(sr->fid_ofile == NULL) here.
1615	 * However, there are cases where it can be called again
1616	 * handling the same command, so let's tolerate that.
1617	 */
1618	if (sr->fid_ofile == NULL) {
1619		sr->smb_fid = (uint16_t)fid->temporal;
1620		sr->fid_ofile = smb_ofile_lookup_by_fid(sr, sr->smb_fid);
1621	}
1622	if (sr->fid_ofile == NULL ||
1623	    sr->fid_ofile->f_persistid != fid->persistent)
1624		return (NT_STATUS_FILE_CLOSED);
1625
1626	return (0);
1627}
1628
1629/*
1630 * smb2_dispatch_stats_init
1631 *
1632 * Initializes dispatch statistics for SMB2.
1633 * See also smb_dispatch_stats_init(), which fills in
1634 * the lower part of the statistics array, from zero
1635 * through SMB_COM_NUM;
1636 */
1637void
1638smb2_dispatch_stats_init(smb_server_t *sv)
1639{
1640	smb_disp_stats_t *sds = sv->sv_disp_stats2;
1641	smb_kstat_req_t *ksr;
1642	int		i;
1643
1644	ksr = ((smbsrv_kstats_t *)sv->sv_ksp->ks_data)->ks_reqs2;
1645
1646	for (i = 0; i < SMB2__NCMDS; i++, ksr++) {
1647		smb_latency_init(&sds[i].sdt_lat);
1648		(void) strlcpy(ksr->kr_name, smb2_disp_table[i].sdt_name,
1649		    sizeof (ksr->kr_name));
1650	}
1651}
1652
1653/*
1654 * smb2_dispatch_stats_fini
1655 *
1656 * Frees and destroyes the resources used for statistics.
1657 */
1658void
1659smb2_dispatch_stats_fini(smb_server_t *sv)
1660{
1661	smb_disp_stats_t *sds = sv->sv_disp_stats2;
1662	int	i;
1663
1664	for (i = 0; i < SMB2__NCMDS; i++)
1665		smb_latency_destroy(&sds[i].sdt_lat);
1666}
1667
1668void
1669smb2_dispatch_stats_update(smb_server_t *sv,
1670    smb_kstat_req_t *ksr, int first, int nreq)
1671{
1672	smb_disp_stats_t *sds = sv->sv_disp_stats2;
1673	int	i;
1674	int	last;
1675
1676	last = first + nreq - 1;
1677
1678	if ((first < SMB2__NCMDS) && (last < SMB2__NCMDS))  {
1679		for (i = first; i <= last; i++, ksr++) {
1680			ksr->kr_rxb = sds[i].sdt_rxb;
1681			ksr->kr_txb = sds[i].sdt_txb;
1682			mutex_enter(&sds[i].sdt_lat.ly_mutex);
1683			ksr->kr_nreq = sds[i].sdt_lat.ly_a_nreq;
1684			ksr->kr_sum = sds[i].sdt_lat.ly_a_sum;
1685			ksr->kr_a_mean = sds[i].sdt_lat.ly_a_mean;
1686			ksr->kr_a_stddev =
1687			    sds[i].sdt_lat.ly_a_stddev;
1688			ksr->kr_d_mean = sds[i].sdt_lat.ly_d_mean;
1689			ksr->kr_d_stddev =
1690			    sds[i].sdt_lat.ly_d_stddev;
1691			sds[i].sdt_lat.ly_d_mean = 0;
1692			sds[i].sdt_lat.ly_d_nreq = 0;
1693			sds[i].sdt_lat.ly_d_stddev = 0;
1694			sds[i].sdt_lat.ly_d_sum = 0;
1695			mutex_exit(&sds[i].sdt_lat.ly_mutex);
1696		}
1697	}
1698}
1699
1700/*
1701 * Append new_sr to the postwork queue.  sr->smb2_cmd_code encodes
1702 * the action that should be run by this sr.
1703 *
1704 * This queue is rarely used (and normally empty) so we're OK
1705 * using a simple "walk to tail and insert" here.
1706 */
1707void
1708smb2sr_append_postwork(smb_request_t *top_sr, smb_request_t *new_sr)
1709{
1710	smb_request_t *last_sr;
1711
1712	ASSERT(top_sr->session->dialect >= SMB_VERS_2_BASE);
1713
1714	last_sr = top_sr;
1715	while (last_sr->sr_postwork != NULL)
1716		last_sr = last_sr->sr_postwork;
1717
1718	last_sr->sr_postwork = new_sr;
1719}
1720
1721/*
1722 * Run any "post work" that was appended to the main SR while it
1723 * was running.  This is called after the request has been sent
1724 * for the main SR, and used in cases i.e. the oplock code, where
1725 * we need to send something to the client only _after_ the main
1726 * sr request has gone out.
1727 */
1728static void
1729smb2sr_run_postwork(smb_request_t *top_sr)
1730{
1731	smb_request_t *post_sr;	/* the one we're running */
1732	smb_request_t *next_sr;
1733
1734	while ((post_sr = top_sr->sr_postwork) != NULL) {
1735		next_sr = post_sr->sr_postwork;
1736		top_sr->sr_postwork = next_sr;
1737		post_sr->sr_postwork = NULL;
1738
1739		post_sr->sr_worker = top_sr->sr_worker;
1740		post_sr->sr_state = SMB_REQ_STATE_ACTIVE;
1741
1742		switch (post_sr->smb2_cmd_code) {
1743		case SMB2_OPLOCK_BREAK:
1744			smb_oplock_send_brk(post_sr);
1745			break;
1746		default:
1747			ASSERT(0);
1748		}
1749
1750		/*
1751		 * If we have a durable handle, and this operation
1752		 * updated the nvlist, write it out.
1753		 */
1754		if (post_sr->dh_nvl_dirty) {
1755			post_sr->dh_nvl_dirty = B_FALSE;
1756			smb2_dh_update_nvfile(post_sr);
1757		}
1758
1759		post_sr->sr_state = SMB_REQ_STATE_COMPLETED;
1760		smb_request_free(post_sr);
1761	}
1762}
1763