dbwrap: Fix a enum conversion
[Samba.git] / libcli / smb / smb2cli_session.c
blob65a604a585a1ace9b301f7e1a11d499c5f603008
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 "system/network.h"
22 #include "../lib/util/tevent_ntstatus.h"
23 #include "../libcli/smb/smb_common.h"
24 #include "../libcli/smb/smbXcli_base.h"
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;
35 static void smb2cli_session_setup_done(struct tevent_req *subreq);
37 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)
48 struct tevent_req *req, *subreq;
49 struct smb2cli_session_setup_state *state;
50 uint8_t *buf;
51 uint8_t *dyn;
52 size_t dyn_len;
53 uint8_t security_mode;
54 uint16_t security_buffer_offset = 0;
55 uint16_t security_buffer_length = 0;
57 req = tevent_req_create(mem_ctx, &state,
58 struct smb2cli_session_setup_state);
59 if (req == NULL) {
60 return NULL;
63 if (session == NULL) {
64 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
65 return tevent_req_post(req, ev);
67 state->session = session;
68 security_mode = smb2cli_session_security_mode(session);
70 if (in_security_buffer) {
71 if (in_security_buffer->length > UINT16_MAX) {
72 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
73 return tevent_req_post(req, ev);
75 security_buffer_offset = SMB2_HDR_BODY + 24;
76 security_buffer_length = in_security_buffer->length;
79 buf = state->fixed;
81 SSVAL(buf, 0, 25);
82 SCVAL(buf, 2, in_flags);
83 SCVAL(buf, 3, security_mode);
84 SIVAL(buf, 4, in_capabilities);
85 SIVAL(buf, 8, in_channel);
86 SSVAL(buf, 12, security_buffer_offset);
87 SSVAL(buf, 14, security_buffer_length);
88 SBVAL(buf, 16, in_previous_session_id);
90 if (security_buffer_length > 0) {
91 dyn = in_security_buffer->data;
92 dyn_len = in_security_buffer->length;
93 } else {
94 dyn = state->dyn_pad;;
95 dyn_len = sizeof(state->dyn_pad);
98 subreq = smb2cli_req_send(state, ev,
99 conn, SMB2_OP_SESSSETUP,
100 0, 0, /* flags */
101 timeout_msec,
102 NULL, /* tcon */
103 session,
104 state->fixed, sizeof(state->fixed),
105 dyn, dyn_len,
106 UINT16_MAX); /* max_dyn_len */
107 if (tevent_req_nomem(subreq, req)) {
108 return tevent_req_post(req, ev);
110 tevent_req_set_callback(subreq, smb2cli_session_setup_done, req);
111 return req;
114 static void smb2cli_session_setup_done(struct tevent_req *subreq)
116 struct tevent_req *req =
117 tevent_req_callback_data(subreq,
118 struct tevent_req);
119 struct smb2cli_session_setup_state *state =
120 tevent_req_data(req,
121 struct smb2cli_session_setup_state);
122 NTSTATUS status;
123 NTSTATUS preauth_status;
124 uint64_t current_session_id;
125 uint64_t session_id;
126 uint16_t session_flags;
127 uint16_t expected_offset = 0;
128 uint16_t security_buffer_offset;
129 uint16_t security_buffer_length;
130 uint8_t *security_buffer_data = NULL;
131 struct iovec sent_iov[3];
132 const uint8_t *hdr;
133 const uint8_t *body;
134 static const struct smb2cli_req_expected_response expected[] = {
136 .status = NT_STATUS_MORE_PROCESSING_REQUIRED,
137 .body_size = 0x09
140 .status = NT_STATUS_OK,
141 .body_size = 0x09
145 status = smb2cli_req_recv(subreq, state, &state->recv_iov,
146 expected, ARRAY_SIZE(expected));
147 if (!NT_STATUS_IS_OK(status) &&
148 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
149 TALLOC_FREE(subreq);
150 tevent_req_nterror(req, status);
151 return;
154 smb2cli_req_get_sent_iov(subreq, sent_iov);
155 preauth_status = smb2cli_session_update_preauth(state->session, sent_iov);
156 TALLOC_FREE(subreq);
157 if (tevent_req_nterror(req, preauth_status)) {
158 return;
161 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
162 preauth_status = smb2cli_session_update_preauth(state->session,
163 state->recv_iov);
164 if (tevent_req_nterror(req, preauth_status)) {
165 return;
169 hdr = (const uint8_t *)state->recv_iov[0].iov_base;
170 body = (const uint8_t *)state->recv_iov[1].iov_base;
172 session_id = BVAL(hdr, SMB2_HDR_SESSION_ID);
173 session_flags = SVAL(body, 2);
175 security_buffer_offset = SVAL(body, 4);
176 security_buffer_length = SVAL(body, 6);
178 if (security_buffer_length > 0) {
179 expected_offset = SMB2_HDR_BODY + 8;
181 if (security_buffer_offset != 0) {
182 security_buffer_data = (uint8_t *)state->recv_iov[2].iov_base;
183 expected_offset = SMB2_HDR_BODY + 8;
186 if (security_buffer_offset != expected_offset) {
187 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
188 return;
190 if (security_buffer_length > state->recv_iov[2].iov_len) {
191 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
192 return;
195 state->out_security_buffer.data = security_buffer_data;
196 state->out_security_buffer.length = security_buffer_length;
198 current_session_id = smb2cli_session_current_id(state->session);
199 if (current_session_id == 0) {
200 /* A new session was requested */
201 current_session_id = session_id;
204 if (current_session_id != session_id) {
205 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
206 return;
209 smb2cli_session_set_id_and_flags(state->session,
210 session_id, session_flags);
212 state->status = status;
213 tevent_req_done(req);
216 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)
221 struct smb2cli_session_setup_state *state =
222 tevent_req_data(req,
223 struct smb2cli_session_setup_state);
224 NTSTATUS status;
225 struct iovec *_tmp;
227 if (tevent_req_is_nterror(req, &status)) {
228 tevent_req_received(req);
229 return status;
232 if (recv_iov == NULL) {
233 recv_iov = &_tmp;
236 *recv_iov = talloc_move(mem_ctx, &state->recv_iov);
238 *out_security_buffer = state->out_security_buffer;
241 * Return the status from the server:
242 * NT_STATUS_MORE_PROCESSING_REQUIRED or
243 * NT_STATUS_OK.
245 status = state->status;
246 tevent_req_received(req);
247 return status;
250 struct smb2cli_logoff_state {
251 uint8_t fixed[4];
254 static void smb2cli_logoff_done(struct tevent_req *subreq);
256 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)
262 struct tevent_req *req, *subreq;
263 struct smb2cli_logoff_state *state;
265 req = tevent_req_create(mem_ctx, &state,
266 struct smb2cli_logoff_state);
267 if (req == NULL) {
268 return NULL;
270 SSVAL(state->fixed, 0, 4);
272 subreq = smb2cli_req_send(state, ev,
273 conn, SMB2_OP_LOGOFF,
274 0, 0, /* flags */
275 timeout_msec,
276 NULL, /* tcon */
277 session,
278 state->fixed, sizeof(state->fixed),
279 NULL, 0, /* dyn* */
280 0); /* max_dyn_len */
281 if (tevent_req_nomem(subreq, req)) {
282 return tevent_req_post(req, ev);
284 tevent_req_set_callback(subreq, smb2cli_logoff_done, req);
285 return req;
288 static void smb2cli_logoff_done(struct tevent_req *subreq)
290 struct tevent_req *req =
291 tevent_req_callback_data(subreq,
292 struct tevent_req);
293 struct smb2cli_logoff_state *state =
294 tevent_req_data(req,
295 struct smb2cli_logoff_state);
296 NTSTATUS status;
297 struct iovec *iov;
298 static const struct smb2cli_req_expected_response expected[] = {
300 .status = NT_STATUS_OK,
301 .body_size = 0x04
305 status = smb2cli_req_recv(subreq, state, &iov,
306 expected, ARRAY_SIZE(expected));
307 TALLOC_FREE(subreq);
308 if (tevent_req_nterror(req, status)) {
309 return;
311 tevent_req_done(req);
314 NTSTATUS smb2cli_logoff_recv(struct tevent_req *req)
316 return tevent_req_simple_recv_ntstatus(req);
319 NTSTATUS smb2cli_logoff(struct smbXcli_conn *conn,
320 uint32_t timeout_msec,
321 struct smbXcli_session *session)
323 TALLOC_CTX *frame = talloc_stackframe();
324 struct tevent_context *ev;
325 struct tevent_req *req;
326 NTSTATUS status = NT_STATUS_NO_MEMORY;
328 if (smbXcli_conn_has_async_calls(conn)) {
330 * Can't use sync call while an async call is in flight
332 status = NT_STATUS_INVALID_PARAMETER;
333 goto fail;
335 ev = samba_tevent_context_init(frame);
336 if (ev == NULL) {
337 goto fail;
339 req = smb2cli_logoff_send(frame, ev, conn, timeout_msec, session);
340 if (req == NULL) {
341 goto fail;
343 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
344 goto fail;
346 status = smb2cli_logoff_recv(req);
347 fail:
348 TALLOC_FREE(frame);
349 return status;