s3:smbd:smb2: fix an assignment-instead-of-check bug conn_snum_used()
[Samba.git] / source3 / libsmb / smb2cli_session.c
blobd1d65f3f43d625f98858d1151515867f8b3b8301
1 /*
2 Unix SMB/CIFS implementation.
3 smb2 lib
4 Copyright (C) Volker Lendecke 2011
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.
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.
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/>.
20 #include "includes.h"
21 #include "client.h"
22 #include "async_smb.h"
23 #include "smb2cli.h"
24 #include "../libcli/smb/smbXcli_base.h"
25 #include "libsmb/proto.h"
26 #include "lib/util/tevent_ntstatus.h"
27 #include "../libcli/auth/spnego.h"
28 #include "../auth/ntlmssp/ntlmssp.h"
30 struct smb2cli_session_setup_state {
31 struct smbXcli_session *session;
32 uint8_t fixed[24];
33 uint8_t dyn_pad[1];
34 struct iovec *recv_iov;
35 DATA_BLOB out_security_buffer;
36 NTSTATUS status;
39 static void smb2cli_session_setup_done(struct tevent_req *subreq);
41 struct tevent_req *smb2cli_session_setup_send(TALLOC_CTX *mem_ctx,
42 struct tevent_context *ev,
43 struct smbXcli_conn *conn,
44 uint32_t timeout_msec,
45 struct smbXcli_session *session,
46 uint8_t in_flags,
47 uint32_t in_capabilities,
48 uint32_t in_channel,
49 struct smbXcli_session *in_previous_session,
50 const DATA_BLOB *in_security_buffer)
52 struct tevent_req *req, *subreq;
53 struct smb2cli_session_setup_state *state;
54 uint8_t *buf;
55 uint8_t *dyn;
56 size_t dyn_len;
57 uint8_t security_mode;
58 uint16_t security_buffer_offset = 0;
59 uint16_t security_buffer_length = 0;
60 uint64_t previous_session_id = 0;
62 req = tevent_req_create(mem_ctx, &state,
63 struct smb2cli_session_setup_state);
64 if (req == NULL) {
65 return NULL;
68 if (session == NULL) {
69 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
70 return tevent_req_post(req, ev);
72 state->session = session;
73 security_mode = smb2cli_session_security_mode(session);
75 if (in_security_buffer) {
76 if (in_security_buffer->length > UINT16_MAX) {
77 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
78 return tevent_req_post(req, ev);
80 security_buffer_offset = SMB2_HDR_BODY + 24;
81 security_buffer_length = in_security_buffer->length;
84 if (in_previous_session) {
85 previous_session_id =
86 smb2cli_session_current_id(in_previous_session);
89 buf = state->fixed;
91 SSVAL(buf, 0, 25);
92 SCVAL(buf, 2, in_flags);
93 SCVAL(buf, 3, security_mode);
94 SIVAL(buf, 4, in_capabilities);
95 SIVAL(buf, 8, in_channel);
96 SSVAL(buf, 12, security_buffer_offset);
97 SSVAL(buf, 14, security_buffer_length);
98 SBVAL(buf, 16, previous_session_id);
100 if (security_buffer_length > 0) {
101 dyn = in_security_buffer->data;
102 dyn_len = in_security_buffer->length;
103 } else {
104 dyn = state->dyn_pad;;
105 dyn_len = sizeof(state->dyn_pad);
108 subreq = smb2cli_req_send(state, ev,
109 conn, SMB2_OP_SESSSETUP,
110 0, 0, /* flags */
111 timeout_msec,
112 0xFEFF,
113 0, /* tid */
114 session,
115 state->fixed, sizeof(state->fixed),
116 dyn, dyn_len);
117 if (tevent_req_nomem(subreq, req)) {
118 return tevent_req_post(req, ev);
120 tevent_req_set_callback(subreq, smb2cli_session_setup_done, req);
121 return req;
124 static void smb2cli_session_setup_done(struct tevent_req *subreq)
126 struct tevent_req *req =
127 tevent_req_callback_data(subreq,
128 struct tevent_req);
129 struct smb2cli_session_setup_state *state =
130 tevent_req_data(req,
131 struct smb2cli_session_setup_state);
132 NTSTATUS status;
133 uint64_t current_session_id;
134 uint64_t session_id;
135 uint16_t session_flags;
136 uint16_t expected_offset = 0;
137 uint16_t security_buffer_offset;
138 uint16_t security_buffer_length;
139 uint8_t *security_buffer_data = NULL;
140 const uint8_t *hdr;
141 const uint8_t *body;
142 static const struct smb2cli_req_expected_response expected[] = {
144 .status = NT_STATUS_MORE_PROCESSING_REQUIRED,
145 .body_size = 0x09
148 .status = NT_STATUS_OK,
149 .body_size = 0x09
153 status = smb2cli_req_recv(subreq, state, &state->recv_iov,
154 expected, ARRAY_SIZE(expected));
155 TALLOC_FREE(subreq);
156 if (!NT_STATUS_IS_OK(status) &&
157 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
158 tevent_req_nterror(req, status);
159 return;
162 hdr = (const uint8_t *)state->recv_iov[0].iov_base;
163 body = (const uint8_t *)state->recv_iov[1].iov_base;
165 session_id = BVAL(hdr, SMB2_HDR_SESSION_ID);
166 session_flags = SVAL(body, 2);
168 security_buffer_offset = SVAL(body, 4);
169 security_buffer_length = SVAL(body, 6);
171 if (security_buffer_length > 0) {
172 expected_offset = SMB2_HDR_BODY + 8;
174 if (security_buffer_offset != 0) {
175 security_buffer_data = (uint8_t *)state->recv_iov[2].iov_base;
176 expected_offset = SMB2_HDR_BODY + 8;
179 if (security_buffer_offset != expected_offset) {
180 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
181 return;
183 if (security_buffer_length > state->recv_iov[2].iov_len) {
184 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
185 return;
188 state->out_security_buffer.data = security_buffer_data;
189 state->out_security_buffer.length = security_buffer_length;
191 current_session_id = smb2cli_session_current_id(state->session);
192 if (current_session_id == 0) {
193 /* A new session was requested */
194 current_session_id = session_id;
197 if (current_session_id != session_id) {
198 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
199 return;
202 smb2cli_session_set_id_and_flags(state->session,
203 session_id, session_flags);
205 state->status = status;
206 tevent_req_done(req);
209 NTSTATUS smb2cli_session_setup_recv(struct tevent_req *req,
210 TALLOC_CTX *mem_ctx,
211 struct iovec **recv_iov,
212 DATA_BLOB *out_security_buffer)
214 struct smb2cli_session_setup_state *state =
215 tevent_req_data(req,
216 struct smb2cli_session_setup_state);
217 NTSTATUS status;
218 struct iovec *_tmp;
220 if (tevent_req_is_nterror(req, &status)) {
221 tevent_req_received(req);
222 return status;
225 if (recv_iov == NULL) {
226 recv_iov = &_tmp;
229 *recv_iov = talloc_move(mem_ctx, &state->recv_iov);
231 *out_security_buffer = state->out_security_buffer;
234 * Return the status from the server:
235 * NT_STATUS_MORE_PROCESSING_REQUIRED or
236 * NT_STATUS_OK.
238 status = state->status;
239 tevent_req_received(req);
240 return status;
243 struct smb2cli_logoff_state {
244 struct cli_state *cli;
245 uint8_t fixed[4];
248 static void smb2cli_logoff_done(struct tevent_req *subreq);
250 struct tevent_req *smb2cli_logoff_send(TALLOC_CTX *mem_ctx,
251 struct tevent_context *ev,
252 struct cli_state *cli)
254 struct tevent_req *req, *subreq;
255 struct smb2cli_logoff_state *state;
257 req = tevent_req_create(mem_ctx, &state,
258 struct smb2cli_logoff_state);
259 if (req == NULL) {
260 return NULL;
262 state->cli = cli;
263 SSVAL(state->fixed, 0, 4);
265 subreq = smb2cli_req_send(state, ev,
266 cli->conn, SMB2_OP_LOGOFF,
267 0, 0, /* flags */
268 cli->timeout,
269 cli->smb2.pid,
270 0, /* tid */
271 cli->smb2.session,
272 state->fixed, sizeof(state->fixed),
273 NULL, 0);
274 if (tevent_req_nomem(subreq, req)) {
275 return tevent_req_post(req, ev);
277 tevent_req_set_callback(subreq, smb2cli_logoff_done, req);
278 return req;
281 static void smb2cli_logoff_done(struct tevent_req *subreq)
283 struct tevent_req *req =
284 tevent_req_callback_data(subreq,
285 struct tevent_req);
286 struct smb2cli_logoff_state *state =
287 tevent_req_data(req,
288 struct smb2cli_logoff_state);
289 NTSTATUS status;
290 struct iovec *iov;
291 static const struct smb2cli_req_expected_response expected[] = {
293 .status = NT_STATUS_OK,
294 .body_size = 0x04
298 status = smb2cli_req_recv(subreq, state, &iov,
299 expected, ARRAY_SIZE(expected));
300 TALLOC_FREE(subreq);
301 TALLOC_FREE(state->cli->smb2.session);
302 if (tevent_req_nterror(req, status)) {
303 return;
305 tevent_req_done(req);
308 NTSTATUS smb2cli_logoff_recv(struct tevent_req *req)
310 return tevent_req_simple_recv_ntstatus(req);
313 NTSTATUS smb2cli_logoff(struct cli_state *cli)
315 TALLOC_CTX *frame = talloc_stackframe();
316 struct event_context *ev;
317 struct tevent_req *req;
318 NTSTATUS status = NT_STATUS_NO_MEMORY;
320 if (cli_has_async_calls(cli)) {
322 * Can't use sync call while an async call is in flight
324 status = NT_STATUS_INVALID_PARAMETER;
325 goto fail;
327 ev = event_context_init(frame);
328 if (ev == NULL) {
329 goto fail;
331 req = smb2cli_logoff_send(frame, ev, cli);
332 if (req == NULL) {
333 goto fail;
335 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
336 goto fail;
338 status = smb2cli_logoff_recv(req);
339 fail:
340 TALLOC_FREE(frame);
341 return status;