2 Unix SMB/CIFS implementation.
4 Copyright (C) Stefan Metzmacher 2010
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.
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.
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/>.
21 #include "system/network.h"
22 #include "libsmb/libsmb.h"
23 #include "libsmb/smb2cli.h"
24 #include "../lib/util/tevent_ntstatus.h"
25 #include "../lib/tsocket/tsocket.h"
26 #include "../lib/tsocket/tsocket_internal.h"
27 #include "cli_np_tstream.h"
29 static const struct tstream_context_ops tstream_cli_np_ops
;
32 * Windows uses 4280 (the max xmit/recv size negotiated on DCERPC).
33 * This is fits into the max_xmit negotiated at the SMB layer.
35 * On the sending side they may use SMBtranss if the request does not
36 * fit into a single SMBtrans call.
38 * Windows uses 1024 as max data size of a SMBtrans request and then
39 * possibly reads the rest of the DCERPC fragment (up to 3256 bytes)
42 * For now we just ask for the full 4280 bytes (max data size) in the SMBtrans
43 * request to get the whole fragment at once (like samba 3.5.x and below did.
45 * It is important that we use do SMBwriteX with the size of a full fragment,
46 * otherwise we may get NT_STATUS_PIPE_BUSY on the SMBtrans request
47 * from NT4 servers. (See bug #8195)
49 #define TSTREAM_CLI_NP_MAX_BUF_SIZE 4280
51 struct tstream_cli_np
{
52 struct cli_state
*cli
;
56 uint64_t fid_persistent
;
57 uint64_t fid_volatile
;
58 unsigned int default_timeout
;
62 struct tevent_req
*read_req
;
63 struct tevent_req
*write_req
;
74 static int tstream_cli_np_destructor(struct tstream_cli_np
*cli_nps
)
78 if (!cli_state_is_connected(cli_nps
->cli
)) {
83 * TODO: do not use a sync call with a destructor!!!
85 * This only happens, if a caller does talloc_free(),
86 * while the everything was still ok.
88 * If we get an unexpected failure within a normal
89 * operation, we already do an async cli_close_send()/_recv().
91 * Once we've fixed all callers to call
92 * tstream_disconnect_send()/_recv(), this will
95 if (cli_nps
->is_smb1
) {
96 status
= cli_close(cli_nps
->cli
, cli_nps
->fnum
);
98 status
= smb2cli_close(cli_nps
->cli
->conn
,
99 cli_nps
->cli
->timeout
,
100 cli_nps
->cli
->smb2
.session
,
101 cli_nps
->cli
->smb2
.tid
, 0,
102 cli_nps
->fid_persistent
,
103 cli_nps
->fid_volatile
);
105 if (!NT_STATUS_IS_OK(status
)) {
106 DEBUG(1, ("tstream_cli_np_destructor: cli_close "
107 "failed on pipe %s. Error was %s\n",
108 cli_nps
->npipe
, nt_errstr(status
)));
111 * We can't do much on failure
116 struct tstream_cli_np_open_state
{
117 struct cli_state
*cli
;
120 uint64_t fid_persistent
;
121 uint64_t fid_volatile
;
125 static void tstream_cli_np_open_done(struct tevent_req
*subreq
);
127 struct tevent_req
*tstream_cli_np_open_send(TALLOC_CTX
*mem_ctx
,
128 struct tevent_context
*ev
,
129 struct cli_state
*cli
,
132 struct tevent_req
*req
;
133 struct tstream_cli_np_open_state
*state
;
134 struct tevent_req
*subreq
;
136 req
= tevent_req_create(mem_ctx
, &state
,
137 struct tstream_cli_np_open_state
);
143 state
->npipe
= talloc_strdup(state
, npipe
);
144 if (tevent_req_nomem(state
->npipe
, req
)) {
145 return tevent_req_post(req
, ev
);
148 if (cli_state_protocol(cli
) < PROTOCOL_SMB2_02
) {
149 state
->is_smb1
= true;
152 if (state
->is_smb1
) {
153 subreq
= cli_ntcreate_send(state
, ev
, cli
,
158 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
163 subreq
= smb2cli_create_send(state
, ev
, cli
->conn
,
164 cli
->timeout
, cli
->smb2
.session
,
167 SMB2_OPLOCK_LEVEL_NONE
,
168 SMB2_IMPERSONATION_IMPERSONATION
,
170 0, /* file_attributes */
171 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
173 0, /* create_options */
176 if (tevent_req_nomem(subreq
, req
)) {
177 return tevent_req_post(req
, ev
);
179 tevent_req_set_callback(subreq
, tstream_cli_np_open_done
, req
);
184 static void tstream_cli_np_open_done(struct tevent_req
*subreq
)
186 struct tevent_req
*req
=
187 tevent_req_callback_data(subreq
, struct tevent_req
);
188 struct tstream_cli_np_open_state
*state
=
189 tevent_req_data(req
, struct tstream_cli_np_open_state
);
192 if (state
->is_smb1
) {
193 status
= cli_ntcreate_recv(subreq
, &state
->fnum
);
195 status
= smb2cli_create_recv(subreq
,
196 &state
->fid_persistent
,
197 &state
->fid_volatile
);
200 if (!NT_STATUS_IS_OK(status
)) {
201 tevent_req_nterror(req
, status
);
205 tevent_req_done(req
);
208 NTSTATUS
_tstream_cli_np_open_recv(struct tevent_req
*req
,
210 struct tstream_context
**_stream
,
211 const char *location
)
213 struct tstream_cli_np_open_state
*state
=
214 tevent_req_data(req
, struct tstream_cli_np_open_state
);
215 struct tstream_context
*stream
;
216 struct tstream_cli_np
*cli_nps
;
219 if (tevent_req_is_nterror(req
, &status
)) {
220 tevent_req_received(req
);
224 stream
= tstream_context_create(mem_ctx
,
227 struct tstream_cli_np
,
230 tevent_req_received(req
);
231 return NT_STATUS_NO_MEMORY
;
233 ZERO_STRUCTP(cli_nps
);
235 cli_nps
->cli
= state
->cli
;
236 cli_nps
->npipe
= talloc_move(cli_nps
, &state
->npipe
);
237 cli_nps
->is_smb1
= state
->is_smb1
;
238 cli_nps
->fnum
= state
->fnum
;
239 cli_nps
->fid_persistent
= state
->fid_persistent
;
240 cli_nps
->fid_volatile
= state
->fid_volatile
;
241 cli_nps
->default_timeout
= cli_set_timeout(state
->cli
, 0);
242 cli_set_timeout(state
->cli
, cli_nps
->default_timeout
);
244 talloc_set_destructor(cli_nps
, tstream_cli_np_destructor
);
246 cli_nps
->trans
.active
= false;
247 cli_nps
->trans
.read_req
= NULL
;
248 cli_nps
->trans
.write_req
= NULL
;
249 SSVAL(cli_nps
->trans
.setup
+0, 0, TRANSACT_DCERPCCMD
);
250 SSVAL(cli_nps
->trans
.setup
+1, 0, cli_nps
->fnum
);
253 tevent_req_received(req
);
257 static ssize_t
tstream_cli_np_pending_bytes(struct tstream_context
*stream
)
259 struct tstream_cli_np
*cli_nps
= tstream_context_data(stream
,
260 struct tstream_cli_np
);
262 if (!cli_state_is_connected(cli_nps
->cli
)) {
267 return cli_nps
->read
.left
;
270 bool tstream_is_cli_np(struct tstream_context
*stream
)
272 struct tstream_cli_np
*cli_nps
=
273 talloc_get_type(_tstream_context_data(stream
),
274 struct tstream_cli_np
);
283 NTSTATUS
tstream_cli_np_use_trans(struct tstream_context
*stream
)
285 struct tstream_cli_np
*cli_nps
= tstream_context_data(stream
,
286 struct tstream_cli_np
);
288 if (cli_nps
->trans
.read_req
) {
289 return NT_STATUS_PIPE_BUSY
;
292 if (cli_nps
->trans
.write_req
) {
293 return NT_STATUS_PIPE_BUSY
;
296 if (cli_nps
->trans
.active
) {
297 return NT_STATUS_PIPE_BUSY
;
300 cli_nps
->trans
.active
= true;
305 unsigned int tstream_cli_np_set_timeout(struct tstream_context
*stream
,
306 unsigned int timeout
)
308 struct tstream_cli_np
*cli_nps
= tstream_context_data(stream
,
309 struct tstream_cli_np
);
311 if (!cli_state_is_connected(cli_nps
->cli
)) {
312 return cli_nps
->default_timeout
;
315 return cli_set_timeout(cli_nps
->cli
, timeout
);
318 struct cli_state
*tstream_cli_np_get_cli_state(struct tstream_context
*stream
)
320 struct tstream_cli_np
*cli_nps
= tstream_context_data(stream
,
321 struct tstream_cli_np
);
326 struct tstream_cli_np_writev_state
{
327 struct tstream_context
*stream
;
328 struct tevent_context
*ev
;
330 struct iovec
*vector
;
337 const char *location
;
341 static int tstream_cli_np_writev_state_destructor(struct tstream_cli_np_writev_state
*state
)
343 struct tstream_cli_np
*cli_nps
=
344 tstream_context_data(state
->stream
,
345 struct tstream_cli_np
);
347 cli_nps
->trans
.write_req
= NULL
;
352 static void tstream_cli_np_writev_write_next(struct tevent_req
*req
);
354 static struct tevent_req
*tstream_cli_np_writev_send(TALLOC_CTX
*mem_ctx
,
355 struct tevent_context
*ev
,
356 struct tstream_context
*stream
,
357 const struct iovec
*vector
,
360 struct tevent_req
*req
;
361 struct tstream_cli_np_writev_state
*state
;
362 struct tstream_cli_np
*cli_nps
= tstream_context_data(stream
,
363 struct tstream_cli_np
);
365 req
= tevent_req_create(mem_ctx
, &state
,
366 struct tstream_cli_np_writev_state
);
370 state
->stream
= stream
;
374 talloc_set_destructor(state
, tstream_cli_np_writev_state_destructor
);
376 if (!cli_state_is_connected(cli_nps
->cli
)) {
377 tevent_req_error(req
, ENOTCONN
);
378 return tevent_req_post(req
, ev
);
382 * we make a copy of the vector so we can change the structure
384 state
->vector
= talloc_array(state
, struct iovec
, count
);
385 if (tevent_req_nomem(state
->vector
, req
)) {
386 return tevent_req_post(req
, ev
);
388 memcpy(state
->vector
, vector
, sizeof(struct iovec
) * count
);
389 state
->count
= count
;
391 tstream_cli_np_writev_write_next(req
);
392 if (!tevent_req_is_in_progress(req
)) {
393 return tevent_req_post(req
, ev
);
399 static void tstream_cli_np_readv_trans_start(struct tevent_req
*req
);
400 static void tstream_cli_np_writev_write_done(struct tevent_req
*subreq
);
402 static void tstream_cli_np_writev_write_next(struct tevent_req
*req
)
404 struct tstream_cli_np_writev_state
*state
=
406 struct tstream_cli_np_writev_state
);
407 struct tstream_cli_np
*cli_nps
=
408 tstream_context_data(state
->stream
,
409 struct tstream_cli_np
);
410 struct tevent_req
*subreq
;
414 for (i
=0; i
< state
->count
; i
++) {
415 left
+= state
->vector
[i
].iov_len
;
419 TALLOC_FREE(cli_nps
->write
.buf
);
420 tevent_req_done(req
);
424 cli_nps
->write
.ofs
= 0;
425 cli_nps
->write
.left
= MIN(left
, TSTREAM_CLI_NP_MAX_BUF_SIZE
);
426 cli_nps
->write
.buf
= talloc_realloc(cli_nps
, cli_nps
->write
.buf
,
427 uint8_t, cli_nps
->write
.left
);
428 if (tevent_req_nomem(cli_nps
->write
.buf
, req
)) {
433 * copy the pending buffer first
435 while (cli_nps
->write
.left
> 0 && state
->count
> 0) {
436 uint8_t *base
= (uint8_t *)state
->vector
[0].iov_base
;
437 size_t len
= MIN(cli_nps
->write
.left
, state
->vector
[0].iov_len
);
439 memcpy(cli_nps
->write
.buf
+ cli_nps
->write
.ofs
, base
, len
);
442 state
->vector
[0].iov_base
= base
;
443 state
->vector
[0].iov_len
-= len
;
445 cli_nps
->write
.ofs
+= len
;
446 cli_nps
->write
.left
-= len
;
448 if (state
->vector
[0].iov_len
== 0) {
456 if (cli_nps
->trans
.active
&& state
->count
== 0) {
457 cli_nps
->trans
.active
= false;
458 cli_nps
->trans
.write_req
= req
;
462 if (cli_nps
->trans
.read_req
&& state
->count
== 0) {
463 cli_nps
->trans
.write_req
= req
;
464 tstream_cli_np_readv_trans_start(cli_nps
->trans
.read_req
);
468 if (cli_nps
->is_smb1
) {
469 subreq
= cli_write_andx_send(state
, state
->ev
, cli_nps
->cli
,
471 8, /* 8 means message mode. */
474 cli_nps
->write
.ofs
); /* size */
476 subreq
= smb2cli_write_send(state
, state
->ev
,
478 cli_nps
->cli
->timeout
,
479 cli_nps
->cli
->smb2
.session
,
480 cli_nps
->cli
->smb2
.tid
,
481 cli_nps
->write
.ofs
, /* length */
483 cli_nps
->fid_persistent
,
484 cli_nps
->fid_volatile
,
485 0, /* remaining_bytes */
489 if (tevent_req_nomem(subreq
, req
)) {
492 tevent_req_set_callback(subreq
,
493 tstream_cli_np_writev_write_done
,
497 static void tstream_cli_np_writev_disconnect_now(struct tevent_req
*req
,
499 const char *location
);
501 static void tstream_cli_np_writev_write_done(struct tevent_req
*subreq
)
503 struct tevent_req
*req
=
504 tevent_req_callback_data(subreq
, struct tevent_req
);
505 struct tstream_cli_np_writev_state
*state
=
506 tevent_req_data(req
, struct tstream_cli_np_writev_state
);
507 struct tstream_cli_np
*cli_nps
=
508 tstream_context_data(state
->stream
,
509 struct tstream_cli_np
);
513 if (cli_nps
->is_smb1
) {
514 status
= cli_write_andx_recv(subreq
, &written
);
516 status
= smb2cli_write_recv(subreq
);
517 written
= cli_nps
->write
.ofs
; // TODO: get the value from the server
520 if (!NT_STATUS_IS_OK(status
)) {
521 tstream_cli_np_writev_disconnect_now(req
, EIO
, __location__
);
525 if (written
!= cli_nps
->write
.ofs
) {
526 tstream_cli_np_writev_disconnect_now(req
, EIO
, __location__
);
530 tstream_cli_np_writev_write_next(req
);
533 static void tstream_cli_np_writev_disconnect_done(struct tevent_req
*subreq
);
535 static void tstream_cli_np_writev_disconnect_now(struct tevent_req
*req
,
537 const char *location
)
539 struct tstream_cli_np_writev_state
*state
=
541 struct tstream_cli_np_writev_state
);
542 struct tstream_cli_np
*cli_nps
=
543 tstream_context_data(state
->stream
,
544 struct tstream_cli_np
);
545 struct tevent_req
*subreq
;
547 state
->error
.val
= error
;
548 state
->error
.location
= location
;
550 if (!cli_state_is_connected(cli_nps
->cli
)) {
551 /* return the original error */
552 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
556 if (cli_nps
->is_smb1
) {
557 subreq
= cli_close_send(state
, state
->ev
, cli_nps
->cli
,
560 subreq
= smb2cli_close_send(state
, state
->ev
,
562 cli_nps
->cli
->timeout
,
563 cli_nps
->cli
->smb2
.session
,
564 cli_nps
->cli
->smb2
.tid
,
566 cli_nps
->fid_persistent
,
567 cli_nps
->fid_volatile
);
569 if (subreq
== NULL
) {
570 /* return the original error */
571 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
574 tevent_req_set_callback(subreq
,
575 tstream_cli_np_writev_disconnect_done
,
579 static void tstream_cli_np_writev_disconnect_done(struct tevent_req
*subreq
)
581 struct tevent_req
*req
=
582 tevent_req_callback_data(subreq
, struct tevent_req
);
583 struct tstream_cli_np_writev_state
*state
=
584 tevent_req_data(req
, struct tstream_cli_np_writev_state
);
585 struct tstream_cli_np
*cli_nps
=
586 tstream_context_data(state
->stream
, struct tstream_cli_np
);
588 if (cli_nps
->is_smb1
) {
589 cli_close_recv(subreq
);
591 smb2cli_close_recv(subreq
);
597 /* return the original error */
598 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
601 static int tstream_cli_np_writev_recv(struct tevent_req
*req
,
604 struct tstream_cli_np_writev_state
*state
=
606 struct tstream_cli_np_writev_state
);
609 ret
= tsocket_simple_int_recv(req
, perrno
);
614 tevent_req_received(req
);
618 struct tstream_cli_np_readv_state
{
619 struct tstream_context
*stream
;
620 struct tevent_context
*ev
;
622 struct iovec
*vector
;
628 struct tevent_immediate
*im
;
633 const char *location
;
637 static int tstream_cli_np_readv_state_destructor(struct tstream_cli_np_readv_state
*state
)
639 struct tstream_cli_np
*cli_nps
=
640 tstream_context_data(state
->stream
,
641 struct tstream_cli_np
);
643 cli_nps
->trans
.read_req
= NULL
;
648 static void tstream_cli_np_readv_read_next(struct tevent_req
*req
);
650 static struct tevent_req
*tstream_cli_np_readv_send(TALLOC_CTX
*mem_ctx
,
651 struct tevent_context
*ev
,
652 struct tstream_context
*stream
,
653 struct iovec
*vector
,
656 struct tevent_req
*req
;
657 struct tstream_cli_np_readv_state
*state
;
658 struct tstream_cli_np
*cli_nps
=
659 tstream_context_data(stream
, struct tstream_cli_np
);
661 req
= tevent_req_create(mem_ctx
, &state
,
662 struct tstream_cli_np_readv_state
);
666 state
->stream
= stream
;
670 talloc_set_destructor(state
, tstream_cli_np_readv_state_destructor
);
672 if (!cli_state_is_connected(cli_nps
->cli
)) {
673 tevent_req_error(req
, ENOTCONN
);
674 return tevent_req_post(req
, ev
);
678 * we make a copy of the vector so we can change the structure
680 state
->vector
= talloc_array(state
, struct iovec
, count
);
681 if (tevent_req_nomem(state
->vector
, req
)) {
682 return tevent_req_post(req
, ev
);
684 memcpy(state
->vector
, vector
, sizeof(struct iovec
) * count
);
685 state
->count
= count
;
687 tstream_cli_np_readv_read_next(req
);
688 if (!tevent_req_is_in_progress(req
)) {
689 return tevent_req_post(req
, ev
);
695 static void tstream_cli_np_readv_read_done(struct tevent_req
*subreq
);
697 static void tstream_cli_np_readv_read_next(struct tevent_req
*req
)
699 struct tstream_cli_np_readv_state
*state
=
701 struct tstream_cli_np_readv_state
);
702 struct tstream_cli_np
*cli_nps
=
703 tstream_context_data(state
->stream
,
704 struct tstream_cli_np
);
705 struct tevent_req
*subreq
;
708 * copy the pending buffer first
710 while (cli_nps
->read
.left
> 0 && state
->count
> 0) {
711 uint8_t *base
= (uint8_t *)state
->vector
[0].iov_base
;
712 size_t len
= MIN(cli_nps
->read
.left
, state
->vector
[0].iov_len
);
714 memcpy(base
, cli_nps
->read
.buf
+ cli_nps
->read
.ofs
, len
);
717 state
->vector
[0].iov_base
= base
;
718 state
->vector
[0].iov_len
-= len
;
720 cli_nps
->read
.ofs
+= len
;
721 cli_nps
->read
.left
-= len
;
723 if (state
->vector
[0].iov_len
== 0) {
731 if (cli_nps
->read
.left
== 0) {
732 TALLOC_FREE(cli_nps
->read
.buf
);
735 if (state
->count
== 0) {
736 tevent_req_done(req
);
740 if (cli_nps
->trans
.active
) {
741 cli_nps
->trans
.active
= false;
742 cli_nps
->trans
.read_req
= req
;
746 if (cli_nps
->trans
.write_req
) {
747 cli_nps
->trans
.read_req
= req
;
748 tstream_cli_np_readv_trans_start(req
);
752 if (cli_nps
->is_smb1
) {
753 subreq
= cli_read_andx_send(state
, state
->ev
, cli_nps
->cli
,
756 TSTREAM_CLI_NP_MAX_BUF_SIZE
);
758 subreq
= smb2cli_read_send(state
, state
->ev
,
760 cli_nps
->cli
->timeout
,
761 cli_nps
->cli
->smb2
.session
,
762 cli_nps
->cli
->smb2
.tid
,
763 TSTREAM_CLI_NP_MAX_BUF_SIZE
, /* length */
765 cli_nps
->fid_persistent
,
766 cli_nps
->fid_volatile
,
767 0, /* minimum_count */
768 0); /* remaining_bytes */
770 if (tevent_req_nomem(subreq
, req
)) {
773 tevent_req_set_callback(subreq
,
774 tstream_cli_np_readv_read_done
,
778 static void tstream_cli_np_readv_trans_done(struct tevent_req
*subreq
);
780 static void tstream_cli_np_readv_trans_start(struct tevent_req
*req
)
782 struct tstream_cli_np_readv_state
*state
=
784 struct tstream_cli_np_readv_state
);
785 struct tstream_cli_np
*cli_nps
=
786 tstream_context_data(state
->stream
,
787 struct tstream_cli_np
);
788 struct tevent_req
*subreq
;
790 state
->trans
.im
= tevent_create_immediate(state
);
791 if (tevent_req_nomem(state
->trans
.im
, req
)) {
795 if (cli_nps
->is_smb1
) {
796 subreq
= cli_trans_send(state
, state
->ev
,
801 cli_nps
->trans
.setup
, 2,
806 TSTREAM_CLI_NP_MAX_BUF_SIZE
);
808 DATA_BLOB in_input_buffer
= data_blob_null
;
809 DATA_BLOB in_output_buffer
= data_blob_null
;
811 in_input_buffer
= data_blob_const(cli_nps
->write
.buf
,
814 subreq
= smb2cli_ioctl_send(state
, state
->ev
,
816 cli_nps
->cli
->timeout
,
817 cli_nps
->cli
->smb2
.session
,
818 cli_nps
->cli
->smb2
.tid
,
819 cli_nps
->fid_persistent
,
820 cli_nps
->fid_volatile
,
821 FSCTL_NAMED_PIPE_READ_WRITE
,
822 0, /* in_max_input_length */
824 /* in_max_output_length */
825 TSTREAM_CLI_NP_MAX_BUF_SIZE
,
827 SMB2_IOCTL_FLAG_IS_FSCTL
);
829 if (tevent_req_nomem(subreq
, req
)) {
832 tevent_req_set_callback(subreq
,
833 tstream_cli_np_readv_trans_done
,
837 static void tstream_cli_np_readv_disconnect_now(struct tevent_req
*req
,
839 const char *location
);
840 static void tstream_cli_np_readv_trans_next(struct tevent_context
*ctx
,
841 struct tevent_immediate
*im
,
844 static void tstream_cli_np_readv_trans_done(struct tevent_req
*subreq
)
846 struct tevent_req
*req
=
847 tevent_req_callback_data(subreq
, struct tevent_req
);
848 struct tstream_cli_np_readv_state
*state
=
849 tevent_req_data(req
, struct tstream_cli_np_readv_state
);
850 struct tstream_cli_np
*cli_nps
=
851 tstream_context_data(state
->stream
, struct tstream_cli_np
);
856 if (cli_nps
->is_smb1
) {
857 status
= cli_trans_recv(subreq
, state
, NULL
, NULL
, 0, NULL
,
859 &rcvbuf
, 0, &received
);
861 DATA_BLOB out_input_buffer
= data_blob_null
;
862 DATA_BLOB out_output_buffer
= data_blob_null
;
864 status
= smb2cli_ioctl_recv(subreq
, state
,
868 /* Note that rcvbuf is not a talloc pointer here */
869 rcvbuf
= out_output_buffer
.data
;
870 received
= out_output_buffer
.length
;
873 if (NT_STATUS_EQUAL(status
, NT_STATUS_BUFFER_TOO_SMALL
)) {
874 status
= NT_STATUS_OK
;
876 if (!NT_STATUS_IS_OK(status
)) {
877 tstream_cli_np_readv_disconnect_now(req
, EIO
, __location__
);
881 if (received
> TSTREAM_CLI_NP_MAX_BUF_SIZE
) {
882 tstream_cli_np_readv_disconnect_now(req
, EIO
, __location__
);
887 tstream_cli_np_readv_disconnect_now(req
, EPIPE
, __location__
);
891 cli_nps
->read
.ofs
= 0;
892 cli_nps
->read
.left
= received
;
893 cli_nps
->read
.buf
= talloc_array(cli_nps
, uint8_t, received
);
894 if (cli_nps
->read
.buf
== NULL
) {
896 tevent_req_nomem(cli_nps
->read
.buf
, req
);
899 memcpy(cli_nps
->read
.buf
, rcvbuf
, received
);
901 if (cli_nps
->trans
.write_req
== NULL
) {
902 tstream_cli_np_readv_read_next(req
);
906 tevent_schedule_immediate(state
->trans
.im
, state
->ev
,
907 tstream_cli_np_readv_trans_next
, req
);
909 tevent_req_done(cli_nps
->trans
.write_req
);
912 static void tstream_cli_np_readv_trans_next(struct tevent_context
*ctx
,
913 struct tevent_immediate
*im
,
916 struct tevent_req
*req
=
917 talloc_get_type_abort(private_data
,
920 tstream_cli_np_readv_read_next(req
);
923 static void tstream_cli_np_readv_read_done(struct tevent_req
*subreq
)
925 struct tevent_req
*req
=
926 tevent_req_callback_data(subreq
, struct tevent_req
);
927 struct tstream_cli_np_readv_state
*state
=
928 tevent_req_data(req
, struct tstream_cli_np_readv_state
);
929 struct tstream_cli_np
*cli_nps
=
930 tstream_context_data(state
->stream
, struct tstream_cli_np
);
936 * We must free subreq in this function as there is
937 * a timer event attached to it.
940 if (cli_nps
->is_smb1
) {
941 status
= cli_read_andx_recv(subreq
, &received
, &rcvbuf
);
943 uint32_t data_length
= 0;
944 status
= smb2cli_read_recv(subreq
, state
, &rcvbuf
, &data_length
);
945 received
= data_length
;
948 * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
951 if (NT_STATUS_EQUAL(status
, NT_STATUS_BUFFER_TOO_SMALL
)) {
953 * NT_STATUS_BUFFER_TOO_SMALL means that there's
954 * more data to read when the named pipe is used
955 * in message mode (which is the case here).
957 * But we hide this from the caller.
959 status
= NT_STATUS_OK
;
961 if (!NT_STATUS_IS_OK(status
)) {
963 tstream_cli_np_readv_disconnect_now(req
, EIO
, __location__
);
967 if (received
> TSTREAM_CLI_NP_MAX_BUF_SIZE
) {
969 tstream_cli_np_readv_disconnect_now(req
, EIO
, __location__
);
975 tstream_cli_np_readv_disconnect_now(req
, EPIPE
, __location__
);
979 cli_nps
->read
.ofs
= 0;
980 cli_nps
->read
.left
= received
;
981 cli_nps
->read
.buf
= talloc_array(cli_nps
, uint8_t, received
);
982 if (cli_nps
->read
.buf
== NULL
) {
984 tevent_req_nomem(cli_nps
->read
.buf
, req
);
987 memcpy(cli_nps
->read
.buf
, rcvbuf
, received
);
990 tstream_cli_np_readv_read_next(req
);
993 static void tstream_cli_np_readv_disconnect_done(struct tevent_req
*subreq
);
995 static void tstream_cli_np_readv_error(struct tevent_req
*req
);
997 static void tstream_cli_np_readv_disconnect_now(struct tevent_req
*req
,
999 const char *location
)
1001 struct tstream_cli_np_readv_state
*state
=
1002 tevent_req_data(req
,
1003 struct tstream_cli_np_readv_state
);
1004 struct tstream_cli_np
*cli_nps
=
1005 tstream_context_data(state
->stream
,
1006 struct tstream_cli_np
);
1007 struct tevent_req
*subreq
;
1009 state
->error
.val
= error
;
1010 state
->error
.location
= location
;
1012 if (!cli_state_is_connected(cli_nps
->cli
)) {
1013 /* return the original error */
1014 tstream_cli_np_readv_error(req
);
1018 if (cli_nps
->is_smb1
) {
1019 subreq
= cli_close_send(state
, state
->ev
, cli_nps
->cli
,
1022 subreq
= smb2cli_close_send(state
, state
->ev
,
1024 cli_nps
->cli
->timeout
,
1025 cli_nps
->cli
->smb2
.session
,
1026 cli_nps
->cli
->smb2
.tid
,
1028 cli_nps
->fid_persistent
,
1029 cli_nps
->fid_volatile
);
1031 if (subreq
== NULL
) {
1032 /* return the original error */
1033 tstream_cli_np_readv_error(req
);
1036 tevent_req_set_callback(subreq
,
1037 tstream_cli_np_readv_disconnect_done
,
1041 static void tstream_cli_np_readv_disconnect_done(struct tevent_req
*subreq
)
1043 struct tevent_req
*req
=
1044 tevent_req_callback_data(subreq
, struct tevent_req
);
1045 struct tstream_cli_np_readv_state
*state
=
1046 tevent_req_data(req
, struct tstream_cli_np_readv_state
);
1047 struct tstream_cli_np
*cli_nps
=
1048 tstream_context_data(state
->stream
, struct tstream_cli_np
);
1050 if (cli_nps
->is_smb1
) {
1051 cli_close_recv(subreq
);
1053 smb2cli_close_recv(subreq
);
1055 TALLOC_FREE(subreq
);
1057 cli_nps
->cli
= NULL
;
1059 tstream_cli_np_readv_error(req
);
1062 static void tstream_cli_np_readv_error_trigger(struct tevent_context
*ctx
,
1063 struct tevent_immediate
*im
,
1064 void *private_data
);
1066 static void tstream_cli_np_readv_error(struct tevent_req
*req
)
1068 struct tstream_cli_np_readv_state
*state
=
1069 tevent_req_data(req
,
1070 struct tstream_cli_np_readv_state
);
1071 struct tstream_cli_np
*cli_nps
=
1072 tstream_context_data(state
->stream
,
1073 struct tstream_cli_np
);
1075 if (cli_nps
->trans
.write_req
== NULL
) {
1076 /* return the original error */
1077 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
1081 if (state
->trans
.im
== NULL
) {
1082 /* return the original error */
1083 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
1087 tevent_schedule_immediate(state
->trans
.im
, state
->ev
,
1088 tstream_cli_np_readv_error_trigger
, req
);
1090 /* return the original error for writev */
1091 _tevent_req_error(cli_nps
->trans
.write_req
,
1092 state
->error
.val
, state
->error
.location
);
1095 static void tstream_cli_np_readv_error_trigger(struct tevent_context
*ctx
,
1096 struct tevent_immediate
*im
,
1099 struct tevent_req
*req
=
1100 talloc_get_type_abort(private_data
,
1102 struct tstream_cli_np_readv_state
*state
=
1103 tevent_req_data(req
,
1104 struct tstream_cli_np_readv_state
);
1106 /* return the original error */
1107 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
1110 static int tstream_cli_np_readv_recv(struct tevent_req
*req
,
1113 struct tstream_cli_np_readv_state
*state
=
1114 tevent_req_data(req
, struct tstream_cli_np_readv_state
);
1117 ret
= tsocket_simple_int_recv(req
, perrno
);
1122 tevent_req_received(req
);
1126 struct tstream_cli_np_disconnect_state
{
1127 struct tstream_context
*stream
;
1130 static void tstream_cli_np_disconnect_done(struct tevent_req
*subreq
);
1132 static struct tevent_req
*tstream_cli_np_disconnect_send(TALLOC_CTX
*mem_ctx
,
1133 struct tevent_context
*ev
,
1134 struct tstream_context
*stream
)
1136 struct tstream_cli_np
*cli_nps
= tstream_context_data(stream
,
1137 struct tstream_cli_np
);
1138 struct tevent_req
*req
;
1139 struct tstream_cli_np_disconnect_state
*state
;
1140 struct tevent_req
*subreq
;
1142 req
= tevent_req_create(mem_ctx
, &state
,
1143 struct tstream_cli_np_disconnect_state
);
1148 state
->stream
= stream
;
1150 if (!cli_state_is_connected(cli_nps
->cli
)) {
1151 tevent_req_error(req
, ENOTCONN
);
1152 return tevent_req_post(req
, ev
);
1155 if (cli_nps
->is_smb1
) {
1156 subreq
= cli_close_send(state
, ev
, cli_nps
->cli
,
1159 subreq
= smb2cli_close_send(state
, ev
, cli_nps
->cli
->conn
,
1160 cli_nps
->cli
->timeout
,
1161 cli_nps
->cli
->smb2
.session
,
1162 cli_nps
->cli
->smb2
.tid
,
1164 cli_nps
->fid_persistent
,
1165 cli_nps
->fid_volatile
);
1167 if (tevent_req_nomem(subreq
, req
)) {
1168 return tevent_req_post(req
, ev
);
1170 tevent_req_set_callback(subreq
, tstream_cli_np_disconnect_done
, req
);
1175 static void tstream_cli_np_disconnect_done(struct tevent_req
*subreq
)
1177 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
1179 struct tstream_cli_np_disconnect_state
*state
=
1180 tevent_req_data(req
, struct tstream_cli_np_disconnect_state
);
1181 struct tstream_cli_np
*cli_nps
=
1182 tstream_context_data(state
->stream
, struct tstream_cli_np
);
1185 if (cli_nps
->is_smb1
) {
1186 status
= cli_close_recv(subreq
);
1188 status
= smb2cli_close_recv(subreq
);
1190 TALLOC_FREE(subreq
);
1191 if (!NT_STATUS_IS_OK(status
)) {
1192 tevent_req_error(req
, EIO
);
1196 cli_nps
->cli
= NULL
;
1198 tevent_req_done(req
);
1201 static int tstream_cli_np_disconnect_recv(struct tevent_req
*req
,
1206 ret
= tsocket_simple_int_recv(req
, perrno
);
1208 tevent_req_received(req
);
1212 static const struct tstream_context_ops tstream_cli_np_ops
= {
1215 .pending_bytes
= tstream_cli_np_pending_bytes
,
1217 .readv_send
= tstream_cli_np_readv_send
,
1218 .readv_recv
= tstream_cli_np_readv_recv
,
1220 .writev_send
= tstream_cli_np_writev_send
,
1221 .writev_recv
= tstream_cli_np_writev_recv
,
1223 .disconnect_send
= tstream_cli_np_disconnect_send
,
1224 .disconnect_recv
= tstream_cli_np_disconnect_recv
,