s3-torture/denytest.c: replace cli_read_old() with cli_read()
[Samba/gebeck_regimport.git] / source3 / libsmb / smb2cli_session.c
blobc7d880e7aa9e36aca692af6dfea00014a10beb7d
1 /*
2 Unix SMB/CIFS implementation.
3 smb2 lib
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/>.
20 #include "includes.h"
21 #include "client.h"
22 #include "async_smb.h"
23 #include "smb2cli_base.h"
24 #include "smb2cli.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;
31 uint8_t fixed[24];
32 uint64_t uid;
33 DATA_BLOB out;
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,
41 DATA_BLOB *blob)
43 struct tevent_req *req, *subreq;
44 struct smb2cli_sesssetup_blob_state *state;
45 uint8_t *buf;
47 req = tevent_req_create(mem_ctx, &state,
48 struct smb2cli_sesssetup_blob_state);
49 if (req == NULL) {
50 return NULL;
53 buf = state->fixed;
55 SSVAL(buf, 0, 25);
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);
71 return req;
74 static void smb2cli_sesssetup_blob_done(struct tevent_req *subreq)
76 struct tevent_req *req =
77 tevent_req_callback_data(subreq,
78 struct tevent_req);
79 struct smb2cli_sesssetup_blob_state *state =
80 tevent_req_data(req,
81 struct smb2cli_sesssetup_blob_state);
82 NTSTATUS status;
83 struct iovec *iov;
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)) {
89 TALLOC_FREE(subreq);
90 tevent_req_nterror(req, status);
91 return;
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)) {
98 TALLOC_FREE(subreq);
99 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
100 return;
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);
107 return;
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 =
116 tevent_req_data(req,
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)) {
122 return status;
124 *uid = state->uid;
125 *out = state->out;
126 return status;
129 struct smb2cli_sesssetup_state {
130 struct tevent_context *ev;
131 struct cli_state *cli;
132 struct ntlmssp_state *ntlmssp;
133 struct iovec iov[2];
134 uint8_t fixed[24];
135 DATA_BLOB msg;
136 int turn;
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,
144 const char *user,
145 const char *domain,
146 const char *pass)
148 struct tevent_req *req, *subreq;
149 struct smb2cli_sesssetup_state *state;
150 NTSTATUS status;
151 DATA_BLOB blob_out;
152 const char *OIDs_ntlm[] = {OID_NTLMSSP, NULL};
154 req = tevent_req_create(mem_ctx, &state,
155 struct smb2cli_sesssetup_state);
156 if (req == NULL) {
157 return NULL;
159 state->ev = ev;
160 state->cli = cli;
162 status = ntlmssp_client_start(state,
163 lp_netbios_name(),
164 lp_workgroup(),
165 lp_client_ntlmv2_auth(),
166 &state->ntlmssp);
167 if (!NT_STATUS_IS_OK(status)) {
168 goto post_status;
170 status = ntlmssp_set_username(state->ntlmssp, user);
171 if (!NT_STATUS_IS_OK(status)) {
172 goto post_status;
174 status = ntlmssp_set_domain(state->ntlmssp, domain);
175 if (!NT_STATUS_IS_OK(status)) {
176 goto post_status;
178 status = ntlmssp_set_password(state->ntlmssp, pass);
179 if (!NT_STATUS_IS_OK(status)) {
180 goto post_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)) {
186 goto post_status;
189 blob_out = spnego_gen_negTokenInit(state, OIDs_ntlm, &blob_out, NULL);
190 state->turn = 1;
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);
198 return req;
199 post_status:
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,
208 struct tevent_req);
209 struct smb2cli_sesssetup_state *state =
210 tevent_req_data(req,
211 struct smb2cli_sesssetup_state);
212 NTSTATUS status;
213 uint64_t uid = 0;
214 DATA_BLOB blob, blob_in, blob_out, spnego_blob;
215 bool ret;
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)) {
220 TALLOC_FREE(subreq);
221 tevent_req_nterror(req, status);
222 return;
225 if (NT_STATUS_IS_OK(status)) {
226 TALLOC_FREE(subreq);
227 tevent_req_done(req);
228 return;
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);
235 } else {
236 ret = spnego_parse_auth_response(state, blob, status,
237 OID_NTLMSSP, &blob_in);
239 TALLOC_FREE(subreq);
240 if (!ret) {
241 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
242 return;
245 status = ntlmssp_update(state->ntlmssp, blob_in, &blob_out);
246 data_blob_free(&blob_in);
247 state->turn += 1;
249 if (!NT_STATUS_IS_OK(status)) {
250 tevent_req_nterror(req, status);
251 return;
254 state->cli->smb2.uid = uid;
256 spnego_blob = spnego_gen_auth(state, blob_out);
257 TALLOC_FREE(subreq);
258 if (tevent_req_nomem(spnego_blob.data, req)) {
259 return;
262 subreq = smb2cli_sesssetup_blob_send(
263 state, state->ev, state->cli, &spnego_blob);
264 if (tevent_req_nomem(subreq, req)) {
265 return;
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;
288 goto fail;
290 ev = event_context_init(frame);
291 if (ev == NULL) {
292 goto fail;
294 req = smb2cli_sesssetup_send(frame, ev, cli, user, domain, pass);
295 if (req == NULL) {
296 goto fail;
298 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
299 goto fail;
301 status = smb2cli_sesssetup_recv(req);
302 fail:
303 TALLOC_FREE(frame);
304 return status;
307 struct smb2cli_logoff_state {
308 uint8_t fixed[4];
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);
322 if (req == NULL) {
323 return NULL;
325 SSVAL(state->fixed, 0, 4);
327 subreq = smb2cli_req_send(state, ev, cli, SMB2_OP_LOGOFF, 0,
328 state->fixed, sizeof(state->fixed),
329 NULL, 0);
330 if (tevent_req_nomem(subreq, req)) {
331 return tevent_req_post(req, ev);
333 tevent_req_set_callback(subreq, smb2cli_logoff_done, req);
334 return req;
337 static void smb2cli_logoff_done(struct tevent_req *subreq)
339 struct tevent_req *req =
340 tevent_req_callback_data(subreq,
341 struct tevent_req);
342 NTSTATUS status;
343 struct iovec *iov;
345 status = smb2cli_req_recv(subreq, talloc_tos(), &iov, 4);
346 TALLOC_FREE(subreq);
347 if (tevent_req_nterror(req, status)) {
348 return;
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;
370 goto fail;
372 ev = event_context_init(frame);
373 if (ev == NULL) {
374 goto fail;
376 req = smb2cli_logoff_send(frame, ev, cli);
377 if (req == NULL) {
378 goto fail;
380 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
381 goto fail;
383 status = smb2cli_logoff_recv(req);
384 fail:
385 TALLOC_FREE(frame);
386 return status;