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