xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb2_session_setup.c (revision 4e065a9f6a4471f1001853cd10a093bc5beb58a5)
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 2017 Nexenta Systems, Inc.  All rights reserved.
14  * Copyright 2020 RackTop Systems, Inc.
15  */
16 
17 /*
18  * Dispatch function for SMB2_SESSION_SETUP
19  *
20  * Note that the Capabilities supplied in this request are an inferior
21  * subset of those given to us previously in the SMB2 Negotiate request.
22  * We need to remember the full set of capabilities from SMB2 Negotiate,
23  * and therefore ignore the subset of capabilities supplied here.
24  */
25 
26 #include <smbsrv/smb2_kproto.h>
27 
28 static void smb2_ss_adjust_credits(smb_request_t *);
29 
30 smb_sdrc_t
31 smb2_session_setup(smb_request_t *sr)
32 {
33 	smb_arg_sessionsetup_t	*sinfo;
34 	uint16_t StructureSize;
35 	uint8_t  Flags;
36 	uint8_t  SecurityMode;
37 	uint32_t Capabilities;	/* ignored - see above */
38 	uint32_t Channel;
39 	uint16_t SecBufOffset;
40 	uint16_t SecBufLength;
41 	uint64_t PrevSsnId;
42 	uint16_t SessionFlags;
43 	uint32_t status;
44 	int skip;
45 	int rc = 0;
46 
47 	sinfo = smb_srm_zalloc(sr, sizeof (smb_arg_sessionsetup_t));
48 	sr->sr_ssetup = sinfo;
49 
50 	rc = smb_mbc_decodef(
51 	    &sr->smb_data, "wbbllwwq",
52 	    &StructureSize,	/* w */
53 	    &Flags,		/* b */
54 	    &SecurityMode,	/* b */
55 	    &Capabilities,	/* l */
56 	    &Channel,		/* l */
57 	    &SecBufOffset,	/* w */
58 	    &SecBufLength,	/* w */
59 	    &PrevSsnId);	/* q */
60 	if (rc)
61 		return (SDRC_ERROR);
62 
63 	/*
64 	 * We're normally positioned at the security buffer now,
65 	 * but there could be some padding before it.
66 	 */
67 	skip = (SecBufOffset + sr->smb2_cmd_hdr) -
68 	    sr->smb_data.chain_offset;
69 	if (skip < 0)
70 		return (SDRC_ERROR);
71 	if (skip > 0)
72 		(void) smb_mbc_decodef(&sr->smb_data, "#.", skip);
73 
74 	/*
75 	 * Get the security buffer
76 	 */
77 	sinfo->ssi_iseclen = SecBufLength;
78 	sinfo->ssi_isecblob = smb_srm_zalloc(sr, sinfo->ssi_iseclen);
79 	rc = smb_mbc_decodef(&sr->smb_data, "#c",
80 	    sinfo->ssi_iseclen, sinfo->ssi_isecblob);
81 	if (rc)
82 		return (SDRC_ERROR);
83 
84 	/*
85 	 * Decoded everything.  Dtrace probe,
86 	 * then no more early returns.
87 	 */
88 	DTRACE_SMB2_START(op__SessionSetup, smb_request_t *, sr);
89 
90 	/*
91 	 * [MS-SMB2] 3.3.5.5 Receiving an SMB2 SESSION_SETUP Request
92 	 *
93 	 * If we support 3.x, RejectUnencryptedAccess is TRUE,
94 	 * global EncryptData is TRUE, but we're not talking
95 	 * 3.x or the client doesn't support encryption,
96 	 * return ACCESS_DENIED.
97 	 *
98 	 * If RejectUnencryptedAccess is TRUE, we force max_protocol
99 	 * to at least 3.0.
100 	 */
101 	if (sr->sr_server->sv_cfg.skc_encrypt == SMB_CONFIG_REQUIRED &&
102 	    (sr->session->dialect < SMB_VERS_3_0 ||
103 	    !SMB3_CLIENT_ENCRYPTS(sr))) {
104 		status = NT_STATUS_ACCESS_DENIED;
105 		goto errout;
106 	}
107 
108 	/*
109 	 * SMB3 multi-channel features are not supported.
110 	 * Once they are, this will check the dialect and
111 	 * whether multi-channel was negotiated, i.e.
112 	 *	if (sr->session->dialect < SMB_VERS_3_0 ||
113 	 *	    s->IsMultiChannelCapable == False)
114 	 *		return (error...)
115 	 */
116 	if (Flags & SMB2_SESSION_FLAG_BINDING) {
117 		status = NT_STATUS_REQUEST_NOT_ACCEPTED;
118 		goto errout;
119 	}
120 
121 	/*
122 	 * The real auth. work happens in here.
123 	 */
124 	status = smb_authenticate_ext(sr);
125 
126 	SecBufOffset = SMB2_HDR_SIZE + 8;
127 	SecBufLength = sinfo->ssi_oseclen;
128 	SessionFlags = 0;
129 
130 	switch (status) {
131 
132 	case NT_STATUS_SUCCESS:	/* Authenticated */
133 		if ((sr->uid_user->u_flags & SMB_USER_FLAG_GUEST) != 0)
134 			SessionFlags |= SMB2_SESSION_FLAG_IS_GUEST;
135 		if ((sr->uid_user->u_flags & SMB_USER_FLAG_ANON) != 0)
136 			SessionFlags |= SMB2_SESSION_FLAG_IS_NULL;
137 		if (sr->uid_user->u_encrypt != SMB_CONFIG_DISABLED)
138 			SessionFlags |= SMB2_SESSION_FLAG_ENCRYPT_DATA;
139 		smb2_ss_adjust_credits(sr);
140 
141 		/*
142 		 * PrevSsnId is a session that the client is reporting as
143 		 * having gone away, and for which we might not yet have seen
144 		 * a disconnect. We need to log off the previous session so
145 		 * any durable handles in that session will become orphans
146 		 * that can be reclaimed in this new session.  Note that
147 		 * either zero or the _current_ session ID means there is
148 		 * no previous session to logoff.
149 		 */
150 		if (PrevSsnId != 0 &&
151 		    PrevSsnId != sr->smb2_ssnid)
152 			smb_server_logoff_ssnid(sr, PrevSsnId);
153 		break;
154 
155 	/*
156 	 * This is not really an error, but tells the client
157 	 * it should send another session setup request.
158 	 * Not smb2_put_error because we send a payload.
159 	 */
160 	case NT_STATUS_MORE_PROCESSING_REQUIRED:
161 		sr->smb2_status = status;
162 		break;
163 
164 	default:
165 errout:
166 		SecBufLength = 0;
167 		sr->smb2_status = status;
168 		break;
169 	}
170 
171 	/* sr->smb2_status set above */
172 	DTRACE_SMB2_DONE(op__SessionSetup, smb_request_t *, sr);
173 
174 	/*
175 	 * SMB2 Session Setup reply
176 	 */
177 
178 	rc = smb_mbc_encodef(
179 	    &sr->reply,
180 	    "wwww#c",
181 	    9,	/* StructSize */	/* w */
182 	    SessionFlags,		/* w */
183 	    SecBufOffset,		/* w */
184 	    SecBufLength,		/* w */
185 	    SecBufLength,		/* # */
186 	    sinfo->ssi_osecblob);	/* c */
187 	if (rc)
188 		sr->smb2_status = NT_STATUS_INTERNAL_ERROR;
189 
190 	return (SDRC_SUCCESS);
191 }
192 
193 /*
194  * After a successful authentication, raise s_max_credits up to the
195  * normal maximum that clients are allowed to request.  Also, if we
196  * haven't yet given them their initial credits, do that now.
197  *
198  * Normally, clients will request some credits with session setup,
199  * but in case they don't request enough to raise s_cur_credits
200  * up to the configured initial_credits, increase the requested
201  * credits of this SR sufficiently to make that happen.  The actual
202  * increase happens in the dispatch code after we return.
203  */
204 static void
205 smb2_ss_adjust_credits(smb_request_t *sr)
206 {
207 	smb_session_t *s = sr->session;
208 
209 	mutex_enter(&s->s_credits_mutex);
210 	s->s_max_credits = s->s_cfg.skc_maximum_credits;
211 
212 	if (s->s_cur_credits < s->s_cfg.skc_initial_credits) {
213 		uint16_t grant;
214 
215 		/* How many credits we want to grant with this SR. */
216 		grant = s->s_cfg.skc_initial_credits - s->s_cur_credits;
217 
218 		/*
219 		 * Do we need to increase the smb2_credit_request?
220 		 * One might prefer to read this expression as:
221 		 *	((credit_request - credit_charge) < grant)
222 		 * but we know credit_charge == 1 and would rather not
223 		 * deal with a possibly negative value on the left,
224 		 * so adding credit_charge to both sides...
225 		 */
226 		if (sr->smb2_credit_request < (grant + 1)) {
227 			sr->smb2_credit_request = (grant + 1);
228 		}
229 	}
230 
231 	mutex_exit(&s->s_credits_mutex);
232 }
233