Line data Source code
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 "system/network.h"
22 : #include "../lib/util/tevent_ntstatus.h"
23 : #include "../libcli/smb/smb_common.h"
24 : #include "../libcli/smb/smbXcli_base.h"
25 :
26 : struct smb2cli_raw_tcon_state {
27 : struct smbXcli_session *session;
28 : struct smbXcli_tcon *tcon;
29 : uint8_t fixed[8];
30 : uint8_t dyn_pad[1];
31 : };
32 :
33 : static void smb2cli_raw_tcon_done(struct tevent_req *subreq);
34 :
35 51031 : struct tevent_req *smb2cli_raw_tcon_send(TALLOC_CTX *mem_ctx,
36 : struct tevent_context *ev,
37 : struct smbXcli_conn *conn,
38 : uint32_t additional_flags,
39 : uint32_t clear_flags,
40 : uint32_t timeout_msec,
41 : struct smbXcli_session *session,
42 : struct smbXcli_tcon *tcon,
43 : uint16_t tcon_flags,
44 : const char *unc)
45 : {
46 51031 : struct tevent_req *req = NULL;
47 51031 : struct smb2cli_raw_tcon_state *state = NULL;
48 51031 : struct tevent_req *subreq = NULL;
49 51031 : uint8_t *fixed = NULL;
50 51031 : uint8_t *dyn = NULL;
51 623 : size_t dyn_len;
52 :
53 51031 : req = tevent_req_create(mem_ctx, &state,
54 : struct smb2cli_raw_tcon_state);
55 51031 : if (req == NULL) {
56 0 : return NULL;
57 : }
58 51031 : state->session = session;
59 51031 : state->tcon = tcon;
60 :
61 51031 : if (!convert_string_talloc(state, CH_UNIX, CH_UTF16,
62 : unc, strlen(unc),
63 : &dyn, &dyn_len)) {
64 0 : tevent_req_oom(req);
65 0 : return tevent_req_post(req, ev);
66 : }
67 :
68 51031 : if (strlen(unc) == 0) {
69 0 : TALLOC_FREE(dyn);
70 0 : dyn_len = 0;
71 : }
72 :
73 51031 : fixed = state->fixed;
74 51031 : SSVAL(fixed, 0, 9);
75 51031 : if (smbXcli_conn_protocol(conn) >= PROTOCOL_SMB3_11) {
76 46618 : SSVAL(fixed, 2, tcon_flags);
77 : } else {
78 4413 : SSVAL(fixed, 2, 0); /* Reserved */
79 : }
80 51031 : SSVAL(fixed, 4, SMB2_HDR_BODY + 8);
81 51031 : SSVAL(fixed, 6, dyn_len);
82 :
83 51031 : if (dyn_len == 0) {
84 0 : dyn = state->dyn_pad;
85 0 : dyn_len = sizeof(state->dyn_pad);
86 : }
87 :
88 51654 : subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_TCON,
89 : additional_flags, clear_flags,
90 : timeout_msec,
91 : NULL, /* tcon */
92 : session,
93 51031 : state->fixed, sizeof(state->fixed),
94 : dyn, dyn_len,
95 : 0); /* max_dyn_len */
96 51031 : if (tevent_req_nomem(subreq, req)) {
97 0 : return tevent_req_post(req, ev);
98 : }
99 51031 : tevent_req_set_callback(subreq, smb2cli_raw_tcon_done, req);
100 :
101 51031 : return req;
102 : }
103 :
104 51031 : static void smb2cli_raw_tcon_done(struct tevent_req *subreq)
105 : {
106 51031 : struct tevent_req *req = tevent_req_callback_data(
107 : subreq, struct tevent_req);
108 51031 : struct smb2cli_raw_tcon_state *state = tevent_req_data(
109 : req, struct smb2cli_raw_tcon_state);
110 623 : NTSTATUS status;
111 623 : struct iovec *iov;
112 623 : uint8_t *body;
113 623 : uint32_t tcon_id;
114 623 : uint8_t share_type;
115 623 : uint32_t share_flags;
116 623 : uint32_t share_capabilities;
117 623 : uint32_t maximal_access;
118 623 : static const struct smb2cli_req_expected_response expected[] = {
119 : {
120 : .status = NT_STATUS_OK,
121 : .body_size = 0x10
122 : }
123 : };
124 :
125 51031 : status = smb2cli_req_recv(subreq, state, &iov,
126 : expected, ARRAY_SIZE(expected));
127 51031 : TALLOC_FREE(subreq);
128 51031 : if (!NT_STATUS_IS_OK(status)) {
129 126 : tevent_req_nterror(req, status);
130 126 : return;
131 : }
132 :
133 50905 : tcon_id = IVAL(iov[0].iov_base, SMB2_HDR_TID);
134 :
135 50905 : body = (uint8_t *)iov[1].iov_base;
136 50905 : share_type = CVAL(body, 0x02);
137 50905 : share_flags = IVAL(body, 0x04);
138 50905 : share_capabilities = IVAL(body, 0x08);
139 50905 : maximal_access = IVAL(body, 0x0C);
140 :
141 50905 : smb2cli_tcon_set_values(state->tcon,
142 : state->session,
143 : tcon_id,
144 : share_type,
145 : share_flags,
146 : share_capabilities,
147 : maximal_access);
148 :
149 50905 : tevent_req_done(req);
150 : }
151 :
152 51031 : NTSTATUS smb2cli_raw_tcon_recv(struct tevent_req *req)
153 : {
154 51031 : return tevent_req_simple_recv_ntstatus(req);
155 : }
156 :
157 18 : NTSTATUS smb2cli_raw_tcon(struct smbXcli_conn *conn,
158 : uint32_t additional_flags,
159 : uint32_t clear_flags,
160 : uint32_t timeout_msec,
161 : struct smbXcli_session *session,
162 : struct smbXcli_tcon *tcon,
163 : uint16_t tcon_flags,
164 : const char *unc)
165 : {
166 18 : TALLOC_CTX *frame = talloc_stackframe();
167 0 : struct tevent_context *ev;
168 0 : struct tevent_req *req;
169 18 : NTSTATUS status = NT_STATUS_NO_MEMORY;
170 :
171 18 : if (smbXcli_conn_has_async_calls(conn)) {
172 : /*
173 : * Can't use sync call while an async call is in flight
174 : */
175 0 : status = NT_STATUS_INVALID_PARAMETER;
176 0 : goto fail;
177 : }
178 18 : ev = samba_tevent_context_init(frame);
179 18 : if (ev == NULL) {
180 0 : goto fail;
181 : }
182 18 : req = smb2cli_raw_tcon_send(frame, ev, conn,
183 : additional_flags, clear_flags,
184 : timeout_msec, session, tcon,
185 : tcon_flags, unc);
186 18 : if (req == NULL) {
187 0 : goto fail;
188 : }
189 18 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
190 0 : goto fail;
191 : }
192 18 : status = smb2cli_raw_tcon_recv(req);
193 18 : fail:
194 18 : TALLOC_FREE(frame);
195 18 : return status;
196 : }
197 :
198 : struct smb2cli_tcon_state {
199 : struct tevent_context *ev;
200 : struct smbXcli_conn *conn;
201 : uint32_t timeout_msec;
202 : struct smbXcli_session *session;
203 : struct smbXcli_tcon *tcon;
204 : uint8_t fixed[8];
205 : uint8_t dyn_pad[1];
206 : };
207 :
208 : static void smb2cli_tcon_done(struct tevent_req *subreq);
209 :
210 51013 : struct tevent_req *smb2cli_tcon_send(TALLOC_CTX *mem_ctx,
211 : struct tevent_context *ev,
212 : struct smbXcli_conn *conn,
213 : uint32_t timeout_msec,
214 : struct smbXcli_session *session,
215 : struct smbXcli_tcon *tcon,
216 : uint16_t flags,
217 : const char *unc)
218 : {
219 623 : struct tevent_req *req, *subreq;
220 623 : struct smb2cli_tcon_state *state;
221 51013 : uint32_t additional_flags = 0;
222 51013 : uint32_t clear_flags = 0;
223 :
224 51013 : req = tevent_req_create(mem_ctx, &state, struct smb2cli_tcon_state);
225 51013 : if (req == NULL) {
226 0 : return NULL;
227 : }
228 51013 : state->ev = ev;
229 51013 : state->conn = conn;
230 51013 : state->timeout_msec = timeout_msec;
231 51013 : state->session = session;
232 51013 : state->tcon = tcon;
233 :
234 51013 : if (smbXcli_session_is_authenticated(state->session)) {
235 50027 : additional_flags |= SMB2_HDR_FLAG_SIGNED;
236 : }
237 :
238 51636 : subreq = smb2cli_raw_tcon_send(state,
239 50390 : state->ev,
240 50390 : state->conn,
241 : additional_flags,
242 : clear_flags,
243 50390 : state->timeout_msec,
244 50390 : state->session,
245 51013 : state->tcon,
246 : flags,
247 : unc);
248 51013 : if (tevent_req_nomem(subreq, req)) {
249 0 : return tevent_req_post(req, ev);
250 : }
251 51013 : tevent_req_set_callback(subreq, smb2cli_tcon_done, req);
252 :
253 51013 : return req;
254 : }
255 :
256 : static void smb2cli_tcon_validate(struct tevent_req *subreq);
257 :
258 51013 : static void smb2cli_tcon_done(struct tevent_req *subreq)
259 : {
260 51013 : struct tevent_req *req = tevent_req_callback_data(
261 : subreq, struct tevent_req);
262 51013 : struct smb2cli_tcon_state *state = tevent_req_data(
263 : req, struct smb2cli_tcon_state);
264 623 : NTSTATUS status;
265 :
266 51013 : status = smb2cli_raw_tcon_recv(subreq);
267 51013 : TALLOC_FREE(subreq);
268 51013 : if (tevent_req_nterror(req, status)) {
269 46713 : return;
270 : }
271 :
272 50891 : if (!smbXcli_session_is_authenticated(state->session)) {
273 980 : tevent_req_done(req);
274 980 : return;
275 : }
276 :
277 49911 : if (smbXcli_conn_protocol(state->conn) >= PROTOCOL_SMB3_11) {
278 45611 : tevent_req_done(req);
279 45611 : return;
280 : }
281 :
282 4300 : subreq = smb2cli_validate_negotiate_info_send(state, state->ev,
283 : state->conn,
284 : state->timeout_msec,
285 : state->session,
286 : state->tcon);
287 4300 : if (tevent_req_nomem(subreq, req)) {
288 0 : return;
289 : }
290 4300 : tevent_req_set_callback(subreq, smb2cli_tcon_validate, req);
291 : }
292 :
293 4300 : static void smb2cli_tcon_validate(struct tevent_req *subreq)
294 : {
295 4300 : struct tevent_req *req = tevent_req_callback_data(
296 : subreq, struct tevent_req);
297 4300 : struct smb2cli_tcon_state *state = tevent_req_data(
298 : req, struct smb2cli_tcon_state);
299 22 : NTSTATUS status;
300 :
301 4300 : status = smb2cli_validate_negotiate_info_recv(subreq);
302 4300 : TALLOC_FREE(subreq);
303 4300 : if (!NT_STATUS_IS_OK(status)) {
304 0 : smb2cli_tcon_set_values(state->tcon, NULL,
305 : UINT32_MAX, 0, 0, 0, 0);
306 0 : tevent_req_nterror(req, status);
307 0 : return;
308 : }
309 :
310 4300 : tevent_req_done(req);
311 : }
312 :
313 51013 : NTSTATUS smb2cli_tcon_recv(struct tevent_req *req)
314 : {
315 51013 : return tevent_req_simple_recv_ntstatus(req);
316 : }
317 :
318 0 : NTSTATUS smb2cli_tcon(struct smbXcli_conn *conn,
319 : uint32_t timeout_msec,
320 : struct smbXcli_session *session,
321 : struct smbXcli_tcon *tcon,
322 : uint16_t flags,
323 : const char *unc)
324 : {
325 0 : TALLOC_CTX *frame = talloc_stackframe();
326 0 : struct tevent_context *ev;
327 0 : struct tevent_req *req;
328 0 : NTSTATUS status = NT_STATUS_NO_MEMORY;
329 :
330 0 : if (smbXcli_conn_has_async_calls(conn)) {
331 : /*
332 : * Can't use sync call while an async call is in flight
333 : */
334 0 : status = NT_STATUS_INVALID_PARAMETER;
335 0 : goto fail;
336 : }
337 0 : ev = samba_tevent_context_init(frame);
338 0 : if (ev == NULL) {
339 0 : goto fail;
340 : }
341 0 : req = smb2cli_tcon_send(frame, ev, conn,
342 : timeout_msec, session, tcon,
343 : flags, unc);
344 0 : if (req == NULL) {
345 0 : goto fail;
346 : }
347 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
348 0 : goto fail;
349 : }
350 0 : status = smb2cli_tcon_recv(req);
351 0 : fail:
352 0 : TALLOC_FREE(frame);
353 0 : return status;
354 : }
355 :
356 : struct smb2cli_tdis_state {
357 : struct smbXcli_tcon *tcon;
358 : uint8_t fixed[4];
359 : };
360 :
361 : static void smb2cli_tdis_done(struct tevent_req *subreq);
362 :
363 34904 : struct tevent_req *smb2cli_tdis_send(TALLOC_CTX *mem_ctx,
364 : struct tevent_context *ev,
365 : struct smbXcli_conn *conn,
366 : uint32_t timeout_msec,
367 : struct smbXcli_session *session,
368 : struct smbXcli_tcon *tcon)
369 : {
370 0 : struct tevent_req *req, *subreq;
371 0 : struct smb2cli_tdis_state *state;
372 :
373 34904 : req = tevent_req_create(mem_ctx, &state,
374 : struct smb2cli_tdis_state);
375 34904 : if (req == NULL) {
376 0 : return NULL;
377 : }
378 34904 : state->tcon = tcon;
379 :
380 34904 : SSVAL(state->fixed, 0, 4);
381 :
382 34904 : subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_TDIS,
383 : 0, 0, /* flags */
384 : timeout_msec,
385 : tcon, session,
386 34904 : state->fixed, sizeof(state->fixed),
387 : NULL, 0, /* dyn* */
388 : 0); /* max_dyn_len */
389 34904 : if (tevent_req_nomem(subreq, req)) {
390 0 : return tevent_req_post(req, ev);
391 : }
392 34904 : tevent_req_set_callback(subreq, smb2cli_tdis_done, req);
393 34904 : return req;
394 : }
395 :
396 34904 : static void smb2cli_tdis_done(struct tevent_req *subreq)
397 : {
398 0 : struct tevent_req *req =
399 34904 : tevent_req_callback_data(subreq,
400 : struct tevent_req);
401 0 : struct smb2cli_tdis_state *state =
402 34904 : tevent_req_data(req,
403 : struct smb2cli_tdis_state);
404 0 : NTSTATUS status;
405 0 : static const struct smb2cli_req_expected_response expected[] = {
406 : {
407 : .status = NT_STATUS_OK,
408 : .body_size = 0x04
409 : }
410 : };
411 :
412 34904 : status = smb2cli_req_recv(subreq, NULL, NULL,
413 : expected, ARRAY_SIZE(expected));
414 34904 : TALLOC_FREE(subreq);
415 34904 : if (tevent_req_nterror(req, status)) {
416 120 : return;
417 : }
418 34784 : smb2cli_tcon_set_values(state->tcon, NULL,
419 : UINT32_MAX, 0, 0, 0, 0);
420 34784 : tevent_req_done(req);
421 : }
422 :
423 34904 : NTSTATUS smb2cli_tdis_recv(struct tevent_req *req)
424 : {
425 34904 : return tevent_req_simple_recv_ntstatus(req);
426 : }
427 :
428 34904 : NTSTATUS smb2cli_tdis(struct smbXcli_conn *conn,
429 : uint32_t timeout_msec,
430 : struct smbXcli_session *session,
431 : struct smbXcli_tcon *tcon)
432 : {
433 34904 : TALLOC_CTX *frame = talloc_stackframe();
434 0 : struct tevent_context *ev;
435 0 : struct tevent_req *req;
436 34904 : NTSTATUS status = NT_STATUS_NO_MEMORY;
437 :
438 34904 : if (smbXcli_conn_has_async_calls(conn)) {
439 : /*
440 : * Can't use sync call while an async call is in flight
441 : */
442 0 : status = NT_STATUS_INVALID_PARAMETER;
443 0 : goto fail;
444 : }
445 34904 : ev = samba_tevent_context_init(frame);
446 34904 : if (ev == NULL) {
447 0 : goto fail;
448 : }
449 34904 : req = smb2cli_tdis_send(frame, ev, conn,
450 : timeout_msec, session, tcon);
451 34904 : if (req == NULL) {
452 0 : goto fail;
453 : }
454 34904 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
455 0 : goto fail;
456 : }
457 34904 : status = smb2cli_tdis_recv(req);
458 34904 : fail:
459 34904 : TALLOC_FREE(frame);
460 34904 : return status;
461 : }
|