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 42256 : 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 42256 : struct tevent_req *req = NULL;
47 42256 : struct smb2cli_raw_tcon_state *state = NULL;
48 42256 : struct tevent_req *subreq = NULL;
49 42256 : uint8_t *fixed = NULL;
50 42256 : uint8_t *dyn = NULL;
51 649 : size_t dyn_len;
52 :
53 42256 : req = tevent_req_create(mem_ctx, &state,
54 : struct smb2cli_raw_tcon_state);
55 42256 : if (req == NULL) {
56 0 : return NULL;
57 : }
58 42256 : state->session = session;
59 42256 : state->tcon = tcon;
60 :
61 42256 : 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 42256 : if (strlen(unc) == 0) {
69 0 : TALLOC_FREE(dyn);
70 0 : dyn_len = 0;
71 : }
72 :
73 42256 : fixed = state->fixed;
74 42256 : SSVAL(fixed, 0, 9);
75 42256 : if (smbXcli_conn_protocol(conn) >= PROTOCOL_SMB3_11) {
76 38142 : SSVAL(fixed, 2, tcon_flags);
77 : } else {
78 4114 : SSVAL(fixed, 2, 0); /* Reserved */
79 : }
80 42256 : SSVAL(fixed, 4, SMB2_HDR_BODY + 8);
81 42256 : SSVAL(fixed, 6, dyn_len);
82 :
83 42256 : if (dyn_len == 0) {
84 0 : dyn = state->dyn_pad;
85 0 : dyn_len = sizeof(state->dyn_pad);
86 : }
87 :
88 42905 : subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_TCON,
89 : additional_flags, clear_flags,
90 : timeout_msec,
91 : NULL, /* tcon */
92 : session,
93 42256 : state->fixed, sizeof(state->fixed),
94 : dyn, dyn_len,
95 : 0); /* max_dyn_len */
96 42256 : if (tevent_req_nomem(subreq, req)) {
97 0 : return tevent_req_post(req, ev);
98 : }
99 42256 : tevent_req_set_callback(subreq, smb2cli_raw_tcon_done, req);
100 :
101 42256 : return req;
102 : }
103 :
104 42256 : static void smb2cli_raw_tcon_done(struct tevent_req *subreq)
105 : {
106 42256 : struct tevent_req *req = tevent_req_callback_data(
107 : subreq, struct tevent_req);
108 42256 : struct smb2cli_raw_tcon_state *state = tevent_req_data(
109 : req, struct smb2cli_raw_tcon_state);
110 649 : NTSTATUS status;
111 649 : struct iovec *iov;
112 649 : uint8_t *body;
113 649 : uint32_t tcon_id;
114 649 : uint8_t share_type;
115 649 : uint32_t share_flags;
116 649 : uint32_t share_capabilities;
117 649 : uint32_t maximal_access;
118 649 : static const struct smb2cli_req_expected_response expected[] = {
119 : {
120 : .status = NT_STATUS_OK,
121 : .body_size = 0x10
122 : }
123 : };
124 :
125 42256 : status = smb2cli_req_recv(subreq, state, &iov,
126 : expected, ARRAY_SIZE(expected));
127 42256 : TALLOC_FREE(subreq);
128 42256 : if (!NT_STATUS_IS_OK(status)) {
129 156 : tevent_req_nterror(req, status);
130 156 : return;
131 : }
132 :
133 42100 : tcon_id = IVAL(iov[0].iov_base, SMB2_HDR_TID);
134 :
135 42100 : body = (uint8_t *)iov[1].iov_base;
136 42100 : share_type = CVAL(body, 0x02);
137 42100 : share_flags = IVAL(body, 0x04);
138 42100 : share_capabilities = IVAL(body, 0x08);
139 42100 : maximal_access = IVAL(body, 0x0C);
140 :
141 42100 : 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 42100 : tevent_req_done(req);
150 : }
151 :
152 42256 : NTSTATUS smb2cli_raw_tcon_recv(struct tevent_req *req)
153 : {
154 42256 : return tevent_req_simple_recv_ntstatus(req);
155 : }
156 :
157 16 : 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 16 : TALLOC_CTX *frame = talloc_stackframe();
167 0 : struct tevent_context *ev;
168 0 : struct tevent_req *req;
169 16 : NTSTATUS status = NT_STATUS_NO_MEMORY;
170 :
171 16 : 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 16 : ev = samba_tevent_context_init(frame);
179 16 : if (ev == NULL) {
180 0 : goto fail;
181 : }
182 16 : req = smb2cli_raw_tcon_send(frame, ev, conn,
183 : additional_flags, clear_flags,
184 : timeout_msec, session, tcon,
185 : tcon_flags, unc);
186 16 : if (req == NULL) {
187 0 : goto fail;
188 : }
189 16 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
190 0 : goto fail;
191 : }
192 16 : status = smb2cli_raw_tcon_recv(req);
193 16 : fail:
194 16 : TALLOC_FREE(frame);
195 16 : 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 42240 : 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 649 : struct tevent_req *req, *subreq;
220 649 : struct smb2cli_tcon_state *state;
221 42240 : uint32_t additional_flags = 0;
222 42240 : uint32_t clear_flags = 0;
223 :
224 42240 : req = tevent_req_create(mem_ctx, &state, struct smb2cli_tcon_state);
225 42240 : if (req == NULL) {
226 0 : return NULL;
227 : }
228 42240 : state->ev = ev;
229 42240 : state->conn = conn;
230 42240 : state->timeout_msec = timeout_msec;
231 42240 : state->session = session;
232 42240 : state->tcon = tcon;
233 :
234 42240 : if (smbXcli_session_is_authenticated(state->session)) {
235 41059 : additional_flags |= SMB2_HDR_FLAG_SIGNED;
236 : }
237 :
238 42889 : subreq = smb2cli_raw_tcon_send(state,
239 41591 : state->ev,
240 41591 : state->conn,
241 : additional_flags,
242 : clear_flags,
243 41591 : state->timeout_msec,
244 41591 : state->session,
245 42240 : state->tcon,
246 : flags,
247 : unc);
248 42240 : if (tevent_req_nomem(subreq, req)) {
249 0 : return tevent_req_post(req, ev);
250 : }
251 42240 : tevent_req_set_callback(subreq, smb2cli_tcon_done, req);
252 :
253 42240 : return req;
254 : }
255 :
256 : static void smb2cli_tcon_validate(struct tevent_req *subreq);
257 :
258 42240 : static void smb2cli_tcon_done(struct tevent_req *subreq)
259 : {
260 42240 : struct tevent_req *req = tevent_req_callback_data(
261 : subreq, struct tevent_req);
262 42240 : struct smb2cli_tcon_state *state = tevent_req_data(
263 : req, struct smb2cli_tcon_state);
264 649 : NTSTATUS status;
265 :
266 42240 : status = smb2cli_raw_tcon_recv(subreq);
267 42240 : TALLOC_FREE(subreq);
268 42240 : if (tevent_req_nterror(req, status)) {
269 38236 : return;
270 : }
271 :
272 42088 : if (!smbXcli_session_is_authenticated(state->session)) {
273 1139 : tevent_req_done(req);
274 1139 : return;
275 : }
276 :
277 40949 : if (smbXcli_conn_protocol(state->conn) >= PROTOCOL_SMB3_11) {
278 36945 : tevent_req_done(req);
279 36945 : return;
280 : }
281 :
282 4004 : subreq = smb2cli_validate_negotiate_info_send(state, state->ev,
283 : state->conn,
284 : state->timeout_msec,
285 : state->session,
286 : state->tcon);
287 4004 : if (tevent_req_nomem(subreq, req)) {
288 0 : return;
289 : }
290 4004 : tevent_req_set_callback(subreq, smb2cli_tcon_validate, req);
291 : }
292 :
293 4004 : static void smb2cli_tcon_validate(struct tevent_req *subreq)
294 : {
295 4004 : struct tevent_req *req = tevent_req_callback_data(
296 : subreq, struct tevent_req);
297 4004 : struct smb2cli_tcon_state *state = tevent_req_data(
298 : req, struct smb2cli_tcon_state);
299 22 : NTSTATUS status;
300 :
301 4004 : status = smb2cli_validate_negotiate_info_recv(subreq);
302 4004 : TALLOC_FREE(subreq);
303 4004 : 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 4004 : tevent_req_done(req);
311 : }
312 :
313 42240 : NTSTATUS smb2cli_tcon_recv(struct tevent_req *req)
314 : {
315 42240 : 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 27328 : 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 27328 : req = tevent_req_create(mem_ctx, &state,
374 : struct smb2cli_tdis_state);
375 27328 : if (req == NULL) {
376 0 : return NULL;
377 : }
378 27328 : state->tcon = tcon;
379 :
380 27328 : SSVAL(state->fixed, 0, 4);
381 :
382 27328 : subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_TDIS,
383 : 0, 0, /* flags */
384 : timeout_msec,
385 : tcon, session,
386 27328 : state->fixed, sizeof(state->fixed),
387 : NULL, 0, /* dyn* */
388 : 0); /* max_dyn_len */
389 27328 : if (tevent_req_nomem(subreq, req)) {
390 0 : return tevent_req_post(req, ev);
391 : }
392 27328 : tevent_req_set_callback(subreq, smb2cli_tdis_done, req);
393 27328 : return req;
394 : }
395 :
396 27328 : static void smb2cli_tdis_done(struct tevent_req *subreq)
397 : {
398 0 : struct tevent_req *req =
399 27328 : tevent_req_callback_data(subreq,
400 : struct tevent_req);
401 0 : struct smb2cli_tdis_state *state =
402 27328 : 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 27328 : status = smb2cli_req_recv(subreq, NULL, NULL,
413 : expected, ARRAY_SIZE(expected));
414 27328 : TALLOC_FREE(subreq);
415 27328 : if (tevent_req_nterror(req, status)) {
416 114 : return;
417 : }
418 27214 : smb2cli_tcon_set_values(state->tcon, NULL,
419 : UINT32_MAX, 0, 0, 0, 0);
420 27214 : tevent_req_done(req);
421 : }
422 :
423 27328 : NTSTATUS smb2cli_tdis_recv(struct tevent_req *req)
424 : {
425 27328 : return tevent_req_simple_recv_ntstatus(req);
426 : }
427 :
428 27328 : NTSTATUS smb2cli_tdis(struct smbXcli_conn *conn,
429 : uint32_t timeout_msec,
430 : struct smbXcli_session *session,
431 : struct smbXcli_tcon *tcon)
432 : {
433 27328 : TALLOC_CTX *frame = talloc_stackframe();
434 0 : struct tevent_context *ev;
435 0 : struct tevent_req *req;
436 27328 : NTSTATUS status = NT_STATUS_NO_MEMORY;
437 :
438 27328 : 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 27328 : ev = samba_tevent_context_init(frame);
446 27328 : if (ev == NULL) {
447 0 : goto fail;
448 : }
449 27328 : req = smb2cli_tdis_send(frame, ev, conn,
450 : timeout_msec, session, tcon);
451 27328 : if (req == NULL) {
452 0 : goto fail;
453 : }
454 27328 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
455 0 : goto fail;
456 : }
457 27328 : status = smb2cli_tdis_recv(req);
458 27328 : fail:
459 27328 : TALLOC_FREE(frame);
460 27328 : return status;
461 : }
|