2 Unix SMB/CIFS implementation.
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/>.
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
;
30 struct iovec
*recv_iov
;
31 DATA_BLOB out_security_buffer
;
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
,
43 uint32_t in_capabilities
,
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
;
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
);
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
;
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
;
94 dyn
= state
->dyn_pad
;;
95 dyn_len
= sizeof(state
->dyn_pad
);
98 subreq
= smb2cli_req_send(state
, ev
,
99 conn
, SMB2_OP_SESSSETUP
,
104 state
->fixed
, sizeof(state
->fixed
),
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
);
114 static void smb2cli_session_setup_done(struct tevent_req
*subreq
)
116 struct tevent_req
*req
=
117 tevent_req_callback_data(subreq
,
119 struct smb2cli_session_setup_state
*state
=
121 struct smb2cli_session_setup_state
);
123 NTSTATUS preauth_status
;
124 uint64_t current_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];
134 static const struct smb2cli_req_expected_response expected
[] = {
136 .status
= NT_STATUS_MORE_PROCESSING_REQUIRED
,
140 .status
= NT_STATUS_OK
,
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
)) {
150 tevent_req_nterror(req
, status
);
154 smb2cli_req_get_sent_iov(subreq
, sent_iov
);
155 preauth_status
= smb2cli_session_update_preauth(state
->session
, sent_iov
);
157 if (tevent_req_nterror(req
, preauth_status
)) {
161 if (NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
162 preauth_status
= smb2cli_session_update_preauth(state
->session
,
164 if (tevent_req_nterror(req
, preauth_status
)) {
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
);
190 if (security_buffer_length
> state
->recv_iov
[2].iov_len
) {
191 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
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
);
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
,
218 struct iovec
**recv_iov
,
219 DATA_BLOB
*out_security_buffer
)
221 struct smb2cli_session_setup_state
*state
=
223 struct smb2cli_session_setup_state
);
227 if (tevent_req_is_nterror(req
, &status
)) {
228 tevent_req_received(req
);
232 if (recv_iov
== NULL
) {
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
245 status
= state
->status
;
246 tevent_req_received(req
);
250 struct smb2cli_logoff_state
{
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
);
270 SSVAL(state
->fixed
, 0, 4);
272 subreq
= smb2cli_req_send(state
, ev
,
273 conn
, SMB2_OP_LOGOFF
,
278 state
->fixed
, sizeof(state
->fixed
),
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
);
288 static void smb2cli_logoff_done(struct tevent_req
*subreq
)
290 struct tevent_req
*req
=
291 tevent_req_callback_data(subreq
,
293 struct smb2cli_logoff_state
*state
=
295 struct smb2cli_logoff_state
);
298 static const struct smb2cli_req_expected_response expected
[] = {
300 .status
= NT_STATUS_OK
,
305 status
= smb2cli_req_recv(subreq
, state
, &iov
,
306 expected
, ARRAY_SIZE(expected
));
308 if (tevent_req_nterror(req
, status
)) {
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
;
335 ev
= samba_tevent_context_init(frame
);
339 req
= smb2cli_logoff_send(frame
, ev
, conn
, timeout_msec
, session
);
343 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
346 status
= smb2cli_logoff_recv(req
);