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