Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : Copyright (C) Stefan Metzmacher 2010
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 "../lib/tsocket/tsocket.h"
24 : #include "../lib/tsocket/tsocket_internal.h"
25 : #include "smb_common.h"
26 : #include "smbXcli_base.h"
27 : #include "tstream_smbXcli_np.h"
28 : #include "libcli/security/security.h"
29 :
30 : static const struct tstream_context_ops tstream_smbXcli_np_ops;
31 :
32 : #define TSTREAM_SMBXCLI_NP_DESIRED_ACCESS ( \
33 : SEC_STD_READ_CONTROL | \
34 : SEC_FILE_READ_DATA | \
35 : SEC_FILE_WRITE_DATA | \
36 : SEC_FILE_APPEND_DATA | \
37 : SEC_FILE_READ_EA | \
38 : SEC_FILE_WRITE_EA | \
39 : SEC_FILE_READ_ATTRIBUTE | \
40 : SEC_FILE_WRITE_ATTRIBUTE | \
41 : 0)
42 :
43 : struct tstream_smbXcli_np_ref;
44 :
45 : struct tstream_smbXcli_np {
46 : struct smbXcli_conn *conn;
47 : struct tstream_smbXcli_np_ref *conn_ref;
48 : struct smbXcli_session *session;
49 : struct tstream_smbXcli_np_ref *session_ref;
50 : struct smbXcli_tcon *tcon;
51 : struct tstream_smbXcli_np_ref *tcon_ref;
52 : uint16_t pid;
53 : unsigned int timeout;
54 :
55 : const char *npipe;
56 : bool is_smb1;
57 : uint16_t fnum;
58 : uint64_t fid_persistent;
59 : uint64_t fid_volatile;
60 : uint32_t max_data;
61 :
62 : struct {
63 : bool active;
64 : struct tevent_req *read_req;
65 : struct tevent_req *write_req;
66 : uint16_t setup[2];
67 : } trans;
68 :
69 : struct {
70 : off_t ofs;
71 : size_t left;
72 : uint8_t *buf;
73 : } read, write;
74 : };
75 :
76 : struct tstream_smbXcli_np_ref {
77 : struct tstream_smbXcli_np *cli_nps;
78 : };
79 :
80 17914 : static int tstream_smbXcli_np_destructor(struct tstream_smbXcli_np *cli_nps)
81 : {
82 620 : NTSTATUS status;
83 :
84 17914 : if (cli_nps->conn_ref != NULL) {
85 17445 : cli_nps->conn_ref->cli_nps = NULL;
86 17445 : TALLOC_FREE(cli_nps->conn_ref);
87 : }
88 :
89 17914 : if (cli_nps->session_ref != NULL) {
90 17445 : cli_nps->session_ref->cli_nps = NULL;
91 17445 : TALLOC_FREE(cli_nps->session_ref);
92 : }
93 :
94 17914 : if (cli_nps->tcon_ref != NULL) {
95 17445 : cli_nps->tcon_ref->cli_nps = NULL;
96 17445 : TALLOC_FREE(cli_nps->tcon_ref);
97 : }
98 :
99 17914 : if (!smbXcli_conn_is_connected(cli_nps->conn)) {
100 7252 : return 0;
101 : }
102 :
103 : /*
104 : * TODO: do not use a sync call with a destructor!!!
105 : *
106 : * This only happens, if a caller does talloc_free(),
107 : * while the everything was still ok.
108 : *
109 : * If we get an unexpected failure within a normal
110 : * operation, we already do an async cli_close_send()/_recv().
111 : *
112 : * Once we've fixed all callers to call
113 : * tstream_disconnect_send()/_recv(), this will
114 : * never be called.
115 : *
116 : * We use a maximum timeout of 1 second == 1000 msec.
117 : */
118 10042 : cli_nps->timeout = MIN(cli_nps->timeout, 1000);
119 :
120 10042 : if (cli_nps->is_smb1) {
121 142 : status = smb1cli_close(cli_nps->conn,
122 : cli_nps->timeout,
123 142 : cli_nps->pid,
124 : cli_nps->tcon,
125 : cli_nps->session,
126 142 : cli_nps->fnum, UINT32_MAX);
127 : } else {
128 9900 : status = smb2cli_close(cli_nps->conn,
129 : cli_nps->timeout,
130 : cli_nps->session,
131 : cli_nps->tcon,
132 : 0, /* flags */
133 : cli_nps->fid_persistent,
134 : cli_nps->fid_volatile);
135 : }
136 10042 : if (!NT_STATUS_IS_OK(status)) {
137 0 : DEBUG(1, ("tstream_smbXcli_np_destructor: cli_close "
138 : "failed on pipe %s. Error was %s\n",
139 : cli_nps->npipe, nt_errstr(status)));
140 : }
141 : /*
142 : * We can't do much on failure
143 : */
144 10042 : return 0;
145 : }
146 :
147 53742 : static int tstream_smbXcli_np_ref_destructor(struct tstream_smbXcli_np_ref *ref)
148 : {
149 53742 : if (ref->cli_nps == NULL) {
150 50763 : return 0;
151 : }
152 :
153 1407 : if (ref->cli_nps->conn == NULL) {
154 746 : return 0;
155 : }
156 :
157 469 : ref->cli_nps->conn = NULL;
158 469 : ref->cli_nps->session = NULL;
159 469 : ref->cli_nps->tcon = NULL;
160 :
161 469 : TALLOC_FREE(ref->cli_nps->conn_ref);
162 469 : TALLOC_FREE(ref->cli_nps->session_ref);
163 469 : TALLOC_FREE(ref->cli_nps->tcon_ref);
164 :
165 373 : return 0;
166 : };
167 :
168 : static struct tevent_req *tstream_smbXcli_np_disconnect_send(TALLOC_CTX *mem_ctx,
169 : struct tevent_context *ev,
170 : struct tstream_context *stream);
171 : static int tstream_smbXcli_np_disconnect_recv(struct tevent_req *req,
172 : int *perrno);
173 :
174 : struct tstream_smbXcli_np_open_state {
175 : struct smbXcli_conn *conn;
176 : struct smbXcli_session *session;
177 : struct smbXcli_tcon *tcon;
178 : uint16_t pid;
179 : unsigned int timeout;
180 :
181 : bool is_smb1;
182 : uint16_t fnum;
183 : uint64_t fid_persistent;
184 : uint64_t fid_volatile;
185 : const char *npipe;
186 : };
187 :
188 : static void tstream_smbXcli_np_open_done(struct tevent_req *subreq);
189 :
190 18125 : struct tevent_req *tstream_smbXcli_np_open_send(TALLOC_CTX *mem_ctx,
191 : struct tevent_context *ev,
192 : struct smbXcli_conn *conn,
193 : struct smbXcli_session *session,
194 : struct smbXcli_tcon *tcon,
195 : uint16_t pid,
196 : unsigned int timeout,
197 : const char *npipe)
198 : {
199 620 : struct tevent_req *req;
200 620 : struct tstream_smbXcli_np_open_state *state;
201 620 : struct tevent_req *subreq;
202 :
203 18125 : req = tevent_req_create(mem_ctx, &state,
204 : struct tstream_smbXcli_np_open_state);
205 18125 : if (!req) {
206 0 : return NULL;
207 : }
208 18125 : state->conn = conn;
209 18125 : state->tcon = tcon;
210 18125 : state->session = session;
211 18125 : state->pid = pid;
212 18125 : state->timeout = timeout;
213 :
214 18125 : state->npipe = talloc_strdup(state, npipe);
215 18125 : if (tevent_req_nomem(state->npipe, req)) {
216 0 : return tevent_req_post(req, ev);
217 : }
218 :
219 18125 : if (smbXcli_conn_protocol(conn) < PROTOCOL_SMB2_02) {
220 361 : state->is_smb1 = true;
221 : }
222 :
223 18125 : if (state->is_smb1) {
224 0 : const char *smb1_npipe;
225 :
226 : /*
227 : * Windows and newer Samba versions allow
228 : * the pipe name without leading backslash,
229 : * but we should better behave like windows clients
230 : */
231 361 : smb1_npipe = talloc_asprintf(state, "\\%s", state->npipe);
232 361 : if (tevent_req_nomem(smb1_npipe, req)) {
233 0 : return tevent_req_post(req, ev);
234 : }
235 361 : subreq = smb1cli_ntcreatex_send(state, ev, state->conn,
236 361 : state->timeout,
237 361 : state->pid,
238 361 : state->tcon,
239 361 : state->session,
240 : smb1_npipe,
241 : 0, /* CreatFlags */
242 : 0, /* RootDirectoryFid */
243 : TSTREAM_SMBXCLI_NP_DESIRED_ACCESS,
244 : 0, /* AllocationSize */
245 : 0, /* FileAttributes */
246 : FILE_SHARE_READ|FILE_SHARE_WRITE,
247 : FILE_OPEN, /* CreateDisposition */
248 : 0, /* CreateOptions */
249 : 2, /* NTCREATEX_IMPERSONATION_IMPERSONATION */
250 : 0); /* SecurityFlags */
251 : } else {
252 17764 : subreq = smb2cli_create_send(state, ev, state->conn,
253 17144 : state->timeout, state->session,
254 17144 : state->tcon,
255 : npipe,
256 : SMB2_OPLOCK_LEVEL_NONE,
257 : SMB2_IMPERSONATION_IMPERSONATION,
258 : TSTREAM_SMBXCLI_NP_DESIRED_ACCESS,
259 : 0, /* file_attributes */
260 : FILE_SHARE_READ|FILE_SHARE_WRITE,
261 : FILE_OPEN,
262 : 0, /* create_options */
263 : NULL); /* blobs */
264 : }
265 18125 : if (tevent_req_nomem(subreq, req)) {
266 0 : return tevent_req_post(req, ev);
267 : }
268 18125 : tevent_req_set_callback(subreq, tstream_smbXcli_np_open_done, req);
269 :
270 18125 : return req;
271 : }
272 :
273 18125 : static void tstream_smbXcli_np_open_done(struct tevent_req *subreq)
274 : {
275 620 : struct tevent_req *req =
276 18125 : tevent_req_callback_data(subreq, struct tevent_req);
277 620 : struct tstream_smbXcli_np_open_state *state =
278 18125 : tevent_req_data(req, struct tstream_smbXcli_np_open_state);
279 620 : NTSTATUS status;
280 :
281 18125 : if (state->is_smb1) {
282 361 : status = smb1cli_ntcreatex_recv(subreq, &state->fnum);
283 : } else {
284 17764 : status = smb2cli_create_recv(
285 : subreq,
286 : &state->fid_persistent,
287 : &state->fid_volatile,
288 : NULL,
289 : NULL,
290 : NULL,
291 : NULL);
292 : }
293 18125 : TALLOC_FREE(subreq);
294 18125 : if (!NT_STATUS_IS_OK(status)) {
295 189 : tevent_req_nterror(req, status);
296 189 : return;
297 : }
298 :
299 17936 : tevent_req_done(req);
300 : }
301 :
302 18125 : NTSTATUS _tstream_smbXcli_np_open_recv(struct tevent_req *req,
303 : TALLOC_CTX *mem_ctx,
304 : struct tstream_context **_stream,
305 : const char *location)
306 : {
307 620 : struct tstream_smbXcli_np_open_state *state =
308 18125 : tevent_req_data(req, struct tstream_smbXcli_np_open_state);
309 620 : struct tstream_context *stream;
310 620 : struct tstream_smbXcli_np *cli_nps;
311 620 : NTSTATUS status;
312 :
313 18125 : if (tevent_req_is_nterror(req, &status)) {
314 189 : tevent_req_received(req);
315 189 : return status;
316 : }
317 :
318 17936 : stream = tstream_context_create(mem_ctx,
319 : &tstream_smbXcli_np_ops,
320 : &cli_nps,
321 : struct tstream_smbXcli_np,
322 : location);
323 17936 : if (!stream) {
324 0 : tevent_req_received(req);
325 0 : return NT_STATUS_NO_MEMORY;
326 : }
327 17936 : ZERO_STRUCTP(cli_nps);
328 :
329 17936 : cli_nps->conn_ref = talloc_zero(state->conn,
330 : struct tstream_smbXcli_np_ref);
331 17936 : if (cli_nps->conn_ref == NULL) {
332 0 : TALLOC_FREE(cli_nps);
333 0 : tevent_req_received(req);
334 0 : return NT_STATUS_NO_MEMORY;
335 : }
336 17936 : cli_nps->conn_ref->cli_nps = cli_nps;
337 :
338 17936 : cli_nps->session_ref = talloc_zero(state->session,
339 : struct tstream_smbXcli_np_ref);
340 17936 : if (cli_nps->session_ref == NULL) {
341 0 : TALLOC_FREE(cli_nps);
342 0 : tevent_req_received(req);
343 0 : return NT_STATUS_NO_MEMORY;
344 : }
345 17936 : cli_nps->session_ref->cli_nps = cli_nps;
346 :
347 17936 : cli_nps->tcon_ref = talloc_zero(state->tcon,
348 : struct tstream_smbXcli_np_ref);
349 17936 : if (cli_nps->tcon_ref == NULL) {
350 0 : TALLOC_FREE(cli_nps);
351 0 : tevent_req_received(req);
352 0 : return NT_STATUS_NO_MEMORY;
353 : }
354 17936 : cli_nps->tcon_ref->cli_nps = cli_nps;
355 :
356 17936 : cli_nps->conn = state->conn;
357 17936 : cli_nps->session = state->session;
358 17936 : cli_nps->tcon = state->tcon;
359 17936 : cli_nps->pid = state->pid;
360 17936 : cli_nps->timeout = state->timeout;
361 17936 : cli_nps->npipe = talloc_move(cli_nps, &state->npipe);
362 17936 : cli_nps->is_smb1 = state->is_smb1;
363 17936 : cli_nps->fnum = state->fnum;
364 17936 : cli_nps->fid_persistent = state->fid_persistent;
365 17936 : cli_nps->fid_volatile = state->fid_volatile;
366 17936 : cli_nps->max_data = TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE;
367 :
368 17936 : talloc_set_destructor(cli_nps, tstream_smbXcli_np_destructor);
369 17936 : talloc_set_destructor(cli_nps->conn_ref,
370 : tstream_smbXcli_np_ref_destructor);
371 17936 : talloc_set_destructor(cli_nps->session_ref,
372 : tstream_smbXcli_np_ref_destructor);
373 17936 : talloc_set_destructor(cli_nps->tcon_ref,
374 : tstream_smbXcli_np_ref_destructor);
375 :
376 17936 : cli_nps->trans.active = false;
377 17936 : cli_nps->trans.read_req = NULL;
378 17936 : cli_nps->trans.write_req = NULL;
379 17936 : SSVAL(cli_nps->trans.setup+0, 0, TRANSACT_DCERPCCMD);
380 17936 : SSVAL(cli_nps->trans.setup+1, 0, cli_nps->fnum);
381 :
382 17936 : *_stream = stream;
383 17936 : tevent_req_received(req);
384 17936 : return NT_STATUS_OK;
385 : }
386 :
387 331314 : static ssize_t tstream_smbXcli_np_pending_bytes(struct tstream_context *stream)
388 : {
389 331314 : struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
390 : struct tstream_smbXcli_np);
391 :
392 331314 : if (!smbXcli_conn_is_connected(cli_nps->conn)) {
393 0 : errno = ENOTCONN;
394 0 : return -1;
395 : }
396 :
397 331314 : return cli_nps->read.left;
398 : }
399 :
400 2694365 : bool tstream_is_smbXcli_np(struct tstream_context *stream)
401 : {
402 7951 : struct tstream_smbXcli_np *cli_nps =
403 2694365 : talloc_get_type(_tstream_context_data(stream),
404 : struct tstream_smbXcli_np);
405 :
406 2694365 : if (!cli_nps) {
407 1979958 : return false;
408 : }
409 :
410 707337 : return true;
411 : }
412 :
413 364529 : NTSTATUS tstream_smbXcli_np_use_trans(struct tstream_context *stream)
414 : {
415 364529 : struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
416 : struct tstream_smbXcli_np);
417 :
418 364529 : if (cli_nps->trans.read_req) {
419 0 : return NT_STATUS_PIPE_BUSY;
420 : }
421 :
422 364529 : if (cli_nps->trans.write_req) {
423 0 : return NT_STATUS_PIPE_BUSY;
424 : }
425 :
426 364529 : if (cli_nps->trans.active) {
427 0 : return NT_STATUS_PIPE_BUSY;
428 : }
429 :
430 364529 : cli_nps->trans.active = true;
431 :
432 364529 : return NT_STATUS_OK;
433 : }
434 :
435 0 : void tstream_smbXcli_np_set_max_data(struct tstream_context *stream,
436 : uint32_t max_data)
437 : {
438 0 : struct tstream_smbXcli_np *cli_nps = tstream_context_data(
439 : stream, struct tstream_smbXcli_np);
440 :
441 0 : cli_nps->max_data = max_data;
442 0 : }
443 :
444 482 : unsigned int tstream_smbXcli_np_set_timeout(struct tstream_context *stream,
445 : unsigned int timeout)
446 : {
447 482 : struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
448 : struct tstream_smbXcli_np);
449 482 : unsigned int old_timeout = cli_nps->timeout;
450 :
451 482 : cli_nps->timeout = timeout;
452 482 : return old_timeout;
453 : }
454 :
455 : struct tstream_smbXcli_np_writev_state {
456 : struct tstream_context *stream;
457 : struct tevent_context *ev;
458 :
459 : struct iovec *vector;
460 : size_t count;
461 :
462 : int ret;
463 :
464 : struct {
465 : int val;
466 : const char *location;
467 : } error;
468 : };
469 :
470 372601 : static int tstream_smbXcli_np_writev_state_destructor(struct tstream_smbXcli_np_writev_state *state)
471 : {
472 7070 : struct tstream_smbXcli_np *cli_nps =
473 372601 : tstream_context_data(state->stream,
474 : struct tstream_smbXcli_np);
475 :
476 372601 : cli_nps->trans.write_req = NULL;
477 :
478 372601 : return 0;
479 : }
480 :
481 : static void tstream_smbXcli_np_writev_write_next(struct tevent_req *req);
482 :
483 372601 : static struct tevent_req *tstream_smbXcli_np_writev_send(TALLOC_CTX *mem_ctx,
484 : struct tevent_context *ev,
485 : struct tstream_context *stream,
486 : const struct iovec *vector,
487 : size_t count)
488 : {
489 7070 : struct tevent_req *req;
490 7070 : struct tstream_smbXcli_np_writev_state *state;
491 372601 : struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
492 : struct tstream_smbXcli_np);
493 :
494 372601 : req = tevent_req_create(mem_ctx, &state,
495 : struct tstream_smbXcli_np_writev_state);
496 372601 : if (!req) {
497 0 : return NULL;
498 : }
499 372601 : state->stream = stream;
500 372601 : state->ev = ev;
501 372601 : state->ret = 0;
502 :
503 372601 : talloc_set_destructor(state, tstream_smbXcli_np_writev_state_destructor);
504 :
505 372601 : if (!smbXcli_conn_is_connected(cli_nps->conn)) {
506 0 : tevent_req_error(req, ENOTCONN);
507 0 : return tevent_req_post(req, ev);
508 : }
509 :
510 : /*
511 : * we make a copy of the vector so we can change the structure
512 : */
513 372601 : state->vector = talloc_array(state, struct iovec, count);
514 372601 : if (tevent_req_nomem(state->vector, req)) {
515 0 : return tevent_req_post(req, ev);
516 : }
517 372601 : memcpy(state->vector, vector, sizeof(struct iovec) * count);
518 372601 : state->count = count;
519 :
520 372601 : tstream_smbXcli_np_writev_write_next(req);
521 372601 : if (!tevent_req_is_in_progress(req)) {
522 0 : return tevent_req_post(req, ev);
523 : }
524 :
525 365531 : return req;
526 : }
527 :
528 : static void tstream_smbXcli_np_readv_trans_start(struct tevent_req *req);
529 : static void tstream_smbXcli_np_writev_write_done(struct tevent_req *subreq);
530 :
531 380673 : static void tstream_smbXcli_np_writev_write_next(struct tevent_req *req)
532 : {
533 7118 : struct tstream_smbXcli_np_writev_state *state =
534 380673 : tevent_req_data(req,
535 : struct tstream_smbXcli_np_writev_state);
536 7118 : struct tstream_smbXcli_np *cli_nps =
537 380673 : tstream_context_data(state->stream,
538 : struct tstream_smbXcli_np);
539 7118 : struct tevent_req *subreq;
540 7118 : size_t i;
541 380673 : size_t left = 0;
542 :
543 760392 : for (i=0; i < state->count; i++) {
544 372601 : left += state->vector[i].iov_len;
545 : }
546 :
547 380673 : if (left == 0) {
548 8072 : TALLOC_FREE(cli_nps->write.buf);
549 8072 : tevent_req_done(req);
550 8072 : return;
551 : }
552 :
553 372601 : cli_nps->write.ofs = 0;
554 372601 : cli_nps->write.left = MIN(left, cli_nps->max_data);
555 372601 : cli_nps->write.buf = talloc_realloc(cli_nps, cli_nps->write.buf,
556 : uint8_t, cli_nps->write.left);
557 372601 : if (tevent_req_nomem(cli_nps->write.buf, req)) {
558 0 : return;
559 : }
560 :
561 : /*
562 : * copy the pending buffer first
563 : */
564 745202 : while (cli_nps->write.left > 0 && state->count > 0) {
565 372601 : uint8_t *base = (uint8_t *)state->vector[0].iov_base;
566 372601 : size_t len = MIN(cli_nps->write.left, state->vector[0].iov_len);
567 :
568 372601 : memcpy(cli_nps->write.buf + cli_nps->write.ofs, base, len);
569 :
570 372601 : base += len;
571 372601 : state->vector[0].iov_base = base;
572 372601 : state->vector[0].iov_len -= len;
573 :
574 372601 : cli_nps->write.ofs += len;
575 372601 : cli_nps->write.left -= len;
576 :
577 372601 : if (state->vector[0].iov_len == 0) {
578 372601 : state->vector += 1;
579 372601 : state->count -= 1;
580 : }
581 :
582 372601 : state->ret += len;
583 : }
584 :
585 372601 : if (cli_nps->trans.active && state->count == 0) {
586 113360 : cli_nps->trans.active = false;
587 113360 : cli_nps->trans.write_req = req;
588 113360 : return;
589 : }
590 :
591 259241 : if (cli_nps->trans.read_req && state->count == 0) {
592 251169 : cli_nps->trans.write_req = req;
593 251169 : tstream_smbXcli_np_readv_trans_start(cli_nps->trans.read_req);
594 251169 : return;
595 : }
596 :
597 8072 : if (cli_nps->is_smb1) {
598 8 : subreq = smb1cli_writex_send(state, state->ev,
599 : cli_nps->conn,
600 : cli_nps->timeout,
601 8 : cli_nps->pid,
602 : cli_nps->tcon,
603 : cli_nps->session,
604 8 : cli_nps->fnum,
605 : 8, /* 8 means message mode. */
606 8 : cli_nps->write.buf,
607 : 0, /* offset */
608 8 : cli_nps->write.ofs); /* size */
609 : } else {
610 8064 : subreq = smb2cli_write_send(state, state->ev,
611 : cli_nps->conn,
612 : cli_nps->timeout,
613 : cli_nps->session,
614 : cli_nps->tcon,
615 8064 : cli_nps->write.ofs, /* length */
616 : 0, /* offset */
617 : cli_nps->fid_persistent,
618 : cli_nps->fid_volatile,
619 : 0, /* remaining_bytes */
620 : 0, /* flags */
621 8064 : cli_nps->write.buf);
622 : }
623 8072 : if (tevent_req_nomem(subreq, req)) {
624 0 : return;
625 : }
626 8072 : tevent_req_set_callback(subreq,
627 : tstream_smbXcli_np_writev_write_done,
628 : req);
629 : }
630 :
631 : static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req *req,
632 : int error,
633 : const char *location);
634 :
635 8072 : static void tstream_smbXcli_np_writev_write_done(struct tevent_req *subreq)
636 : {
637 48 : struct tevent_req *req =
638 8072 : tevent_req_callback_data(subreq, struct tevent_req);
639 48 : struct tstream_smbXcli_np_writev_state *state =
640 8072 : tevent_req_data(req, struct tstream_smbXcli_np_writev_state);
641 48 : struct tstream_smbXcli_np *cli_nps =
642 8072 : tstream_context_data(state->stream,
643 : struct tstream_smbXcli_np);
644 48 : uint32_t written;
645 48 : NTSTATUS status;
646 :
647 8072 : if (cli_nps->is_smb1) {
648 8 : status = smb1cli_writex_recv(subreq, &written, NULL);
649 : } else {
650 8064 : status = smb2cli_write_recv(subreq, &written);
651 : }
652 8072 : TALLOC_FREE(subreq);
653 8072 : if (!NT_STATUS_IS_OK(status)) {
654 0 : tstream_smbXcli_np_writev_disconnect_now(req, EPIPE, __location__);
655 0 : return;
656 : }
657 :
658 8072 : if (written != cli_nps->write.ofs) {
659 0 : tstream_smbXcli_np_writev_disconnect_now(req, EIO, __location__);
660 0 : return;
661 : }
662 :
663 8072 : tstream_smbXcli_np_writev_write_next(req);
664 : }
665 :
666 : static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req *subreq);
667 :
668 0 : static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req *req,
669 : int error,
670 : const char *location)
671 : {
672 0 : struct tstream_smbXcli_np_writev_state *state =
673 0 : tevent_req_data(req,
674 : struct tstream_smbXcli_np_writev_state);
675 0 : struct tstream_smbXcli_np *cli_nps =
676 0 : tstream_context_data(state->stream,
677 : struct tstream_smbXcli_np);
678 0 : struct tevent_req *subreq;
679 :
680 0 : state->error.val = error;
681 0 : state->error.location = location;
682 :
683 0 : if (!smbXcli_conn_is_connected(cli_nps->conn)) {
684 : /* return the original error */
685 0 : _tevent_req_error(req, state->error.val, state->error.location);
686 0 : return;
687 : }
688 :
689 0 : subreq = tstream_smbXcli_np_disconnect_send(state, state->ev,
690 : state->stream);
691 0 : if (subreq == NULL) {
692 : /* return the original error */
693 0 : _tevent_req_error(req, state->error.val, state->error.location);
694 0 : return;
695 : }
696 0 : tevent_req_set_callback(subreq,
697 : tstream_smbXcli_np_writev_disconnect_done,
698 : req);
699 : }
700 :
701 0 : static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req *subreq)
702 : {
703 0 : struct tevent_req *req =
704 0 : tevent_req_callback_data(subreq, struct tevent_req);
705 0 : struct tstream_smbXcli_np_writev_state *state =
706 0 : tevent_req_data(req, struct tstream_smbXcli_np_writev_state);
707 0 : int error;
708 :
709 0 : tstream_smbXcli_np_disconnect_recv(subreq, &error);
710 0 : TALLOC_FREE(subreq);
711 :
712 : /* return the original error */
713 0 : _tevent_req_error(req, state->error.val, state->error.location);
714 0 : }
715 :
716 372601 : static int tstream_smbXcli_np_writev_recv(struct tevent_req *req,
717 : int *perrno)
718 : {
719 7070 : struct tstream_smbXcli_np_writev_state *state =
720 372601 : tevent_req_data(req,
721 : struct tstream_smbXcli_np_writev_state);
722 7070 : int ret;
723 :
724 372601 : ret = tsocket_simple_int_recv(req, perrno);
725 372601 : if (ret == 0) {
726 372570 : ret = state->ret;
727 : }
728 :
729 372601 : tevent_req_received(req);
730 372601 : return ret;
731 : }
732 :
733 : struct tstream_smbXcli_np_readv_state {
734 : struct tstream_context *stream;
735 : struct tevent_context *ev;
736 :
737 : struct iovec *vector;
738 : size_t count;
739 :
740 : int ret;
741 :
742 : struct {
743 : struct tevent_immediate *im;
744 : } trans;
745 :
746 : struct {
747 : int val;
748 : const char *location;
749 : } error;
750 : };
751 :
752 745659 : static int tstream_smbXcli_np_readv_state_destructor(struct tstream_smbXcli_np_readv_state *state)
753 : {
754 14137 : struct tstream_smbXcli_np *cli_nps =
755 745659 : tstream_context_data(state->stream,
756 : struct tstream_smbXcli_np);
757 :
758 745659 : cli_nps->trans.read_req = NULL;
759 :
760 745659 : return 0;
761 : }
762 :
763 : static void tstream_smbXcli_np_readv_read_next(struct tevent_req *req);
764 :
765 745659 : static struct tevent_req *tstream_smbXcli_np_readv_send(TALLOC_CTX *mem_ctx,
766 : struct tevent_context *ev,
767 : struct tstream_context *stream,
768 : struct iovec *vector,
769 : size_t count)
770 : {
771 14137 : struct tevent_req *req;
772 14137 : struct tstream_smbXcli_np_readv_state *state;
773 14137 : struct tstream_smbXcli_np *cli_nps =
774 745659 : tstream_context_data(stream, struct tstream_smbXcli_np);
775 :
776 745659 : req = tevent_req_create(mem_ctx, &state,
777 : struct tstream_smbXcli_np_readv_state);
778 745659 : if (!req) {
779 0 : return NULL;
780 : }
781 745659 : state->stream = stream;
782 745659 : state->ev = ev;
783 745659 : state->ret = 0;
784 :
785 745659 : talloc_set_destructor(state, tstream_smbXcli_np_readv_state_destructor);
786 :
787 745659 : if (!smbXcli_conn_is_connected(cli_nps->conn)) {
788 0 : tevent_req_error(req, ENOTCONN);
789 0 : return tevent_req_post(req, ev);
790 : }
791 :
792 : /*
793 : * we make a copy of the vector so we can change the structure
794 : */
795 745659 : state->vector = talloc_array(state, struct iovec, count);
796 745659 : if (tevent_req_nomem(state->vector, req)) {
797 0 : return tevent_req_post(req, ev);
798 : }
799 745659 : memcpy(state->vector, vector, sizeof(struct iovec) * count);
800 745659 : state->count = count;
801 :
802 745659 : tstream_smbXcli_np_readv_read_next(req);
803 745659 : if (!tevent_req_is_in_progress(req)) {
804 372814 : return tevent_req_post(req, ev);
805 : }
806 :
807 365775 : return req;
808 : }
809 :
810 : static void tstream_smbXcli_np_readv_read_done(struct tevent_req *subreq);
811 :
812 1118473 : static void tstream_smbXcli_np_readv_read_next(struct tevent_req *req)
813 : {
814 21204 : struct tstream_smbXcli_np_readv_state *state =
815 1118473 : tevent_req_data(req,
816 : struct tstream_smbXcli_np_readv_state);
817 21204 : struct tstream_smbXcli_np *cli_nps =
818 1118473 : tstream_context_data(state->stream,
819 : struct tstream_smbXcli_np);
820 21204 : struct tevent_req *subreq;
821 :
822 : /*
823 : * copy the pending buffer first
824 : */
825 1864101 : while (cli_nps->read.left > 0 && state->count > 0) {
826 745628 : uint8_t *base = (uint8_t *)state->vector[0].iov_base;
827 745628 : size_t len = MIN(cli_nps->read.left, state->vector[0].iov_len);
828 :
829 745628 : memcpy(base, cli_nps->read.buf + cli_nps->read.ofs, len);
830 :
831 745628 : base += len;
832 745628 : state->vector[0].iov_base = base;
833 745628 : state->vector[0].iov_len -= len;
834 :
835 745628 : cli_nps->read.ofs += len;
836 745628 : cli_nps->read.left -= len;
837 :
838 745628 : if (state->vector[0].iov_len == 0) {
839 745628 : state->vector += 1;
840 745628 : state->count -= 1;
841 : }
842 :
843 745628 : state->ret += len;
844 : }
845 :
846 1118473 : if (cli_nps->read.left == 0) {
847 745659 : TALLOC_FREE(cli_nps->read.buf);
848 : }
849 :
850 1118473 : if (state->count == 0) {
851 745628 : tevent_req_done(req);
852 745628 : return;
853 : }
854 :
855 372845 : if (cli_nps->trans.active) {
856 251169 : cli_nps->trans.active = false;
857 251169 : cli_nps->trans.read_req = req;
858 251169 : return;
859 : }
860 :
861 121676 : if (cli_nps->trans.write_req) {
862 113360 : cli_nps->trans.read_req = req;
863 113360 : tstream_smbXcli_np_readv_trans_start(req);
864 113360 : return;
865 : }
866 :
867 8316 : if (cli_nps->is_smb1) {
868 34 : subreq = smb1cli_readx_send(state, state->ev,
869 : cli_nps->conn,
870 : cli_nps->timeout,
871 34 : cli_nps->pid,
872 : cli_nps->tcon,
873 : cli_nps->session,
874 34 : cli_nps->fnum,
875 : 0, /* offset */
876 : cli_nps->max_data);
877 : } else {
878 8282 : subreq = smb2cli_read_send(state, state->ev,
879 : cli_nps->conn,
880 : cli_nps->timeout,
881 : cli_nps->session,
882 : cli_nps->tcon,
883 : cli_nps->max_data, /* length */
884 : 0, /* offset */
885 : cli_nps->fid_persistent,
886 : cli_nps->fid_volatile,
887 : 0, /* minimum_count */
888 : 0); /* remaining_bytes */
889 : }
890 8316 : if (tevent_req_nomem(subreq, req)) {
891 0 : return;
892 : }
893 8316 : tevent_req_set_callback(subreq,
894 : tstream_smbXcli_np_readv_read_done,
895 : req);
896 : }
897 :
898 : static void tstream_smbXcli_np_readv_trans_done(struct tevent_req *subreq);
899 :
900 364529 : static void tstream_smbXcli_np_readv_trans_start(struct tevent_req *req)
901 : {
902 7022 : struct tstream_smbXcli_np_readv_state *state =
903 364529 : tevent_req_data(req,
904 : struct tstream_smbXcli_np_readv_state);
905 7022 : struct tstream_smbXcli_np *cli_nps =
906 364529 : tstream_context_data(state->stream,
907 : struct tstream_smbXcli_np);
908 7022 : struct tevent_req *subreq;
909 :
910 364529 : state->trans.im = tevent_create_immediate(state);
911 364529 : if (tevent_req_nomem(state->trans.im, req)) {
912 0 : return;
913 : }
914 :
915 364529 : if (cli_nps->is_smb1) {
916 1470 : subreq = smb1cli_trans_send(state, state->ev,
917 : cli_nps->conn, SMBtrans,
918 : 0, 0, /* *_flags */
919 : 0, 0, /* *_flags2 */
920 : cli_nps->timeout,
921 1470 : cli_nps->pid,
922 : cli_nps->tcon,
923 : cli_nps->session,
924 : "\\PIPE\\",
925 : 0, 0, 0,
926 1470 : cli_nps->trans.setup, 2,
927 : 0,
928 : NULL, 0, 0,
929 : cli_nps->write.buf,
930 1470 : cli_nps->write.ofs,
931 : cli_nps->max_data);
932 : } else {
933 363059 : DATA_BLOB in_input_buffer = data_blob_null;
934 363059 : DATA_BLOB in_output_buffer = data_blob_null;
935 :
936 363059 : in_input_buffer = data_blob_const(cli_nps->write.buf,
937 363059 : cli_nps->write.ofs);
938 :
939 363059 : subreq = smb2cli_ioctl_send(state, state->ev,
940 : cli_nps->conn,
941 : cli_nps->timeout,
942 : cli_nps->session,
943 : cli_nps->tcon,
944 : cli_nps->fid_persistent,
945 : cli_nps->fid_volatile,
946 : FSCTL_NAMED_PIPE_READ_WRITE,
947 : 0, /* in_max_input_length */
948 : &in_input_buffer,
949 : /* in_max_output_length */
950 : cli_nps->max_data,
951 : &in_output_buffer,
952 : SMB2_IOCTL_FLAG_IS_FSCTL);
953 : }
954 364529 : if (tevent_req_nomem(subreq, req)) {
955 0 : return;
956 : }
957 364529 : tevent_req_set_callback(subreq,
958 : tstream_smbXcli_np_readv_trans_done,
959 : req);
960 : }
961 :
962 : static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req *req,
963 : int error,
964 : const char *location);
965 : static void tstream_smbXcli_np_readv_trans_next(struct tevent_context *ctx,
966 : struct tevent_immediate *im,
967 : void *private_data);
968 :
969 364529 : static void tstream_smbXcli_np_readv_trans_done(struct tevent_req *subreq)
970 : {
971 7022 : struct tevent_req *req =
972 364529 : tevent_req_callback_data(subreq, struct tevent_req);
973 7022 : struct tstream_smbXcli_np_readv_state *state =
974 364529 : tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
975 7022 : struct tstream_smbXcli_np *cli_nps =
976 364529 : tstream_context_data(state->stream, struct tstream_smbXcli_np);
977 7022 : uint8_t *rcvbuf;
978 7022 : uint32_t received;
979 7022 : NTSTATUS status;
980 :
981 364529 : if (cli_nps->is_smb1) {
982 1470 : status = smb1cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
983 : NULL, 0, NULL,
984 : &rcvbuf, 0, &received);
985 : } else {
986 363059 : DATA_BLOB out_input_buffer = data_blob_null;
987 363059 : DATA_BLOB out_output_buffer = data_blob_null;
988 :
989 363059 : status = smb2cli_ioctl_recv(subreq, state,
990 : &out_input_buffer,
991 : &out_output_buffer);
992 :
993 : /* Note that rcvbuf is not a talloc pointer here */
994 363059 : rcvbuf = out_output_buffer.data;
995 363059 : received = out_output_buffer.length;
996 : }
997 364529 : TALLOC_FREE(subreq);
998 364529 : if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
999 : /*
1000 : * STATUS_BUFFER_OVERFLOW means that there's
1001 : * more data to read when the named pipe is used
1002 : * in message mode (which is the case here).
1003 : *
1004 : * But we hide this from the caller.
1005 : */
1006 0 : status = NT_STATUS_OK;
1007 : }
1008 364529 : if (!NT_STATUS_IS_OK(status)) {
1009 31 : tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
1010 34 : return;
1011 : }
1012 :
1013 364498 : if (received > cli_nps->max_data) {
1014 0 : tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
1015 0 : return;
1016 : }
1017 :
1018 364498 : if (received == 0) {
1019 0 : tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
1020 0 : return;
1021 : }
1022 :
1023 364498 : cli_nps->read.ofs = 0;
1024 364498 : cli_nps->read.left = received;
1025 364498 : cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received);
1026 364498 : if (cli_nps->read.buf == NULL) {
1027 0 : TALLOC_FREE(subreq);
1028 0 : tevent_req_oom(req);
1029 0 : return;
1030 : }
1031 364498 : memcpy(cli_nps->read.buf, rcvbuf, received);
1032 :
1033 364498 : if (cli_nps->trans.write_req == NULL) {
1034 0 : tstream_smbXcli_np_readv_read_next(req);
1035 0 : return;
1036 : }
1037 :
1038 364498 : tevent_schedule_immediate(state->trans.im, state->ev,
1039 7019 : tstream_smbXcli_np_readv_trans_next, req);
1040 :
1041 364498 : tevent_req_done(cli_nps->trans.write_req);
1042 : }
1043 :
1044 364498 : static void tstream_smbXcli_np_readv_trans_next(struct tevent_context *ctx,
1045 : struct tevent_immediate *im,
1046 : void *private_data)
1047 : {
1048 7019 : struct tevent_req *req =
1049 364498 : talloc_get_type_abort(private_data,
1050 : struct tevent_req);
1051 :
1052 364498 : tstream_smbXcli_np_readv_read_next(req);
1053 364498 : }
1054 :
1055 8316 : static void tstream_smbXcli_np_readv_read_done(struct tevent_req *subreq)
1056 : {
1057 48 : struct tevent_req *req =
1058 8316 : tevent_req_callback_data(subreq, struct tevent_req);
1059 48 : struct tstream_smbXcli_np_readv_state *state =
1060 8316 : tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
1061 48 : struct tstream_smbXcli_np *cli_nps =
1062 8316 : tstream_context_data(state->stream, struct tstream_smbXcli_np);
1063 48 : uint8_t *rcvbuf;
1064 48 : uint32_t received;
1065 48 : NTSTATUS status;
1066 :
1067 : /*
1068 : * We must free subreq in this function as there is
1069 : * a timer event attached to it.
1070 : */
1071 :
1072 8316 : if (cli_nps->is_smb1) {
1073 34 : status = smb1cli_readx_recv(subreq, &received, &rcvbuf);
1074 : } else {
1075 8282 : status = smb2cli_read_recv(subreq, state, &rcvbuf, &received);
1076 : }
1077 : /*
1078 : * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
1079 : * child of that.
1080 : */
1081 8316 : if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
1082 : /*
1083 : * STATUS_BUFFER_OVERFLOW means that there's
1084 : * more data to read when the named pipe is used
1085 : * in message mode (which is the case here).
1086 : *
1087 : * But we hide this from the caller.
1088 : */
1089 0 : status = NT_STATUS_OK;
1090 : }
1091 8316 : if (!NT_STATUS_IS_OK(status)) {
1092 0 : TALLOC_FREE(subreq);
1093 0 : tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
1094 0 : return;
1095 : }
1096 :
1097 8316 : if (received > cli_nps->max_data) {
1098 0 : TALLOC_FREE(subreq);
1099 0 : tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
1100 0 : return;
1101 : }
1102 :
1103 8316 : if (received == 0) {
1104 0 : TALLOC_FREE(subreq);
1105 0 : tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
1106 0 : return;
1107 : }
1108 :
1109 8316 : cli_nps->read.ofs = 0;
1110 8316 : cli_nps->read.left = received;
1111 8316 : cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received);
1112 8316 : if (cli_nps->read.buf == NULL) {
1113 0 : TALLOC_FREE(subreq);
1114 0 : tevent_req_oom(req);
1115 0 : return;
1116 : }
1117 8316 : memcpy(cli_nps->read.buf, rcvbuf, received);
1118 8316 : TALLOC_FREE(subreq);
1119 :
1120 8316 : tstream_smbXcli_np_readv_read_next(req);
1121 : }
1122 :
1123 : static void tstream_smbXcli_np_readv_disconnect_done(struct tevent_req *subreq);
1124 :
1125 : static void tstream_smbXcli_np_readv_error(struct tevent_req *req);
1126 :
1127 31 : static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req *req,
1128 : int error,
1129 : const char *location)
1130 : {
1131 3 : struct tstream_smbXcli_np_readv_state *state =
1132 31 : tevent_req_data(req,
1133 : struct tstream_smbXcli_np_readv_state);
1134 3 : struct tstream_smbXcli_np *cli_nps =
1135 31 : tstream_context_data(state->stream,
1136 : struct tstream_smbXcli_np);
1137 3 : struct tevent_req *subreq;
1138 :
1139 31 : state->error.val = error;
1140 31 : state->error.location = location;
1141 :
1142 31 : if (!smbXcli_conn_is_connected(cli_nps->conn)) {
1143 : /* return the original error */
1144 0 : tstream_smbXcli_np_readv_error(req);
1145 0 : return;
1146 : }
1147 :
1148 31 : subreq = tstream_smbXcli_np_disconnect_send(state, state->ev,
1149 : state->stream);
1150 31 : if (subreq == NULL) {
1151 : /* return the original error */
1152 0 : tstream_smbXcli_np_readv_error(req);
1153 0 : return;
1154 : }
1155 31 : tevent_req_set_callback(subreq,
1156 : tstream_smbXcli_np_readv_disconnect_done,
1157 : req);
1158 : }
1159 :
1160 31 : static void tstream_smbXcli_np_readv_disconnect_done(struct tevent_req *subreq)
1161 : {
1162 3 : struct tevent_req *req =
1163 31 : tevent_req_callback_data(subreq, struct tevent_req);
1164 3 : int error;
1165 :
1166 34 : tstream_smbXcli_np_disconnect_recv(subreq, &error);
1167 31 : TALLOC_FREE(subreq);
1168 :
1169 31 : tstream_smbXcli_np_readv_error(req);
1170 31 : }
1171 :
1172 : static void tstream_smbXcli_np_readv_error_trigger(struct tevent_context *ctx,
1173 : struct tevent_immediate *im,
1174 : void *private_data);
1175 :
1176 31 : static void tstream_smbXcli_np_readv_error(struct tevent_req *req)
1177 : {
1178 3 : struct tstream_smbXcli_np_readv_state *state =
1179 31 : tevent_req_data(req,
1180 : struct tstream_smbXcli_np_readv_state);
1181 3 : struct tstream_smbXcli_np *cli_nps =
1182 31 : tstream_context_data(state->stream,
1183 : struct tstream_smbXcli_np);
1184 :
1185 31 : if (cli_nps->trans.write_req == NULL) {
1186 : /* return the original error */
1187 0 : _tevent_req_error(req, state->error.val, state->error.location);
1188 0 : return;
1189 : }
1190 :
1191 31 : if (state->trans.im == NULL) {
1192 : /* return the original error */
1193 0 : _tevent_req_error(req, state->error.val, state->error.location);
1194 0 : return;
1195 : }
1196 :
1197 31 : tevent_schedule_immediate(state->trans.im, state->ev,
1198 3 : tstream_smbXcli_np_readv_error_trigger, req);
1199 :
1200 : /* return the original error for writev */
1201 31 : _tevent_req_error(cli_nps->trans.write_req,
1202 31 : state->error.val, state->error.location);
1203 : }
1204 :
1205 0 : static void tstream_smbXcli_np_readv_error_trigger(struct tevent_context *ctx,
1206 : struct tevent_immediate *im,
1207 : void *private_data)
1208 : {
1209 0 : struct tevent_req *req =
1210 0 : talloc_get_type_abort(private_data,
1211 : struct tevent_req);
1212 0 : struct tstream_smbXcli_np_readv_state *state =
1213 0 : tevent_req_data(req,
1214 : struct tstream_smbXcli_np_readv_state);
1215 :
1216 : /* return the original error */
1217 0 : _tevent_req_error(req, state->error.val, state->error.location);
1218 0 : }
1219 :
1220 745628 : static int tstream_smbXcli_np_readv_recv(struct tevent_req *req,
1221 : int *perrno)
1222 : {
1223 14134 : struct tstream_smbXcli_np_readv_state *state =
1224 745628 : tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
1225 14134 : int ret;
1226 :
1227 745628 : ret = tsocket_simple_int_recv(req, perrno);
1228 745628 : if (ret == 0) {
1229 745628 : ret = state->ret;
1230 : }
1231 :
1232 745628 : tevent_req_received(req);
1233 745628 : return ret;
1234 : }
1235 :
1236 : struct tstream_smbXcli_np_disconnect_state {
1237 : struct tstream_context *stream;
1238 : struct tevent_req *subreq;
1239 : };
1240 :
1241 : static void tstream_smbXcli_np_disconnect_done(struct tevent_req *subreq);
1242 : static void tstream_smbXcli_np_disconnect_cleanup(struct tevent_req *req,
1243 : enum tevent_req_state req_state);
1244 :
1245 7872 : static struct tevent_req *tstream_smbXcli_np_disconnect_send(TALLOC_CTX *mem_ctx,
1246 : struct tevent_context *ev,
1247 : struct tstream_context *stream)
1248 : {
1249 7872 : struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
1250 : struct tstream_smbXcli_np);
1251 620 : struct tevent_req *req;
1252 620 : struct tstream_smbXcli_np_disconnect_state *state;
1253 620 : struct tevent_req *subreq;
1254 :
1255 7872 : req = tevent_req_create(mem_ctx, &state,
1256 : struct tstream_smbXcli_np_disconnect_state);
1257 7872 : if (req == NULL) {
1258 0 : return NULL;
1259 : }
1260 :
1261 7872 : state->stream = stream;
1262 :
1263 7872 : if (!smbXcli_conn_is_connected(cli_nps->conn)) {
1264 469 : tevent_req_error(req, ENOTCONN);
1265 469 : return tevent_req_post(req, ev);
1266 : }
1267 :
1268 7403 : if (cli_nps->is_smb1) {
1269 189 : subreq = smb1cli_close_send(state, ev, cli_nps->conn,
1270 : cli_nps->timeout,
1271 189 : cli_nps->pid,
1272 : cli_nps->tcon,
1273 : cli_nps->session,
1274 189 : cli_nps->fnum, UINT32_MAX);
1275 : } else {
1276 7214 : subreq = smb2cli_close_send(state, ev, cli_nps->conn,
1277 : cli_nps->timeout,
1278 : cli_nps->session,
1279 : cli_nps->tcon,
1280 : 0, /* flags */
1281 : cli_nps->fid_persistent,
1282 : cli_nps->fid_volatile);
1283 : }
1284 7403 : if (tevent_req_nomem(subreq, req)) {
1285 0 : return tevent_req_post(req, ev);
1286 : }
1287 7403 : tevent_req_set_callback(subreq, tstream_smbXcli_np_disconnect_done, req);
1288 7403 : state->subreq = subreq;
1289 :
1290 7403 : tevent_req_set_cleanup_fn(req, tstream_smbXcli_np_disconnect_cleanup);
1291 :
1292 : /*
1293 : * Make sure we don't send any requests anymore.
1294 : */
1295 7403 : cli_nps->conn = NULL;
1296 :
1297 7403 : return req;
1298 : }
1299 :
1300 31 : static void tstream_smbXcli_np_disconnect_done(struct tevent_req *subreq)
1301 : {
1302 31 : struct tevent_req *req = tevent_req_callback_data(subreq,
1303 : struct tevent_req);
1304 3 : struct tstream_smbXcli_np_disconnect_state *state =
1305 31 : tevent_req_data(req, struct tstream_smbXcli_np_disconnect_state);
1306 3 : struct tstream_smbXcli_np *cli_nps =
1307 31 : tstream_context_data(state->stream, struct tstream_smbXcli_np);
1308 3 : NTSTATUS status;
1309 :
1310 31 : state->subreq = NULL;
1311 :
1312 31 : if (cli_nps->is_smb1) {
1313 19 : status = smb1cli_close_recv(subreq);
1314 : } else {
1315 12 : status = smb2cli_close_recv(subreq);
1316 : }
1317 31 : TALLOC_FREE(subreq);
1318 31 : if (!NT_STATUS_IS_OK(status)) {
1319 19 : tevent_req_error(req, EPIPE);
1320 19 : return;
1321 : }
1322 :
1323 12 : cli_nps->conn = NULL;
1324 12 : cli_nps->session = NULL;
1325 12 : cli_nps->tcon = NULL;
1326 :
1327 12 : tevent_req_done(req);
1328 : }
1329 :
1330 : static void tstream_smbXcli_np_disconnect_free(struct tevent_req *subreq);
1331 :
1332 7434 : static void tstream_smbXcli_np_disconnect_cleanup(struct tevent_req *req,
1333 : enum tevent_req_state req_state)
1334 : {
1335 527 : struct tstream_smbXcli_np_disconnect_state *state =
1336 7434 : tevent_req_data(req, struct tstream_smbXcli_np_disconnect_state);
1337 7434 : struct tstream_smbXcli_np *cli_nps = NULL;
1338 :
1339 7434 : if (state->subreq == NULL) {
1340 56 : return;
1341 : }
1342 :
1343 7372 : cli_nps = tstream_context_data(state->stream, struct tstream_smbXcli_np);
1344 :
1345 7372 : if (cli_nps->tcon == NULL) {
1346 0 : return;
1347 : }
1348 :
1349 : /*
1350 : * We're no longer interested in the result
1351 : * any more, but need to make sure that the close
1352 : * request arrives at the server if the smb connection,
1353 : * session and tcon are still alive.
1354 : *
1355 : * We move the low level request to the tcon,
1356 : * which means that it stays as long as the tcon
1357 : * is available.
1358 : */
1359 7372 : talloc_steal(cli_nps->tcon, state->subreq);
1360 7372 : tevent_req_set_callback(state->subreq,
1361 : tstream_smbXcli_np_disconnect_free,
1362 : NULL);
1363 7372 : state->subreq = NULL;
1364 :
1365 7372 : cli_nps->conn = NULL;
1366 7372 : cli_nps->session = NULL;
1367 7372 : cli_nps->tcon = NULL;
1368 : }
1369 :
1370 347 : static void tstream_smbXcli_np_disconnect_free(struct tevent_req *subreq)
1371 : {
1372 347 : TALLOC_FREE(subreq);
1373 347 : }
1374 :
1375 31 : static int tstream_smbXcli_np_disconnect_recv(struct tevent_req *req,
1376 : int *perrno)
1377 : {
1378 3 : int ret;
1379 :
1380 31 : ret = tsocket_simple_int_recv(req, perrno);
1381 :
1382 31 : tevent_req_received(req);
1383 31 : return ret;
1384 : }
1385 :
1386 : static const struct tstream_context_ops tstream_smbXcli_np_ops = {
1387 : .name = "smbXcli_np",
1388 :
1389 : .pending_bytes = tstream_smbXcli_np_pending_bytes,
1390 :
1391 : .readv_send = tstream_smbXcli_np_readv_send,
1392 : .readv_recv = tstream_smbXcli_np_readv_recv,
1393 :
1394 : .writev_send = tstream_smbXcli_np_writev_send,
1395 : .writev_recv = tstream_smbXcli_np_writev_recv,
1396 :
1397 : .disconnect_send = tstream_smbXcli_np_disconnect_send,
1398 : .disconnect_recv = tstream_smbXcli_np_disconnect_recv,
1399 : };
|