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"
29 struct smb2cli_sesssetup_blob_state
{
30 struct ntlmssp_state
*ntlmssp
;
36 static void smb2cli_sesssetup_blob_done(struct tevent_req
*subreq
);
38 static struct tevent_req
*smb2cli_sesssetup_blob_send(TALLOC_CTX
*mem_ctx
,
39 struct tevent_context
*ev
,
40 struct cli_state
*cli
,
43 struct tevent_req
*req
, *subreq
;
44 struct smb2cli_sesssetup_blob_state
*state
;
47 req
= tevent_req_create(mem_ctx
, &state
,
48 struct smb2cli_sesssetup_blob_state
);
56 SCVAL(buf
, 2, 0); /* VcNumber */
57 SCVAL(buf
, 3, 0); /* SecurityMode */
58 SIVAL(buf
, 4, 0); /* Capabilities */
59 SIVAL(buf
, 8, 0); /* Channel */
60 SSVAL(buf
, 12, SMB2_HDR_BODY
+ 24); /* SecurityBufferOffset */
61 SSVAL(buf
, 14, blob
->length
);
62 SBVAL(buf
, 16, 0); /* PreviousSessionId */
64 subreq
= smb2cli_req_send(state
, ev
, cli
, SMB2_OP_SESSSETUP
, 0,
65 state
->fixed
, sizeof(state
->fixed
),
66 blob
->data
, blob
->length
);
67 if (tevent_req_nomem(subreq
, req
)) {
68 return tevent_req_post(req
, ev
);
70 tevent_req_set_callback(subreq
, smb2cli_sesssetup_blob_done
, req
);
74 static void smb2cli_sesssetup_blob_done(struct tevent_req
*subreq
)
76 struct tevent_req
*req
=
77 tevent_req_callback_data(subreq
,
79 struct smb2cli_sesssetup_blob_state
*state
=
81 struct smb2cli_sesssetup_blob_state
);
84 uint16_t offset
, length
;
86 status
= smb2cli_req_recv(subreq
, talloc_tos(), &iov
, 9);
87 if (!NT_STATUS_IS_OK(status
) &&
88 !NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
90 tevent_req_nterror(req
, status
);
94 offset
= SVAL(iov
[1].iov_base
, 4);
95 length
= SVAL(iov
[1].iov_base
, 6);
97 if ((offset
!= SMB2_HDR_BODY
+ 8) || (length
> iov
[2].iov_len
)) {
99 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
102 state
->uid
= BVAL(iov
[0].iov_base
, SMB2_HDR_SESSION_ID
);
103 state
->out
.data
= (uint8_t *)iov
[2].iov_base
;
104 state
->out
.length
= length
;
105 if (!NT_STATUS_IS_OK(status
)) {
106 tevent_req_nterror(req
, status
);
109 tevent_req_done(req
);
112 static NTSTATUS
smb2cli_sesssetup_blob_recv(struct tevent_req
*req
,
113 uint64_t *uid
, DATA_BLOB
*out
)
115 struct smb2cli_sesssetup_blob_state
*state
=
117 struct smb2cli_sesssetup_blob_state
);
118 NTSTATUS status
= NT_STATUS_OK
;
120 if (tevent_req_is_nterror(req
, &status
)
121 && !NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
129 struct smb2cli_sesssetup_state
{
130 struct tevent_context
*ev
;
131 struct cli_state
*cli
;
132 struct ntlmssp_state
*ntlmssp
;
139 static void smb2cli_sesssetup_done(struct tevent_req
*subreq
);
141 struct tevent_req
*smb2cli_sesssetup_send(TALLOC_CTX
*mem_ctx
,
142 struct tevent_context
*ev
,
143 struct cli_state
*cli
,
148 struct tevent_req
*req
, *subreq
;
149 struct smb2cli_sesssetup_state
*state
;
152 const char *OIDs_ntlm
[] = {OID_NTLMSSP
, NULL
};
154 req
= tevent_req_create(mem_ctx
, &state
,
155 struct smb2cli_sesssetup_state
);
162 status
= ntlmssp_client_start(state
,
165 lp_client_ntlmv2_auth(),
167 if (!NT_STATUS_IS_OK(status
)) {
170 status
= ntlmssp_set_username(state
->ntlmssp
, user
);
171 if (!NT_STATUS_IS_OK(status
)) {
174 status
= ntlmssp_set_domain(state
->ntlmssp
, domain
);
175 if (!NT_STATUS_IS_OK(status
)) {
178 status
= ntlmssp_set_password(state
->ntlmssp
, pass
);
179 if (!NT_STATUS_IS_OK(status
)) {
183 status
= ntlmssp_update(state
->ntlmssp
, data_blob_null
, &blob_out
);
184 if (!NT_STATUS_IS_OK(status
)
185 && !NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
189 blob_out
= spnego_gen_negTokenInit(state
, OIDs_ntlm
, &blob_out
, NULL
);
192 subreq
= smb2cli_sesssetup_blob_send(
193 state
, state
->ev
, state
->cli
, &blob_out
);
194 if (tevent_req_nomem(subreq
, req
)) {
195 return tevent_req_post(req
, ev
);
197 tevent_req_set_callback(subreq
, smb2cli_sesssetup_done
, req
);
200 tevent_req_nterror(req
, status
);
201 return tevent_req_post(req
, ev
);
204 static void smb2cli_sesssetup_done(struct tevent_req
*subreq
)
206 struct tevent_req
*req
=
207 tevent_req_callback_data(subreq
,
209 struct smb2cli_sesssetup_state
*state
=
211 struct smb2cli_sesssetup_state
);
214 DATA_BLOB blob
, blob_in
, blob_out
, spnego_blob
;
217 status
= smb2cli_sesssetup_blob_recv(subreq
, &uid
, &blob
);
218 if (!NT_STATUS_IS_OK(status
)
219 && !NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
221 tevent_req_nterror(req
, status
);
225 if (NT_STATUS_IS_OK(status
)) {
227 tevent_req_done(req
);
231 if (state
->turn
== 1) {
232 DATA_BLOB tmp_blob
= data_blob_null
;
233 ret
= spnego_parse_challenge(state
, blob
, &blob_in
, &tmp_blob
);
234 data_blob_free(&tmp_blob
);
236 ret
= spnego_parse_auth_response(state
, blob
, status
,
237 OID_NTLMSSP
, &blob_in
);
241 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
245 status
= ntlmssp_update(state
->ntlmssp
, blob_in
, &blob_out
);
246 data_blob_free(&blob_in
);
249 if (!NT_STATUS_IS_OK(status
)) {
250 tevent_req_nterror(req
, status
);
254 state
->cli
->smb2
.uid
= uid
;
256 spnego_blob
= spnego_gen_auth(state
, blob_out
);
258 if (tevent_req_nomem(spnego_blob
.data
, req
)) {
262 subreq
= smb2cli_sesssetup_blob_send(
263 state
, state
->ev
, state
->cli
, &spnego_blob
);
264 if (tevent_req_nomem(subreq
, req
)) {
267 tevent_req_set_callback(subreq
, smb2cli_sesssetup_done
, req
);
270 NTSTATUS
smb2cli_sesssetup_recv(struct tevent_req
*req
)
272 return tevent_req_simple_recv_ntstatus(req
);
275 NTSTATUS
smb2cli_sesssetup(struct cli_state
*cli
, const char *user
,
276 const char *domain
, const char *pass
)
278 TALLOC_CTX
*frame
= talloc_stackframe();
279 struct event_context
*ev
;
280 struct tevent_req
*req
;
281 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
283 if (cli_has_async_calls(cli
)) {
285 * Can't use sync call while an async call is in flight
287 status
= NT_STATUS_INVALID_PARAMETER
;
290 ev
= event_context_init(frame
);
294 req
= smb2cli_sesssetup_send(frame
, ev
, cli
, user
, domain
, pass
);
298 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
301 status
= smb2cli_sesssetup_recv(req
);
307 struct smb2cli_logoff_state
{
311 static void smb2cli_logoff_done(struct tevent_req
*subreq
);
313 struct tevent_req
*smb2cli_logoff_send(TALLOC_CTX
*mem_ctx
,
314 struct tevent_context
*ev
,
315 struct cli_state
*cli
)
317 struct tevent_req
*req
, *subreq
;
318 struct smb2cli_logoff_state
*state
;
320 req
= tevent_req_create(mem_ctx
, &state
,
321 struct smb2cli_logoff_state
);
325 SSVAL(state
->fixed
, 0, 4);
327 subreq
= smb2cli_req_send(state
, ev
, cli
, SMB2_OP_LOGOFF
, 0,
328 state
->fixed
, sizeof(state
->fixed
),
330 if (tevent_req_nomem(subreq
, req
)) {
331 return tevent_req_post(req
, ev
);
333 tevent_req_set_callback(subreq
, smb2cli_logoff_done
, req
);
337 static void smb2cli_logoff_done(struct tevent_req
*subreq
)
339 struct tevent_req
*req
=
340 tevent_req_callback_data(subreq
,
345 status
= smb2cli_req_recv(subreq
, talloc_tos(), &iov
, 4);
347 if (tevent_req_nterror(req
, status
)) {
350 tevent_req_done(req
);
353 NTSTATUS
smb2cli_logoff_recv(struct tevent_req
*req
)
355 return tevent_req_simple_recv_ntstatus(req
);
358 NTSTATUS
smb2cli_logoff(struct cli_state
*cli
)
360 TALLOC_CTX
*frame
= talloc_stackframe();
361 struct event_context
*ev
;
362 struct tevent_req
*req
;
363 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
365 if (cli_has_async_calls(cli
)) {
367 * Can't use sync call while an async call is in flight
369 status
= NT_STATUS_INVALID_PARAMETER
;
372 ev
= event_context_init(frame
);
376 req
= smb2cli_logoff_send(frame
, ev
, cli
);
380 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
383 status
= smb2cli_logoff_recv(req
);