Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : smb2 lib
4 : Copyright (C) Volker Lendecke 2011
5 :
6 : This program is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation; either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include "system/network.h"
22 : #include "../lib/util/tevent_ntstatus.h"
23 : #include "../libcli/smb/smb_common.h"
24 : #include "../libcli/smb/smbXcli_base.h"
25 :
26 : struct smb2cli_session_setup_state {
27 : struct smbXcli_session *session;
28 : uint8_t fixed[24];
29 : uint8_t dyn_pad[1];
30 : struct iovec *recv_iov;
31 : DATA_BLOB out_security_buffer;
32 : NTSTATUS status;
33 : };
34 :
35 : static void smb2cli_session_setup_done(struct tevent_req *subreq);
36 :
37 49408 : struct tevent_req *smb2cli_session_setup_send(TALLOC_CTX *mem_ctx,
38 : struct tevent_context *ev,
39 : struct smbXcli_conn *conn,
40 : uint32_t timeout_msec,
41 : struct smbXcli_session *session,
42 : uint8_t in_flags,
43 : uint32_t in_capabilities,
44 : uint32_t in_channel,
45 : uint64_t in_previous_session_id,
46 : const DATA_BLOB *in_security_buffer)
47 : {
48 1122 : struct tevent_req *req, *subreq;
49 1122 : struct smb2cli_session_setup_state *state;
50 1122 : uint8_t *buf;
51 1122 : uint8_t *dyn;
52 1122 : size_t dyn_len;
53 1122 : uint8_t security_mode;
54 49408 : uint16_t security_buffer_offset = 0;
55 49408 : uint16_t security_buffer_length = 0;
56 :
57 49408 : req = tevent_req_create(mem_ctx, &state,
58 : struct smb2cli_session_setup_state);
59 49408 : if (req == NULL) {
60 0 : return NULL;
61 : }
62 :
63 49408 : if (session == NULL) {
64 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
65 0 : return tevent_req_post(req, ev);
66 : }
67 49408 : state->session = session;
68 49408 : security_mode = smb2cli_session_security_mode(session);
69 :
70 49408 : if (in_security_buffer) {
71 49408 : if (in_security_buffer->length > UINT16_MAX) {
72 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
73 0 : return tevent_req_post(req, ev);
74 : }
75 49408 : security_buffer_offset = SMB2_HDR_BODY + 24;
76 49408 : security_buffer_length = in_security_buffer->length;
77 : }
78 :
79 49408 : buf = state->fixed;
80 :
81 49408 : SSVAL(buf, 0, 25);
82 49408 : SCVAL(buf, 2, in_flags);
83 49408 : SCVAL(buf, 3, security_mode);
84 49408 : SIVAL(buf, 4, in_capabilities);
85 49408 : SIVAL(buf, 8, in_channel);
86 49408 : SSVAL(buf, 12, security_buffer_offset);
87 49408 : SSVAL(buf, 14, security_buffer_length);
88 49408 : SBVAL(buf, 16, in_previous_session_id);
89 :
90 49408 : if (security_buffer_length > 0) {
91 49408 : dyn = in_security_buffer->data;
92 49408 : dyn_len = in_security_buffer->length;
93 : } else {
94 0 : dyn = state->dyn_pad;;
95 0 : dyn_len = sizeof(state->dyn_pad);
96 : }
97 :
98 49408 : subreq = smb2cli_req_send(state, ev,
99 : conn, SMB2_OP_SESSSETUP,
100 : 0, 0, /* flags */
101 : timeout_msec,
102 : NULL, /* tcon */
103 : session,
104 48286 : state->fixed, sizeof(state->fixed),
105 : dyn, dyn_len,
106 : UINT16_MAX); /* max_dyn_len */
107 49408 : if (tevent_req_nomem(subreq, req)) {
108 0 : return tevent_req_post(req, ev);
109 : }
110 49408 : tevent_req_set_callback(subreq, smb2cli_session_setup_done, req);
111 49408 : return req;
112 : }
113 :
114 49408 : static void smb2cli_session_setup_done(struct tevent_req *subreq)
115 : {
116 1122 : struct tevent_req *req =
117 49408 : tevent_req_callback_data(subreq,
118 : struct tevent_req);
119 1122 : struct smb2cli_session_setup_state *state =
120 49408 : tevent_req_data(req,
121 : struct smb2cli_session_setup_state);
122 1122 : NTSTATUS status;
123 1122 : NTSTATUS preauth_status;
124 1122 : uint64_t current_session_id;
125 1122 : uint64_t session_id;
126 1122 : uint16_t session_flags;
127 49408 : uint16_t expected_offset = 0;
128 1122 : uint16_t security_buffer_offset;
129 1122 : uint16_t security_buffer_length;
130 49408 : uint8_t *security_buffer_data = NULL;
131 1122 : struct iovec sent_iov[3];
132 1122 : const uint8_t *hdr;
133 1122 : const uint8_t *body;
134 1122 : static const struct smb2cli_req_expected_response expected[] = {
135 : {
136 : .status = NT_STATUS_MORE_PROCESSING_REQUIRED,
137 : .body_size = 0x09
138 : },
139 : {
140 : .status = NT_STATUS_OK,
141 : .body_size = 0x09
142 : }
143 : };
144 :
145 49408 : status = smb2cli_req_recv(subreq, state, &state->recv_iov,
146 : expected, ARRAY_SIZE(expected));
147 49408 : if (!NT_STATUS_IS_OK(status) &&
148 22938 : !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
149 3981 : TALLOC_FREE(subreq);
150 3981 : tevent_req_nterror(req, status);
151 3981 : return;
152 : }
153 :
154 45427 : smb2cli_req_get_sent_iov(subreq, sent_iov);
155 45427 : preauth_status = smb2cli_session_update_preauth(state->session, sent_iov);
156 45427 : TALLOC_FREE(subreq);
157 45427 : if (tevent_req_nterror(req, preauth_status)) {
158 0 : return;
159 : }
160 :
161 45427 : if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
162 19412 : preauth_status = smb2cli_session_update_preauth(state->session,
163 19412 : state->recv_iov);
164 19412 : if (tevent_req_nterror(req, preauth_status)) {
165 0 : return;
166 : }
167 : }
168 :
169 45427 : hdr = (const uint8_t *)state->recv_iov[0].iov_base;
170 45427 : body = (const uint8_t *)state->recv_iov[1].iov_base;
171 :
172 45427 : session_id = BVAL(hdr, SMB2_HDR_SESSION_ID);
173 45427 : session_flags = SVAL(body, 2);
174 :
175 45427 : security_buffer_offset = SVAL(body, 4);
176 45427 : security_buffer_length = SVAL(body, 6);
177 :
178 45427 : if (security_buffer_length > 0) {
179 45347 : expected_offset = SMB2_HDR_BODY + 8;
180 : }
181 45427 : if (security_buffer_offset != 0) {
182 45427 : security_buffer_data = (uint8_t *)state->recv_iov[2].iov_base;
183 45427 : expected_offset = SMB2_HDR_BODY + 8;
184 : }
185 :
186 45427 : if (security_buffer_offset != expected_offset) {
187 0 : tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
188 0 : return;
189 : }
190 45427 : if (security_buffer_length > state->recv_iov[2].iov_len) {
191 0 : tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
192 0 : return;
193 : }
194 :
195 45427 : state->out_security_buffer.data = security_buffer_data;
196 45427 : state->out_security_buffer.length = security_buffer_length;
197 :
198 45427 : current_session_id = smb2cli_session_current_id(state->session);
199 45427 : if (current_session_id == 0) {
200 : /* A new session was requested */
201 27153 : current_session_id = session_id;
202 : }
203 :
204 45427 : if (current_session_id != session_id) {
205 0 : tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
206 0 : return;
207 : }
208 :
209 45427 : smb2cli_session_set_id_and_flags(state->session,
210 : session_id, session_flags);
211 :
212 45427 : state->status = status;
213 45427 : tevent_req_done(req);
214 : }
215 :
216 49408 : NTSTATUS smb2cli_session_setup_recv(struct tevent_req *req,
217 : TALLOC_CTX *mem_ctx,
218 : struct iovec **recv_iov,
219 : DATA_BLOB *out_security_buffer)
220 : {
221 1122 : struct smb2cli_session_setup_state *state =
222 49408 : tevent_req_data(req,
223 : struct smb2cli_session_setup_state);
224 1122 : NTSTATUS status;
225 1122 : struct iovec *_tmp;
226 :
227 49408 : if (tevent_req_is_nterror(req, &status)) {
228 3981 : tevent_req_received(req);
229 3981 : return status;
230 : }
231 :
232 45427 : if (recv_iov == NULL) {
233 8 : recv_iov = &_tmp;
234 : }
235 :
236 45427 : *recv_iov = talloc_move(mem_ctx, &state->recv_iov);
237 :
238 45427 : *out_security_buffer = state->out_security_buffer;
239 :
240 : /*
241 : * Return the status from the server:
242 : * NT_STATUS_MORE_PROCESSING_REQUIRED or
243 : * NT_STATUS_OK.
244 : */
245 45427 : status = state->status;
246 45427 : tevent_req_received(req);
247 45427 : return status;
248 : }
249 :
250 : struct smb2cli_logoff_state {
251 : uint8_t fixed[4];
252 : };
253 :
254 : static void smb2cli_logoff_done(struct tevent_req *subreq);
255 :
256 26 : struct tevent_req *smb2cli_logoff_send(TALLOC_CTX *mem_ctx,
257 : struct tevent_context *ev,
258 : struct smbXcli_conn *conn,
259 : uint32_t timeout_msec,
260 : struct smbXcli_session *session)
261 : {
262 0 : struct tevent_req *req, *subreq;
263 0 : struct smb2cli_logoff_state *state;
264 :
265 26 : req = tevent_req_create(mem_ctx, &state,
266 : struct smb2cli_logoff_state);
267 26 : if (req == NULL) {
268 0 : return NULL;
269 : }
270 26 : SSVAL(state->fixed, 0, 4);
271 :
272 26 : subreq = smb2cli_req_send(state, ev,
273 : conn, SMB2_OP_LOGOFF,
274 : 0, 0, /* flags */
275 : timeout_msec,
276 : NULL, /* tcon */
277 : session,
278 26 : state->fixed, sizeof(state->fixed),
279 : NULL, 0, /* dyn* */
280 : 0); /* max_dyn_len */
281 26 : if (tevent_req_nomem(subreq, req)) {
282 0 : return tevent_req_post(req, ev);
283 : }
284 26 : tevent_req_set_callback(subreq, smb2cli_logoff_done, req);
285 26 : return req;
286 : }
287 :
288 26 : static void smb2cli_logoff_done(struct tevent_req *subreq)
289 : {
290 0 : struct tevent_req *req =
291 26 : tevent_req_callback_data(subreq,
292 : struct tevent_req);
293 0 : struct smb2cli_logoff_state *state =
294 26 : tevent_req_data(req,
295 : struct smb2cli_logoff_state);
296 0 : NTSTATUS status;
297 0 : struct iovec *iov;
298 0 : static const struct smb2cli_req_expected_response expected[] = {
299 : {
300 : .status = NT_STATUS_OK,
301 : .body_size = 0x04
302 : }
303 : };
304 :
305 26 : status = smb2cli_req_recv(subreq, state, &iov,
306 : expected, ARRAY_SIZE(expected));
307 26 : TALLOC_FREE(subreq);
308 26 : if (tevent_req_nterror(req, status)) {
309 13 : return;
310 : }
311 13 : tevent_req_done(req);
312 : }
313 :
314 26 : NTSTATUS smb2cli_logoff_recv(struct tevent_req *req)
315 : {
316 26 : return tevent_req_simple_recv_ntstatus(req);
317 : }
318 :
319 26 : NTSTATUS smb2cli_logoff(struct smbXcli_conn *conn,
320 : uint32_t timeout_msec,
321 : struct smbXcli_session *session)
322 : {
323 26 : TALLOC_CTX *frame = talloc_stackframe();
324 0 : struct tevent_context *ev;
325 0 : struct tevent_req *req;
326 26 : NTSTATUS status = NT_STATUS_NO_MEMORY;
327 :
328 26 : if (smbXcli_conn_has_async_calls(conn)) {
329 : /*
330 : * Can't use sync call while an async call is in flight
331 : */
332 0 : status = NT_STATUS_INVALID_PARAMETER;
333 0 : goto fail;
334 : }
335 26 : ev = samba_tevent_context_init(frame);
336 26 : if (ev == NULL) {
337 0 : goto fail;
338 : }
339 26 : req = smb2cli_logoff_send(frame, ev, conn, timeout_msec, session);
340 26 : if (req == NULL) {
341 0 : goto fail;
342 : }
343 26 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
344 0 : goto fail;
345 : }
346 26 : status = smb2cli_logoff_recv(req);
347 26 : fail:
348 26 : TALLOC_FREE(frame);
349 26 : return status;
350 : }
|