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 "../libcli/auth/ntlmssp.h"
30 struct smb2cli_session_setup_state {
31 struct ntlmssp_state *ntlmssp;
38 static void smb2cli_session_setup_done(struct tevent_req *subreq);
40 static struct tevent_req *smb2cli_session_setup_send(TALLOC_CTX *mem_ctx,
41 struct tevent_context *ev,
42 struct cli_state *cli,
45 struct tevent_req *req, *subreq;
46 struct smb2cli_session_setup_state *state;
51 req = tevent_req_create(mem_ctx, &state,
52 struct smb2cli_session_setup_state);
60 SCVAL(buf, 2, 0); /* VcNumber */
61 SCVAL(buf, 3, 0); /* SecurityMode */
62 SIVAL(buf, 4, 0); /* Capabilities */
63 SIVAL(buf, 8, 0); /* Channel */
64 SSVAL(buf, 12, SMB2_HDR_BODY + 24); /* SecurityBufferOffset */
65 SSVAL(buf, 14, blob->length);
66 SBVAL(buf, 16, 0); /* PreviousSessionId */
68 if (blob->length > 0) {
70 dyn_len = blob->length;
72 dyn = state->dyn_pad;;
73 dyn_len = sizeof(state->dyn_pad);
76 subreq = smb2cli_req_send(state, ev, cli, SMB2_OP_SESSSETUP,
82 state->fixed, sizeof(state->fixed),
84 if (tevent_req_nomem(subreq, req)) {
85 return tevent_req_post(req, ev);
87 tevent_req_set_callback(subreq, smb2cli_session_setup_done, req);
91 static void smb2cli_session_setup_done(struct tevent_req *subreq)
93 struct tevent_req *req =
94 tevent_req_callback_data(subreq,
96 struct smb2cli_session_setup_state *state =
98 struct smb2cli_session_setup_state);
101 uint16_t offset, length;
102 static const struct smb2cli_req_expected_response expected[] = {
104 .status = NT_STATUS_MORE_PROCESSING_REQUIRED,
108 .status = NT_STATUS_OK,
113 status = smb2cli_req_recv(subreq, talloc_tos(), &iov,
114 expected, ARRAY_SIZE(expected));
115 if (!NT_STATUS_IS_OK(status) &&
116 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
118 tevent_req_nterror(req, status);
122 offset = SVAL(iov[1].iov_base, 4);
123 length = SVAL(iov[1].iov_base, 6);
125 if ((offset != SMB2_HDR_BODY + 8) || (length > iov[2].iov_len)) {
127 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
130 state->uid = BVAL(iov[0].iov_base, SMB2_HDR_SESSION_ID);
131 state->out.data = (uint8_t *)iov[2].iov_base;
132 state->out.length = length;
133 if (!NT_STATUS_IS_OK(status)) {
134 tevent_req_nterror(req, status);
137 tevent_req_done(req);
140 static NTSTATUS smb2cli_session_setup_recv(struct tevent_req *req,
141 uint64_t *uid, DATA_BLOB *out)
143 struct smb2cli_session_setup_state *state =
145 struct smb2cli_session_setup_state);
146 NTSTATUS status = NT_STATUS_OK;
148 if (tevent_req_is_nterror(req, &status)
149 && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
157 struct smb2cli_sesssetup_ntlmssp_state {
158 struct tevent_context *ev;
159 struct cli_state *cli;
160 struct ntlmssp_state *ntlmssp;
167 static void smb2cli_sesssetup_ntlmssp_done(struct tevent_req *subreq);
169 struct tevent_req *smb2cli_sesssetup_ntlmssp_send(TALLOC_CTX *mem_ctx,
170 struct tevent_context *ev,
171 struct cli_state *cli,
176 struct tevent_req *req, *subreq;
177 struct smb2cli_sesssetup_ntlmssp_state *state;
180 const char *OIDs_ntlm[] = {OID_NTLMSSP, NULL};
182 req = tevent_req_create(mem_ctx, &state,
183 struct smb2cli_sesssetup_ntlmssp_state);
190 status = ntlmssp_client_start(state,
193 lp_client_ntlmv2_auth(),
195 if (!NT_STATUS_IS_OK(status)) {
198 ntlmssp_want_feature(state->ntlmssp,
199 NTLMSSP_FEATURE_SESSION_KEY);
200 status = ntlmssp_set_username(state->ntlmssp, user);
201 if (!NT_STATUS_IS_OK(status)) {
204 status = ntlmssp_set_domain(state->ntlmssp, domain);
205 if (!NT_STATUS_IS_OK(status)) {
208 status = ntlmssp_set_password(state->ntlmssp, pass);
209 if (!NT_STATUS_IS_OK(status)) {
213 status = ntlmssp_update(state->ntlmssp, data_blob_null, &blob_out);
214 if (!NT_STATUS_IS_OK(status)
215 && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
219 blob_out = spnego_gen_negTokenInit(state, OIDs_ntlm, &blob_out, NULL);
222 subreq = smb2cli_session_setup_send(
223 state, state->ev, state->cli, &blob_out);
224 if (tevent_req_nomem(subreq, req)) {
225 return tevent_req_post(req, ev);
227 tevent_req_set_callback(subreq, smb2cli_sesssetup_ntlmssp_done, req);
230 tevent_req_nterror(req, status);
231 return tevent_req_post(req, ev);
234 static void smb2cli_sesssetup_ntlmssp_done(struct tevent_req *subreq)
236 struct tevent_req *req =
237 tevent_req_callback_data(subreq,
239 struct smb2cli_sesssetup_ntlmssp_state *state =
241 struct smb2cli_sesssetup_ntlmssp_state);
244 DATA_BLOB blob, blob_in, blob_out, spnego_blob;
247 status = smb2cli_session_setup_recv(subreq, &uid, &blob);
248 if (!NT_STATUS_IS_OK(status)
249 && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
251 tevent_req_nterror(req, status);
255 if (NT_STATUS_IS_OK(status)) {
257 tevent_req_done(req);
261 if (state->turn == 1) {
262 DATA_BLOB tmp_blob = data_blob_null;
263 ret = spnego_parse_challenge(state, blob, &blob_in, &tmp_blob);
264 data_blob_free(&tmp_blob);
266 ret = spnego_parse_auth_response(state, blob, status,
267 OID_NTLMSSP, &blob_in);
271 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
275 status = ntlmssp_update(state->ntlmssp, blob_in, &blob_out);
276 data_blob_free(&blob_in);
279 if (!NT_STATUS_IS_OK(status)) {
280 tevent_req_nterror(req, status);
284 state->cli->smb2.uid = uid;
286 spnego_blob = spnego_gen_auth(state, blob_out);
288 if (tevent_req_nomem(spnego_blob.data, req)) {
292 subreq = smb2cli_session_setup_send(
293 state, state->ev, state->cli, &spnego_blob);
294 if (tevent_req_nomem(subreq, req)) {
297 tevent_req_set_callback(subreq, smb2cli_sesssetup_ntlmssp_done, req);
300 NTSTATUS smb2cli_sesssetup_ntlmssp_recv(struct tevent_req *req)
302 return tevent_req_simple_recv_ntstatus(req);
305 NTSTATUS smb2cli_sesssetup_ntlmssp(struct cli_state *cli, const char *user,
306 const char *domain, const char *pass)
308 TALLOC_CTX *frame = talloc_stackframe();
309 struct event_context *ev;
310 struct tevent_req *req;
311 NTSTATUS status = NT_STATUS_NO_MEMORY;
313 if (cli_has_async_calls(cli)) {
315 * Can't use sync call while an async call is in flight
317 status = NT_STATUS_INVALID_PARAMETER;
320 ev = event_context_init(frame);
324 req = smb2cli_sesssetup_ntlmssp_send(frame, ev, cli, user, domain, pass);
328 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
331 status = smb2cli_sesssetup_ntlmssp_recv(req);
337 struct smb2cli_logoff_state {
341 static void smb2cli_logoff_done(struct tevent_req *subreq);
343 struct tevent_req *smb2cli_logoff_send(TALLOC_CTX *mem_ctx,
344 struct tevent_context *ev,
345 struct cli_state *cli)
347 struct tevent_req *req, *subreq;
348 struct smb2cli_logoff_state *state;
350 req = tevent_req_create(mem_ctx, &state,
351 struct smb2cli_logoff_state);
355 SSVAL(state->fixed, 0, 4);
357 subreq = smb2cli_req_send(state, ev, cli, SMB2_OP_LOGOFF,
363 state->fixed, sizeof(state->fixed),
365 if (tevent_req_nomem(subreq, req)) {
366 return tevent_req_post(req, ev);
368 tevent_req_set_callback(subreq, smb2cli_logoff_done, req);
372 static void smb2cli_logoff_done(struct tevent_req *subreq)
374 struct tevent_req *req =
375 tevent_req_callback_data(subreq,
379 static const struct smb2cli_req_expected_response expected[] = {
381 .status = NT_STATUS_OK,
386 status = smb2cli_req_recv(subreq, talloc_tos(), &iov,
387 expected, ARRAY_SIZE(expected));
389 if (tevent_req_nterror(req, status)) {
392 tevent_req_done(req);
395 NTSTATUS smb2cli_logoff_recv(struct tevent_req *req)
397 return tevent_req_simple_recv_ntstatus(req);
400 NTSTATUS smb2cli_logoff(struct cli_state *cli)
402 TALLOC_CTX *frame = talloc_stackframe();
403 struct event_context *ev;
404 struct tevent_req *req;
405 NTSTATUS status = NT_STATUS_NO_MEMORY;
407 if (cli_has_async_calls(cli)) {
409 * Can't use sync call while an async call is in flight
411 status = NT_STATUS_INVALID_PARAMETER;
414 ev = event_context_init(frame);
418 req = smb2cli_logoff_send(frame, ev, cli);
422 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
425 status = smb2cli_logoff_recv(req);