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"
23 #include "smb2cli_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
{
37 static void smb2cli_session_setup_done(struct tevent_req
*subreq
);
39 static struct tevent_req
*smb2cli_session_setup_send(TALLOC_CTX
*mem_ctx
,
40 struct tevent_context
*ev
,
41 struct cli_state
*cli
,
44 struct tevent_req
*req
, *subreq
;
45 struct smb2cli_session_setup_state
*state
;
50 req
= tevent_req_create(mem_ctx
, &state
,
51 struct smb2cli_session_setup_state
);
59 SCVAL(buf
, 2, 0); /* VcNumber */
60 SCVAL(buf
, 3, 0); /* SecurityMode */
61 SIVAL(buf
, 4, 0); /* Capabilities */
62 SIVAL(buf
, 8, 0); /* Channel */
63 SSVAL(buf
, 12, SMB2_HDR_BODY
+ 24); /* SecurityBufferOffset */
64 SSVAL(buf
, 14, blob
->length
);
65 SBVAL(buf
, 16, 0); /* PreviousSessionId */
67 if (blob
->length
> 0) {
69 dyn_len
= blob
->length
;
71 dyn
= state
->dyn_pad
;;
72 dyn_len
= sizeof(state
->dyn_pad
);
75 subreq
= smb2cli_req_send(state
, ev
, cli
, SMB2_OP_SESSSETUP
,
81 state
->fixed
, sizeof(state
->fixed
),
83 if (tevent_req_nomem(subreq
, req
)) {
84 return tevent_req_post(req
, ev
);
86 tevent_req_set_callback(subreq
, smb2cli_session_setup_done
, req
);
90 static void smb2cli_session_setup_done(struct tevent_req
*subreq
)
92 struct tevent_req
*req
=
93 tevent_req_callback_data(subreq
,
95 struct smb2cli_session_setup_state
*state
=
97 struct smb2cli_session_setup_state
);
100 uint16_t offset
, length
;
101 static const struct smb2cli_req_expected_response expected
[] = {
103 .status
= NT_STATUS_MORE_PROCESSING_REQUIRED
,
107 .status
= NT_STATUS_OK
,
112 status
= smb2cli_req_recv(subreq
, talloc_tos(), &iov
,
113 expected
, ARRAY_SIZE(expected
));
114 if (!NT_STATUS_IS_OK(status
) &&
115 !NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
117 tevent_req_nterror(req
, status
);
121 offset
= SVAL(iov
[1].iov_base
, 4);
122 length
= SVAL(iov
[1].iov_base
, 6);
124 if ((offset
!= SMB2_HDR_BODY
+ 8) || (length
> iov
[2].iov_len
)) {
126 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
129 state
->uid
= BVAL(iov
[0].iov_base
, SMB2_HDR_SESSION_ID
);
130 state
->out
.data
= (uint8_t *)iov
[2].iov_base
;
131 state
->out
.length
= length
;
132 if (!NT_STATUS_IS_OK(status
)) {
133 tevent_req_nterror(req
, status
);
136 tevent_req_done(req
);
139 static NTSTATUS
smb2cli_session_setup_recv(struct tevent_req
*req
,
140 uint64_t *uid
, DATA_BLOB
*out
)
142 struct smb2cli_session_setup_state
*state
=
144 struct smb2cli_session_setup_state
);
145 NTSTATUS status
= NT_STATUS_OK
;
147 if (tevent_req_is_nterror(req
, &status
)
148 && !NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
156 struct smb2cli_sesssetup_ntlmssp_state
{
157 struct tevent_context
*ev
;
158 struct cli_state
*cli
;
159 struct ntlmssp_state
*ntlmssp
;
166 static void smb2cli_sesssetup_ntlmssp_done(struct tevent_req
*subreq
);
168 struct tevent_req
*smb2cli_sesssetup_ntlmssp_send(TALLOC_CTX
*mem_ctx
,
169 struct tevent_context
*ev
,
170 struct cli_state
*cli
,
175 struct tevent_req
*req
, *subreq
;
176 struct smb2cli_sesssetup_ntlmssp_state
*state
;
179 const char *OIDs_ntlm
[] = {OID_NTLMSSP
, NULL
};
181 req
= tevent_req_create(mem_ctx
, &state
,
182 struct smb2cli_sesssetup_ntlmssp_state
);
189 status
= ntlmssp_client_start(state
,
192 lp_client_ntlmv2_auth(),
194 if (!NT_STATUS_IS_OK(status
)) {
197 ntlmssp_want_feature(state
->ntlmssp
,
198 NTLMSSP_FEATURE_SESSION_KEY
);
199 status
= ntlmssp_set_username(state
->ntlmssp
, user
);
200 if (!NT_STATUS_IS_OK(status
)) {
203 status
= ntlmssp_set_domain(state
->ntlmssp
, domain
);
204 if (!NT_STATUS_IS_OK(status
)) {
207 status
= ntlmssp_set_password(state
->ntlmssp
, pass
);
208 if (!NT_STATUS_IS_OK(status
)) {
212 status
= ntlmssp_update(state
->ntlmssp
, data_blob_null
, &blob_out
);
213 if (!NT_STATUS_IS_OK(status
)
214 && !NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
218 blob_out
= spnego_gen_negTokenInit(state
, OIDs_ntlm
, &blob_out
, NULL
);
221 subreq
= smb2cli_session_setup_send(
222 state
, state
->ev
, state
->cli
, &blob_out
);
223 if (tevent_req_nomem(subreq
, req
)) {
224 return tevent_req_post(req
, ev
);
226 tevent_req_set_callback(subreq
, smb2cli_sesssetup_ntlmssp_done
, req
);
229 tevent_req_nterror(req
, status
);
230 return tevent_req_post(req
, ev
);
233 static void smb2cli_sesssetup_ntlmssp_done(struct tevent_req
*subreq
)
235 struct tevent_req
*req
=
236 tevent_req_callback_data(subreq
,
238 struct smb2cli_sesssetup_ntlmssp_state
*state
=
240 struct smb2cli_sesssetup_ntlmssp_state
);
243 DATA_BLOB blob
, blob_in
, blob_out
, spnego_blob
;
246 status
= smb2cli_session_setup_recv(subreq
, &uid
, &blob
);
247 if (!NT_STATUS_IS_OK(status
)
248 && !NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
250 tevent_req_nterror(req
, status
);
254 if (NT_STATUS_IS_OK(status
)) {
256 tevent_req_done(req
);
260 if (state
->turn
== 1) {
261 DATA_BLOB tmp_blob
= data_blob_null
;
262 ret
= spnego_parse_challenge(state
, blob
, &blob_in
, &tmp_blob
);
263 data_blob_free(&tmp_blob
);
265 ret
= spnego_parse_auth_response(state
, blob
, status
,
266 OID_NTLMSSP
, &blob_in
);
270 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
274 status
= ntlmssp_update(state
->ntlmssp
, blob_in
, &blob_out
);
275 data_blob_free(&blob_in
);
278 if (!NT_STATUS_IS_OK(status
)) {
279 tevent_req_nterror(req
, status
);
283 state
->cli
->smb2
.uid
= uid
;
285 spnego_blob
= spnego_gen_auth(state
, blob_out
);
287 if (tevent_req_nomem(spnego_blob
.data
, req
)) {
291 subreq
= smb2cli_session_setup_send(
292 state
, state
->ev
, state
->cli
, &spnego_blob
);
293 if (tevent_req_nomem(subreq
, req
)) {
296 tevent_req_set_callback(subreq
, smb2cli_sesssetup_ntlmssp_done
, req
);
299 NTSTATUS
smb2cli_sesssetup_ntlmssp_recv(struct tevent_req
*req
)
301 return tevent_req_simple_recv_ntstatus(req
);
304 NTSTATUS
smb2cli_sesssetup_ntlmssp(struct cli_state
*cli
, const char *user
,
305 const char *domain
, const char *pass
)
307 TALLOC_CTX
*frame
= talloc_stackframe();
308 struct event_context
*ev
;
309 struct tevent_req
*req
;
310 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
312 if (cli_has_async_calls(cli
)) {
314 * Can't use sync call while an async call is in flight
316 status
= NT_STATUS_INVALID_PARAMETER
;
319 ev
= event_context_init(frame
);
323 req
= smb2cli_sesssetup_ntlmssp_send(frame
, ev
, cli
, user
, domain
, pass
);
327 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
330 status
= smb2cli_sesssetup_ntlmssp_recv(req
);
336 struct smb2cli_logoff_state
{
340 static void smb2cli_logoff_done(struct tevent_req
*subreq
);
342 struct tevent_req
*smb2cli_logoff_send(TALLOC_CTX
*mem_ctx
,
343 struct tevent_context
*ev
,
344 struct cli_state
*cli
)
346 struct tevent_req
*req
, *subreq
;
347 struct smb2cli_logoff_state
*state
;
349 req
= tevent_req_create(mem_ctx
, &state
,
350 struct smb2cli_logoff_state
);
354 SSVAL(state
->fixed
, 0, 4);
356 subreq
= smb2cli_req_send(state
, ev
, cli
, SMB2_OP_LOGOFF
,
362 state
->fixed
, sizeof(state
->fixed
),
364 if (tevent_req_nomem(subreq
, req
)) {
365 return tevent_req_post(req
, ev
);
367 tevent_req_set_callback(subreq
, smb2cli_logoff_done
, req
);
371 static void smb2cli_logoff_done(struct tevent_req
*subreq
)
373 struct tevent_req
*req
=
374 tevent_req_callback_data(subreq
,
378 static const struct smb2cli_req_expected_response expected
[] = {
380 .status
= NT_STATUS_OK
,
385 status
= smb2cli_req_recv(subreq
, talloc_tos(), &iov
,
386 expected
, ARRAY_SIZE(expected
));
388 if (tevent_req_nterror(req
, status
)) {
391 tevent_req_done(req
);
394 NTSTATUS
smb2cli_logoff_recv(struct tevent_req
*req
)
396 return tevent_req_simple_recv_ntstatus(req
);
399 NTSTATUS
smb2cli_logoff(struct cli_state
*cli
)
401 TALLOC_CTX
*frame
= talloc_stackframe();
402 struct event_context
*ev
;
403 struct tevent_req
*req
;
404 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
406 if (cli_has_async_calls(cli
)) {
408 * Can't use sync call while an async call is in flight
410 status
= NT_STATUS_INVALID_PARAMETER
;
413 ev
= event_context_init(frame
);
417 req
= smb2cli_logoff_send(frame
, ev
, cli
);
421 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
424 status
= smb2cli_logoff_recv(req
);