xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb2_session_setup.c (revision 4e065a9f6a4471f1001853cd10a093bc5beb58a5)
1a90cf9f2SGordon Ross /*
2a90cf9f2SGordon Ross  * This file and its contents are supplied under the terms of the
3a90cf9f2SGordon Ross  * Common Development and Distribution License ("CDDL"), version 1.0.
4a90cf9f2SGordon Ross  * You may only use this file in accordance with the terms of version
5a90cf9f2SGordon Ross  * 1.0 of the CDDL.
6a90cf9f2SGordon Ross  *
7a90cf9f2SGordon Ross  * A full copy of the text of the CDDL should have accompanied this
8a90cf9f2SGordon Ross  * source.  A copy of the CDDL is also available via the Internet at
9a90cf9f2SGordon Ross  * http://www.illumos.org/license/CDDL.
10a90cf9f2SGordon Ross  */
11a90cf9f2SGordon Ross 
12a90cf9f2SGordon Ross /*
1393bc28dbSGordon Ross  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
14*4e065a9fSAlexander Stetsenko  * Copyright 2020 RackTop Systems, Inc.
15a90cf9f2SGordon Ross  */
16a90cf9f2SGordon Ross 
17a90cf9f2SGordon Ross /*
18a90cf9f2SGordon Ross  * Dispatch function for SMB2_SESSION_SETUP
19a90cf9f2SGordon Ross  *
20a90cf9f2SGordon Ross  * Note that the Capabilities supplied in this request are an inferior
21a90cf9f2SGordon Ross  * subset of those given to us previously in the SMB2 Negotiate request.
22a90cf9f2SGordon Ross  * We need to remember the full set of capabilities from SMB2 Negotiate,
23a90cf9f2SGordon Ross  * and therefore ignore the subset of capabilities supplied here.
24a90cf9f2SGordon Ross  */
25a90cf9f2SGordon Ross 
26a90cf9f2SGordon Ross #include <smbsrv/smb2_kproto.h>
27a90cf9f2SGordon Ross 
28a90cf9f2SGordon Ross static void smb2_ss_adjust_credits(smb_request_t *);
29a90cf9f2SGordon Ross 
30a90cf9f2SGordon Ross smb_sdrc_t
smb2_session_setup(smb_request_t * sr)31a90cf9f2SGordon Ross smb2_session_setup(smb_request_t *sr)
32a90cf9f2SGordon Ross {
33a90cf9f2SGordon Ross 	smb_arg_sessionsetup_t	*sinfo;
34a90cf9f2SGordon Ross 	uint16_t StructureSize;
35a90cf9f2SGordon Ross 	uint8_t  Flags;
36a90cf9f2SGordon Ross 	uint8_t  SecurityMode;
37a90cf9f2SGordon Ross 	uint32_t Capabilities;	/* ignored - see above */
38a90cf9f2SGordon Ross 	uint32_t Channel;
39a90cf9f2SGordon Ross 	uint16_t SecBufOffset;
40a90cf9f2SGordon Ross 	uint16_t SecBufLength;
41811599a4SMatt Barden 	uint64_t PrevSsnId;
42a90cf9f2SGordon Ross 	uint16_t SessionFlags;
43a90cf9f2SGordon Ross 	uint32_t status;
44a90cf9f2SGordon Ross 	int skip;
45a90cf9f2SGordon Ross 	int rc = 0;
46a90cf9f2SGordon Ross 
47a90cf9f2SGordon Ross 	sinfo = smb_srm_zalloc(sr, sizeof (smb_arg_sessionsetup_t));
48a90cf9f2SGordon Ross 	sr->sr_ssetup = sinfo;
49a90cf9f2SGordon Ross 
50a90cf9f2SGordon Ross 	rc = smb_mbc_decodef(
51a90cf9f2SGordon Ross 	    &sr->smb_data, "wbbllwwq",
52a90cf9f2SGordon Ross 	    &StructureSize,	/* w */
53a90cf9f2SGordon Ross 	    &Flags,		/* b */
54a90cf9f2SGordon Ross 	    &SecurityMode,	/* b */
55a90cf9f2SGordon Ross 	    &Capabilities,	/* l */
56a90cf9f2SGordon Ross 	    &Channel,		/* l */
57a90cf9f2SGordon Ross 	    &SecBufOffset,	/* w */
58a90cf9f2SGordon Ross 	    &SecBufLength,	/* w */
59811599a4SMatt Barden 	    &PrevSsnId);	/* q */
60a90cf9f2SGordon Ross 	if (rc)
61a90cf9f2SGordon Ross 		return (SDRC_ERROR);
62a90cf9f2SGordon Ross 
63a90cf9f2SGordon Ross 	/*
64a90cf9f2SGordon Ross 	 * We're normally positioned at the security buffer now,
65a90cf9f2SGordon Ross 	 * but there could be some padding before it.
66a90cf9f2SGordon Ross 	 */
67a90cf9f2SGordon Ross 	skip = (SecBufOffset + sr->smb2_cmd_hdr) -
68a90cf9f2SGordon Ross 	    sr->smb_data.chain_offset;
69a90cf9f2SGordon Ross 	if (skip < 0)
70a90cf9f2SGordon Ross 		return (SDRC_ERROR);
71a90cf9f2SGordon Ross 	if (skip > 0)
72a90cf9f2SGordon Ross 		(void) smb_mbc_decodef(&sr->smb_data, "#.", skip);
73a90cf9f2SGordon Ross 
74a90cf9f2SGordon Ross 	/*
75a90cf9f2SGordon Ross 	 * Get the security buffer
76a90cf9f2SGordon Ross 	 */
77a90cf9f2SGordon Ross 	sinfo->ssi_iseclen = SecBufLength;
78a90cf9f2SGordon Ross 	sinfo->ssi_isecblob = smb_srm_zalloc(sr, sinfo->ssi_iseclen);
79a90cf9f2SGordon Ross 	rc = smb_mbc_decodef(&sr->smb_data, "#c",
80a90cf9f2SGordon Ross 	    sinfo->ssi_iseclen, sinfo->ssi_isecblob);
81a90cf9f2SGordon Ross 	if (rc)
82a90cf9f2SGordon Ross 		return (SDRC_ERROR);
83a90cf9f2SGordon Ross 
84a90cf9f2SGordon Ross 	/*
8593bc28dbSGordon Ross 	 * Decoded everything.  Dtrace probe,
8693bc28dbSGordon Ross 	 * then no more early returns.
8793bc28dbSGordon Ross 	 */
8893bc28dbSGordon Ross 	DTRACE_SMB2_START(op__SessionSetup, smb_request_t *, sr);
8993bc28dbSGordon Ross 
9093bc28dbSGordon Ross 	/*
911160dcf7SMatt Barden 	 * [MS-SMB2] 3.3.5.5 Receiving an SMB2 SESSION_SETUP Request
921160dcf7SMatt Barden 	 *
931160dcf7SMatt Barden 	 * If we support 3.x, RejectUnencryptedAccess is TRUE,
941160dcf7SMatt Barden 	 * global EncryptData is TRUE, but we're not talking
951160dcf7SMatt Barden 	 * 3.x or the client doesn't support encryption,
961160dcf7SMatt Barden 	 * return ACCESS_DENIED.
971160dcf7SMatt Barden 	 *
981160dcf7SMatt Barden 	 * If RejectUnencryptedAccess is TRUE, we force max_protocol
991160dcf7SMatt Barden 	 * to at least 3.0.
1001160dcf7SMatt Barden 	 */
1011160dcf7SMatt Barden 	if (sr->sr_server->sv_cfg.skc_encrypt == SMB_CONFIG_REQUIRED &&
1021160dcf7SMatt Barden 	    (sr->session->dialect < SMB_VERS_3_0 ||
1031160dcf7SMatt Barden 	    !SMB3_CLIENT_ENCRYPTS(sr))) {
1041160dcf7SMatt Barden 		status = NT_STATUS_ACCESS_DENIED;
1051160dcf7SMatt Barden 		goto errout;
1061160dcf7SMatt Barden 	}
1071160dcf7SMatt Barden 
1081160dcf7SMatt Barden 	/*
1091160dcf7SMatt Barden 	 * SMB3 multi-channel features are not supported.
1101160dcf7SMatt Barden 	 * Once they are, this will check the dialect and
1111160dcf7SMatt Barden 	 * whether multi-channel was negotiated, i.e.
1121160dcf7SMatt Barden 	 *	if (sr->session->dialect < SMB_VERS_3_0 ||
1131160dcf7SMatt Barden 	 *	    s->IsMultiChannelCapable == False)
1141160dcf7SMatt Barden 	 *		return (error...)
1151160dcf7SMatt Barden 	 */
1161160dcf7SMatt Barden 	if (Flags & SMB2_SESSION_FLAG_BINDING) {
1171160dcf7SMatt Barden 		status = NT_STATUS_REQUEST_NOT_ACCEPTED;
1181160dcf7SMatt Barden 		goto errout;
1191160dcf7SMatt Barden 	}
1201160dcf7SMatt Barden 
1211160dcf7SMatt Barden 	/*
122a90cf9f2SGordon Ross 	 * The real auth. work happens in here.
123a90cf9f2SGordon Ross 	 */
124a90cf9f2SGordon Ross 	status = smb_authenticate_ext(sr);
125a90cf9f2SGordon Ross 
126a90cf9f2SGordon Ross 	SecBufOffset = SMB2_HDR_SIZE + 8;
127a90cf9f2SGordon Ross 	SecBufLength = sinfo->ssi_oseclen;
128a90cf9f2SGordon Ross 	SessionFlags = 0;
129a90cf9f2SGordon Ross 
130a90cf9f2SGordon Ross 	switch (status) {
131a90cf9f2SGordon Ross 
132a90cf9f2SGordon Ross 	case NT_STATUS_SUCCESS:	/* Authenticated */
1331160dcf7SMatt Barden 		if ((sr->uid_user->u_flags & SMB_USER_FLAG_GUEST) != 0)
134a90cf9f2SGordon Ross 			SessionFlags |= SMB2_SESSION_FLAG_IS_GUEST;
1351160dcf7SMatt Barden 		if ((sr->uid_user->u_flags & SMB_USER_FLAG_ANON) != 0)
136a90cf9f2SGordon Ross 			SessionFlags |= SMB2_SESSION_FLAG_IS_NULL;
1371160dcf7SMatt Barden 		if (sr->uid_user->u_encrypt != SMB_CONFIG_DISABLED)
1381160dcf7SMatt Barden 			SessionFlags |= SMB2_SESSION_FLAG_ENCRYPT_DATA;
139a90cf9f2SGordon Ross 		smb2_ss_adjust_credits(sr);
140811599a4SMatt Barden 
141811599a4SMatt Barden 		/*
142811599a4SMatt Barden 		 * PrevSsnId is a session that the client is reporting as
143811599a4SMatt Barden 		 * having gone away, and for which we might not yet have seen
144811599a4SMatt Barden 		 * a disconnect. We need to log off the previous session so
145811599a4SMatt Barden 		 * any durable handles in that session will become orphans
146811599a4SMatt Barden 		 * that can be reclaimed in this new session.  Note that
147811599a4SMatt Barden 		 * either zero or the _current_ session ID means there is
148811599a4SMatt Barden 		 * no previous session to logoff.
149811599a4SMatt Barden 		 */
150811599a4SMatt Barden 		if (PrevSsnId != 0 &&
151811599a4SMatt Barden 		    PrevSsnId != sr->smb2_ssnid)
152811599a4SMatt Barden 			smb_server_logoff_ssnid(sr, PrevSsnId);
153a90cf9f2SGordon Ross 		break;
154a90cf9f2SGordon Ross 
155a90cf9f2SGordon Ross 	/*
156a90cf9f2SGordon Ross 	 * This is not really an error, but tells the client
157a90cf9f2SGordon Ross 	 * it should send another session setup request.
158a90cf9f2SGordon Ross 	 * Not smb2_put_error because we send a payload.
159a90cf9f2SGordon Ross 	 */
160a90cf9f2SGordon Ross 	case NT_STATUS_MORE_PROCESSING_REQUIRED:
161a90cf9f2SGordon Ross 		sr->smb2_status = status;
162a90cf9f2SGordon Ross 		break;
163a90cf9f2SGordon Ross 
164a90cf9f2SGordon Ross 	default:
165c51c88bdSMatt Barden errout:
166a90cf9f2SGordon Ross 		SecBufLength = 0;
167a90cf9f2SGordon Ross 		sr->smb2_status = status;
168a90cf9f2SGordon Ross 		break;
169a90cf9f2SGordon Ross 	}
170a90cf9f2SGordon Ross 
17193bc28dbSGordon Ross 	/* sr->smb2_status set above */
17293bc28dbSGordon Ross 	DTRACE_SMB2_DONE(op__SessionSetup, smb_request_t *, sr);
17393bc28dbSGordon Ross 
174a90cf9f2SGordon Ross 	/*
175a90cf9f2SGordon Ross 	 * SMB2 Session Setup reply
176a90cf9f2SGordon Ross 	 */
177a90cf9f2SGordon Ross 
178a90cf9f2SGordon Ross 	rc = smb_mbc_encodef(
179a90cf9f2SGordon Ross 	    &sr->reply,
180a90cf9f2SGordon Ross 	    "wwww#c",
181a90cf9f2SGordon Ross 	    9,	/* StructSize */	/* w */
182a90cf9f2SGordon Ross 	    SessionFlags,		/* w */
183a90cf9f2SGordon Ross 	    SecBufOffset,		/* w */
184a90cf9f2SGordon Ross 	    SecBufLength,		/* w */
185a90cf9f2SGordon Ross 	    SecBufLength,		/* # */
186a90cf9f2SGordon Ross 	    sinfo->ssi_osecblob);	/* c */
187a90cf9f2SGordon Ross 	if (rc)
18893bc28dbSGordon Ross 		sr->smb2_status = NT_STATUS_INTERNAL_ERROR;
189a90cf9f2SGordon Ross 
190a90cf9f2SGordon Ross 	return (SDRC_SUCCESS);
191a90cf9f2SGordon Ross }
192a90cf9f2SGordon Ross 
193a90cf9f2SGordon Ross /*
194a90cf9f2SGordon Ross  * After a successful authentication, raise s_max_credits up to the
195a90cf9f2SGordon Ross  * normal maximum that clients are allowed to request.  Also, if we
196a90cf9f2SGordon Ross  * haven't yet given them their initial credits, do that now.
197a90cf9f2SGordon Ross  *
198a90cf9f2SGordon Ross  * Normally, clients will request some credits with session setup,
199a90cf9f2SGordon Ross  * but in case they don't request enough to raise s_cur_credits
200a90cf9f2SGordon Ross  * up to the configured initial_credits, increase the requested
201a90cf9f2SGordon Ross  * credits of this SR sufficiently to make that happen.  The actual
202a90cf9f2SGordon Ross  * increase happens in the dispatch code after we return.
203a90cf9f2SGordon Ross  */
204a90cf9f2SGordon Ross static void
smb2_ss_adjust_credits(smb_request_t * sr)205a90cf9f2SGordon Ross smb2_ss_adjust_credits(smb_request_t *sr)
206a90cf9f2SGordon Ross {
207a90cf9f2SGordon Ross 	smb_session_t *s = sr->session;
208a90cf9f2SGordon Ross 
209a90cf9f2SGordon Ross 	mutex_enter(&s->s_credits_mutex);
210a90cf9f2SGordon Ross 	s->s_max_credits = s->s_cfg.skc_maximum_credits;
211a90cf9f2SGordon Ross 
212a90cf9f2SGordon Ross 	if (s->s_cur_credits < s->s_cfg.skc_initial_credits) {
213a90cf9f2SGordon Ross 		uint16_t grant;
214a90cf9f2SGordon Ross 
215a90cf9f2SGordon Ross 		/* How many credits we want to grant with this SR. */
216a90cf9f2SGordon Ross 		grant = s->s_cfg.skc_initial_credits - s->s_cur_credits;
217a90cf9f2SGordon Ross 
218a90cf9f2SGordon Ross 		/*
219a90cf9f2SGordon Ross 		 * Do we need to increase the smb2_credit_request?
220a90cf9f2SGordon Ross 		 * One might prefer to read this expression as:
221a90cf9f2SGordon Ross 		 *	((credit_request - credit_charge) < grant)
222a90cf9f2SGordon Ross 		 * but we know credit_charge == 1 and would rather not
223a90cf9f2SGordon Ross 		 * deal with a possibly negative value on the left,
224a90cf9f2SGordon Ross 		 * so adding credit_charge to both sides...
225a90cf9f2SGordon Ross 		 */
226a90cf9f2SGordon Ross 		if (sr->smb2_credit_request < (grant + 1)) {
227a90cf9f2SGordon Ross 			sr->smb2_credit_request = (grant + 1);
228a90cf9f2SGordon Ross 		}
229a90cf9f2SGordon Ross 	}
230a90cf9f2SGordon Ross 
231a90cf9f2SGordon Ross 	mutex_exit(&s->s_credits_mutex);
232a90cf9f2SGordon Ross }
233