s3:smb2cli: s/smb2cli_sesssetup_blob/smb2cli_session_setup/
[rusty/samba.git] / source3 / libsmb / smb2cli_session.c
1 /*
2    Unix SMB/CIFS implementation.
3    smb2 lib
4    Copyright (C) Volker Lendecke 2011
5
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.
10
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.
15
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/>.
18 */
19
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"
28 #include "../libcli/auth/ntlmssp.h"
29
30 struct smb2cli_session_setup_state {
31         struct ntlmssp_state *ntlmssp;
32         uint8_t fixed[24];
33         uint8_t dyn_pad[1];
34         uint64_t uid;
35         DATA_BLOB out;
36 };
37
38 static void smb2cli_session_setup_done(struct tevent_req *subreq);
39
40 static struct tevent_req *smb2cli_session_setup_send(TALLOC_CTX *mem_ctx,
41                                                 struct tevent_context *ev,
42                                                 struct cli_state *cli,
43                                                 DATA_BLOB *blob)
44 {
45         struct tevent_req *req, *subreq;
46         struct smb2cli_session_setup_state *state;
47         uint8_t *buf;
48         uint8_t *dyn;
49         size_t dyn_len;
50
51         req = tevent_req_create(mem_ctx, &state,
52                                 struct smb2cli_session_setup_state);
53         if (req == NULL) {
54                 return NULL;
55         }
56
57         buf = state->fixed;
58
59         SSVAL(buf, 0, 25);
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 */
67
68         if (blob->length > 0) {
69                 dyn = blob->data;
70                 dyn_len = blob->length;
71         } else {
72                 dyn = state->dyn_pad;;
73                 dyn_len = sizeof(state->dyn_pad);
74         }
75
76         subreq = smb2cli_req_send(state, ev, cli, SMB2_OP_SESSSETUP,
77                                   0, 0, /* flags */
78                                   cli->timeout,
79                                   cli->smb2.pid,
80                                   0, /* tid */
81                                   cli->smb2.uid,
82                                   state->fixed, sizeof(state->fixed),
83                                   dyn, dyn_len);
84         if (tevent_req_nomem(subreq, req)) {
85                 return tevent_req_post(req, ev);
86         }
87         tevent_req_set_callback(subreq, smb2cli_session_setup_done, req);
88         return req;
89 }
90
91 static void smb2cli_session_setup_done(struct tevent_req *subreq)
92 {
93         struct tevent_req *req =
94                 tevent_req_callback_data(subreq,
95                 struct tevent_req);
96         struct smb2cli_session_setup_state *state =
97                 tevent_req_data(req,
98                 struct smb2cli_session_setup_state);
99         NTSTATUS status;
100         struct iovec *iov;
101         uint16_t offset, length;
102         static const struct smb2cli_req_expected_response expected[] = {
103         {
104                 .status = NT_STATUS_MORE_PROCESSING_REQUIRED,
105                 .body_size = 0x09
106         },
107         {
108                 .status = NT_STATUS_OK,
109                 .body_size = 0x09
110         }
111         };
112
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)) {
117                 TALLOC_FREE(subreq);
118                 tevent_req_nterror(req, status);
119                 return;
120         }
121
122         offset = SVAL(iov[1].iov_base, 4);
123         length = SVAL(iov[1].iov_base, 6);
124
125         if ((offset != SMB2_HDR_BODY + 8) || (length > iov[2].iov_len)) {
126                 TALLOC_FREE(subreq);
127                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
128                 return;
129         }
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);
135                 return;
136         }
137         tevent_req_done(req);
138 }
139
140 static NTSTATUS smb2cli_session_setup_recv(struct tevent_req *req,
141                                             uint64_t *uid, DATA_BLOB *out)
142 {
143         struct smb2cli_session_setup_state *state =
144                 tevent_req_data(req,
145                 struct smb2cli_session_setup_state);
146         NTSTATUS status = NT_STATUS_OK;
147
148         if (tevent_req_is_nterror(req, &status)
149             && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
150                 return status;
151         }
152         *uid = state->uid;
153         *out = state->out;
154         return status;
155 }
156
157 struct smb2cli_sesssetup_ntlmssp_state {
158         struct tevent_context *ev;
159         struct cli_state *cli;
160         struct ntlmssp_state *ntlmssp;
161         struct iovec iov[2];
162         uint8_t fixed[24];
163         DATA_BLOB msg;
164         int turn;
165 };
166
167 static void smb2cli_sesssetup_ntlmssp_done(struct tevent_req *subreq);
168
169 struct tevent_req *smb2cli_sesssetup_ntlmssp_send(TALLOC_CTX *mem_ctx,
170                                           struct tevent_context *ev,
171                                           struct cli_state *cli,
172                                           const char *user,
173                                           const char *domain,
174                                           const char *pass)
175 {
176         struct tevent_req *req, *subreq;
177         struct smb2cli_sesssetup_ntlmssp_state *state;
178         NTSTATUS status;
179         DATA_BLOB blob_out;
180         const char *OIDs_ntlm[] = {OID_NTLMSSP, NULL};
181
182         req = tevent_req_create(mem_ctx, &state,
183                                 struct smb2cli_sesssetup_ntlmssp_state);
184         if (req == NULL) {
185                 return NULL;
186         }
187         state->ev = ev;
188         state->cli = cli;
189
190         status = ntlmssp_client_start(state,
191                                       lp_netbios_name(),
192                                       lp_workgroup(),
193                                       lp_client_ntlmv2_auth(),
194                                       &state->ntlmssp);
195         if (!NT_STATUS_IS_OK(status)) {
196                 goto post_status;
197         }
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)) {
202                 goto post_status;
203         }
204         status = ntlmssp_set_domain(state->ntlmssp, domain);
205         if (!NT_STATUS_IS_OK(status)) {
206                 goto post_status;
207         }
208         status = ntlmssp_set_password(state->ntlmssp, pass);
209         if (!NT_STATUS_IS_OK(status)) {
210                 goto post_status;
211         }
212
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)) {
216                 goto post_status;
217         }
218
219         blob_out = spnego_gen_negTokenInit(state, OIDs_ntlm, &blob_out, NULL);
220         state->turn = 1;
221
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);
226         }
227         tevent_req_set_callback(subreq, smb2cli_sesssetup_ntlmssp_done, req);
228         return req;
229 post_status:
230         tevent_req_nterror(req, status);
231         return tevent_req_post(req, ev);
232 }
233
234 static void smb2cli_sesssetup_ntlmssp_done(struct tevent_req *subreq)
235 {
236         struct tevent_req *req =
237                 tevent_req_callback_data(subreq,
238                 struct tevent_req);
239         struct smb2cli_sesssetup_ntlmssp_state *state =
240                 tevent_req_data(req,
241                 struct smb2cli_sesssetup_ntlmssp_state);
242         NTSTATUS status;
243         uint64_t uid = 0;
244         DATA_BLOB blob, blob_in, blob_out, spnego_blob;
245         bool ret;
246
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)) {
250                 TALLOC_FREE(subreq);
251                 tevent_req_nterror(req, status);
252                 return;
253         }
254
255         if (NT_STATUS_IS_OK(status)) {
256                 TALLOC_FREE(subreq);
257                 tevent_req_done(req);
258                 return;
259         }
260
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);
265         } else {
266                 ret = spnego_parse_auth_response(state, blob, status,
267                                                  OID_NTLMSSP, &blob_in);
268         }
269         TALLOC_FREE(subreq);
270         if (!ret) {
271                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
272                 return;
273         }
274
275         status = ntlmssp_update(state->ntlmssp, blob_in, &blob_out);
276         data_blob_free(&blob_in);
277         state->turn += 1;
278
279         if (!NT_STATUS_IS_OK(status)) {
280                 tevent_req_nterror(req, status);
281                 return;
282         }
283
284         state->cli->smb2.uid = uid;
285
286         spnego_blob = spnego_gen_auth(state, blob_out);
287         TALLOC_FREE(subreq);
288         if (tevent_req_nomem(spnego_blob.data, req)) {
289                 return;
290         }
291
292         subreq = smb2cli_session_setup_send(
293                 state, state->ev, state->cli, &spnego_blob);
294         if (tevent_req_nomem(subreq, req)) {
295                 return;
296         }
297         tevent_req_set_callback(subreq, smb2cli_sesssetup_ntlmssp_done, req);
298 }
299
300 NTSTATUS smb2cli_sesssetup_ntlmssp_recv(struct tevent_req *req)
301 {
302         return tevent_req_simple_recv_ntstatus(req);
303 }
304
305 NTSTATUS smb2cli_sesssetup_ntlmssp(struct cli_state *cli, const char *user,
306                            const char *domain, const char *pass)
307 {
308         TALLOC_CTX *frame = talloc_stackframe();
309         struct event_context *ev;
310         struct tevent_req *req;
311         NTSTATUS status = NT_STATUS_NO_MEMORY;
312
313         if (cli_has_async_calls(cli)) {
314                 /*
315                  * Can't use sync call while an async call is in flight
316                  */
317                 status = NT_STATUS_INVALID_PARAMETER;
318                 goto fail;
319         }
320         ev = event_context_init(frame);
321         if (ev == NULL) {
322                 goto fail;
323         }
324         req = smb2cli_sesssetup_ntlmssp_send(frame, ev, cli, user, domain, pass);
325         if (req == NULL) {
326                 goto fail;
327         }
328         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
329                 goto fail;
330         }
331         status = smb2cli_sesssetup_ntlmssp_recv(req);
332  fail:
333         TALLOC_FREE(frame);
334         return status;
335 }
336
337 struct smb2cli_logoff_state {
338         uint8_t fixed[4];
339 };
340
341 static void smb2cli_logoff_done(struct tevent_req *subreq);
342
343 struct tevent_req *smb2cli_logoff_send(TALLOC_CTX *mem_ctx,
344                                        struct tevent_context *ev,
345                                        struct cli_state *cli)
346 {
347         struct tevent_req *req, *subreq;
348         struct smb2cli_logoff_state *state;
349
350         req = tevent_req_create(mem_ctx, &state,
351                                 struct smb2cli_logoff_state);
352         if (req == NULL) {
353                 return NULL;
354         }
355         SSVAL(state->fixed, 0, 4);
356
357         subreq = smb2cli_req_send(state, ev, cli, SMB2_OP_LOGOFF,
358                                   0, 0, /* flags */
359                                   cli->timeout,
360                                   cli->smb2.pid,
361                                   0, /* tid */
362                                   cli->smb2.uid,
363                                   state->fixed, sizeof(state->fixed),
364                                   NULL, 0);
365         if (tevent_req_nomem(subreq, req)) {
366                 return tevent_req_post(req, ev);
367         }
368         tevent_req_set_callback(subreq, smb2cli_logoff_done, req);
369         return req;
370 }
371
372 static void smb2cli_logoff_done(struct tevent_req *subreq)
373 {
374         struct tevent_req *req =
375                 tevent_req_callback_data(subreq,
376                 struct tevent_req);
377         NTSTATUS status;
378         struct iovec *iov;
379         static const struct smb2cli_req_expected_response expected[] = {
380         {
381                 .status = NT_STATUS_OK,
382                 .body_size = 0x04
383         }
384         };
385
386         status = smb2cli_req_recv(subreq, talloc_tos(), &iov,
387                                   expected, ARRAY_SIZE(expected));
388         TALLOC_FREE(subreq);
389         if (tevent_req_nterror(req, status)) {
390                 return;
391         }
392         tevent_req_done(req);
393 }
394
395 NTSTATUS smb2cli_logoff_recv(struct tevent_req *req)
396 {
397         return tevent_req_simple_recv_ntstatus(req);
398 }
399
400 NTSTATUS smb2cli_logoff(struct cli_state *cli)
401 {
402         TALLOC_CTX *frame = talloc_stackframe();
403         struct event_context *ev;
404         struct tevent_req *req;
405         NTSTATUS status = NT_STATUS_NO_MEMORY;
406
407         if (cli_has_async_calls(cli)) {
408                 /*
409                  * Can't use sync call while an async call is in flight
410                  */
411                 status = NT_STATUS_INVALID_PARAMETER;
412                 goto fail;
413         }
414         ev = event_context_init(frame);
415         if (ev == NULL) {
416                 goto fail;
417         }
418         req = smb2cli_logoff_send(frame, ev, cli);
419         if (req == NULL) {
420                 goto fail;
421         }
422         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
423                 goto fail;
424         }
425         status = smb2cli_logoff_recv(req);
426  fail:
427         TALLOC_FREE(frame);
428         return status;
429 }