tevent: expose tevent_context_init_ops
[Samba/gebeck_regimport.git] / libcli / smb / smb2cli_session.c
blob640eb95f0b33b96a8a7dc171a7df4f9ce0e7e55b
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 0xFEFF,
103 0, /* tid */
104 session,
105 state->fixed, sizeof(state->fixed),
106 dyn, 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 uint64_t current_session_id;
124 uint64_t session_id;
125 uint16_t session_flags;
126 uint16_t expected_offset = 0;
127 uint16_t security_buffer_offset;
128 uint16_t security_buffer_length;
129 uint8_t *security_buffer_data = NULL;
130 const uint8_t *hdr;
131 const uint8_t *body;
132 static const struct smb2cli_req_expected_response expected[] = {
134 .status = NT_STATUS_MORE_PROCESSING_REQUIRED,
135 .body_size = 0x09
138 .status = NT_STATUS_OK,
139 .body_size = 0x09
143 status = smb2cli_req_recv(subreq, state, &state->recv_iov,
144 expected, ARRAY_SIZE(expected));
145 TALLOC_FREE(subreq);
146 if (!NT_STATUS_IS_OK(status) &&
147 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
148 tevent_req_nterror(req, status);
149 return;
152 hdr = (const uint8_t *)state->recv_iov[0].iov_base;
153 body = (const uint8_t *)state->recv_iov[1].iov_base;
155 session_id = BVAL(hdr, SMB2_HDR_SESSION_ID);
156 session_flags = SVAL(body, 2);
158 security_buffer_offset = SVAL(body, 4);
159 security_buffer_length = SVAL(body, 6);
161 if (security_buffer_length > 0) {
162 expected_offset = SMB2_HDR_BODY + 8;
164 if (security_buffer_offset != 0) {
165 security_buffer_data = (uint8_t *)state->recv_iov[2].iov_base;
166 expected_offset = SMB2_HDR_BODY + 8;
169 if (security_buffer_offset != expected_offset) {
170 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
171 return;
173 if (security_buffer_length > state->recv_iov[2].iov_len) {
174 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
175 return;
178 state->out_security_buffer.data = security_buffer_data;
179 state->out_security_buffer.length = security_buffer_length;
181 current_session_id = smb2cli_session_current_id(state->session);
182 if (current_session_id == 0) {
183 /* A new session was requested */
184 current_session_id = session_id;
187 if (current_session_id != session_id) {
188 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
189 return;
192 smb2cli_session_set_id_and_flags(state->session,
193 session_id, session_flags);
195 state->status = status;
196 tevent_req_done(req);
199 NTSTATUS smb2cli_session_setup_recv(struct tevent_req *req,
200 TALLOC_CTX *mem_ctx,
201 struct iovec **recv_iov,
202 DATA_BLOB *out_security_buffer)
204 struct smb2cli_session_setup_state *state =
205 tevent_req_data(req,
206 struct smb2cli_session_setup_state);
207 NTSTATUS status;
208 struct iovec *_tmp;
210 if (tevent_req_is_nterror(req, &status)) {
211 tevent_req_received(req);
212 return status;
215 if (recv_iov == NULL) {
216 recv_iov = &_tmp;
219 *recv_iov = talloc_move(mem_ctx, &state->recv_iov);
221 *out_security_buffer = state->out_security_buffer;
224 * Return the status from the server:
225 * NT_STATUS_MORE_PROCESSING_REQUIRED or
226 * NT_STATUS_OK.
228 status = state->status;
229 tevent_req_received(req);
230 return status;
233 struct smb2cli_logoff_state {
234 uint8_t fixed[4];
237 static void smb2cli_logoff_done(struct tevent_req *subreq);
239 struct tevent_req *smb2cli_logoff_send(TALLOC_CTX *mem_ctx,
240 struct tevent_context *ev,
241 struct smbXcli_conn *conn,
242 uint32_t timeout_msec,
243 struct smbXcli_session *session)
245 struct tevent_req *req, *subreq;
246 struct smb2cli_logoff_state *state;
248 req = tevent_req_create(mem_ctx, &state,
249 struct smb2cli_logoff_state);
250 if (req == NULL) {
251 return NULL;
253 SSVAL(state->fixed, 0, 4);
255 subreq = smb2cli_req_send(state, ev,
256 conn, SMB2_OP_LOGOFF,
257 0, 0, /* flags */
258 timeout_msec,
259 0xFEFF, /* pid */
260 0, /* tid */
261 session,
262 state->fixed, sizeof(state->fixed),
263 NULL, 0);
264 if (tevent_req_nomem(subreq, req)) {
265 return tevent_req_post(req, ev);
267 tevent_req_set_callback(subreq, smb2cli_logoff_done, req);
268 return req;
271 static void smb2cli_logoff_done(struct tevent_req *subreq)
273 struct tevent_req *req =
274 tevent_req_callback_data(subreq,
275 struct tevent_req);
276 struct smb2cli_logoff_state *state =
277 tevent_req_data(req,
278 struct smb2cli_logoff_state);
279 NTSTATUS status;
280 struct iovec *iov;
281 static const struct smb2cli_req_expected_response expected[] = {
283 .status = NT_STATUS_OK,
284 .body_size = 0x04
288 status = smb2cli_req_recv(subreq, state, &iov,
289 expected, ARRAY_SIZE(expected));
290 TALLOC_FREE(subreq);
291 if (tevent_req_nterror(req, status)) {
292 return;
294 tevent_req_done(req);
297 NTSTATUS smb2cli_logoff_recv(struct tevent_req *req)
299 return tevent_req_simple_recv_ntstatus(req);
302 NTSTATUS smb2cli_logoff(struct smbXcli_conn *conn,
303 uint32_t timeout_msec,
304 struct smbXcli_session *session)
306 TALLOC_CTX *frame = talloc_stackframe();
307 struct tevent_context *ev;
308 struct tevent_req *req;
309 NTSTATUS status = NT_STATUS_NO_MEMORY;
311 if (smbXcli_conn_has_async_calls(conn)) {
313 * Can't use sync call while an async call is in flight
315 status = NT_STATUS_INVALID_PARAMETER;
316 goto fail;
318 ev = tevent_context_init(frame);
319 if (ev == NULL) {
320 goto fail;
322 req = smb2cli_logoff_send(frame, ev, conn, timeout_msec, session);
323 if (req == NULL) {
324 goto fail;
326 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
327 goto fail;
329 status = smb2cli_logoff_recv(req);
330 fail:
331 TALLOC_FREE(frame);
332 return status;