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/>.
22 #include "async_smb.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
;
34 struct iovec
*recv_iov
;
35 DATA_BLOB out_security_buffer
;
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
,
47 uint32_t in_capabilities
,
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
;
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
);
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
) {
86 smb2cli_session_current_id(in_previous_session
);
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
;
104 dyn
= state
->dyn_pad
;;
105 dyn_len
= sizeof(state
->dyn_pad
);
108 subreq
= smb2cli_req_send(state
, ev
,
109 conn
, SMB2_OP_SESSSETUP
,
115 state
->fixed
, sizeof(state
->fixed
),
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
);
124 static void smb2cli_session_setup_done(struct tevent_req
*subreq
)
126 struct tevent_req
*req
=
127 tevent_req_callback_data(subreq
,
129 struct smb2cli_session_setup_state
*state
=
131 struct smb2cli_session_setup_state
);
133 uint64_t current_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
;
142 static const struct smb2cli_req_expected_response expected
[] = {
144 .status
= NT_STATUS_MORE_PROCESSING_REQUIRED
,
148 .status
= NT_STATUS_OK
,
153 status
= smb2cli_req_recv(subreq
, state
, &state
->recv_iov
,
154 expected
, ARRAY_SIZE(expected
));
156 if (!NT_STATUS_IS_OK(status
) &&
157 !NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
158 tevent_req_nterror(req
, status
);
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
);
183 if (security_buffer_length
> state
->recv_iov
[2].iov_len
) {
184 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
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
);
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
,
211 struct iovec
**recv_iov
,
212 DATA_BLOB
*out_security_buffer
)
214 struct smb2cli_session_setup_state
*state
=
216 struct smb2cli_session_setup_state
);
220 if (tevent_req_is_nterror(req
, &status
)) {
221 tevent_req_received(req
);
225 if (recv_iov
== NULL
) {
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
238 status
= state
->status
;
239 tevent_req_received(req
);
243 struct smb2cli_logoff_state
{
244 struct cli_state
*cli
;
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
);
263 SSVAL(state
->fixed
, 0, 4);
265 subreq
= smb2cli_req_send(state
, ev
,
266 cli
->conn
, SMB2_OP_LOGOFF
,
272 state
->fixed
, sizeof(state
->fixed
),
274 if (tevent_req_nomem(subreq
, req
)) {
275 return tevent_req_post(req
, ev
);
277 tevent_req_set_callback(subreq
, smb2cli_logoff_done
, req
);
281 static void smb2cli_logoff_done(struct tevent_req
*subreq
)
283 struct tevent_req
*req
=
284 tevent_req_callback_data(subreq
,
286 struct smb2cli_logoff_state
*state
=
288 struct smb2cli_logoff_state
);
291 static const struct smb2cli_req_expected_response expected
[] = {
293 .status
= NT_STATUS_OK
,
298 status
= smb2cli_req_recv(subreq
, state
, &iov
,
299 expected
, ARRAY_SIZE(expected
));
301 TALLOC_FREE(state
->cli
->smb2
.session
);
302 if (tevent_req_nterror(req
, status
)) {
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
;
327 ev
= event_context_init(frame
);
331 req
= smb2cli_logoff_send(frame
, ev
, cli
);
335 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
338 status
= smb2cli_logoff_recv(req
);