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 "../libcli/smb/smbXcli_base.h"
25 #include "../lib/util/tevent_ntstatus.h"
26 #include "../lib/tsocket/tsocket.h"
27 #include "../lib/tsocket/tsocket_internal.h"
28 #include "cli_np_tstream.h"
30 static const struct tstream_context_ops tstream_cli_np_ops
;
33 * Windows uses 4280 (the max xmit/recv size negotiated on DCERPC).
34 * This is fits into the max_xmit negotiated at the SMB layer.
36 * On the sending side they may use SMBtranss if the request does not
37 * fit into a single SMBtrans call.
39 * Windows uses 1024 as max data size of a SMBtrans request and then
40 * possibly reads the rest of the DCERPC fragment (up to 3256 bytes)
43 * For now we just ask for the full 4280 bytes (max data size) in the SMBtrans
44 * request to get the whole fragment at once (like samba 3.5.x and below did.
46 * It is important that we use do SMBwriteX with the size of a full fragment,
47 * otherwise we may get NT_STATUS_PIPE_BUSY on the SMBtrans request
48 * from NT4 servers. (See bug #8195)
50 #define TSTREAM_CLI_NP_MAX_BUF_SIZE 4280
52 struct tstream_cli_np
{
53 struct cli_state
*cli
;
57 uint64_t fid_persistent
;
58 uint64_t fid_volatile
;
59 unsigned int default_timeout
;
63 struct tevent_req
*read_req
;
64 struct tevent_req
*write_req
;
75 static int tstream_cli_np_destructor(struct tstream_cli_np
*cli_nps
)
79 if (!cli_state_is_connected(cli_nps
->cli
)) {
84 * TODO: do not use a sync call with a destructor!!!
86 * This only happens, if a caller does talloc_free(),
87 * while the everything was still ok.
89 * If we get an unexpected failure within a normal
90 * operation, we already do an async cli_close_send()/_recv().
92 * Once we've fixed all callers to call
93 * tstream_disconnect_send()/_recv(), this will
96 if (cli_nps
->is_smb1
) {
97 status
= cli_close(cli_nps
->cli
, cli_nps
->fnum
);
99 status
= smb2cli_close(cli_nps
->cli
->conn
,
100 cli_nps
->cli
->timeout
,
101 cli_nps
->cli
->smb2
.session
,
102 cli_nps
->cli
->smb2
.tcon
,
104 cli_nps
->fid_persistent
,
105 cli_nps
->fid_volatile
);
107 if (!NT_STATUS_IS_OK(status
)) {
108 DEBUG(1, ("tstream_cli_np_destructor: cli_close "
109 "failed on pipe %s. Error was %s\n",
110 cli_nps
->npipe
, nt_errstr(status
)));
113 * We can't do much on failure
118 struct tstream_cli_np_open_state
{
119 struct cli_state
*cli
;
122 uint64_t fid_persistent
;
123 uint64_t fid_volatile
;
127 static void tstream_cli_np_open_done(struct tevent_req
*subreq
);
129 struct tevent_req
*tstream_cli_np_open_send(TALLOC_CTX
*mem_ctx
,
130 struct tevent_context
*ev
,
131 struct cli_state
*cli
,
134 struct tevent_req
*req
;
135 struct tstream_cli_np_open_state
*state
;
136 struct tevent_req
*subreq
;
138 req
= tevent_req_create(mem_ctx
, &state
,
139 struct tstream_cli_np_open_state
);
145 state
->npipe
= talloc_strdup(state
, npipe
);
146 if (tevent_req_nomem(state
->npipe
, req
)) {
147 return tevent_req_post(req
, ev
);
150 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
151 state
->is_smb1
= true;
154 if (state
->is_smb1
) {
155 const char *smb1_npipe
;
158 * Windows and newer Samba versions allow
159 * the pipe name without leading backslash,
160 * but we should better behave like windows clients
162 smb1_npipe
= talloc_asprintf(state
, "\\%s", state
->npipe
);
163 if (tevent_req_nomem(smb1_npipe
, req
)) {
164 return tevent_req_post(req
, ev
);
167 subreq
= cli_ntcreate_send(state
, ev
, cli
,
172 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
177 subreq
= smb2cli_create_send(state
, ev
, cli
->conn
,
178 cli
->timeout
, cli
->smb2
.session
,
181 SMB2_OPLOCK_LEVEL_NONE
,
182 SMB2_IMPERSONATION_IMPERSONATION
,
184 0, /* file_attributes */
185 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
187 0, /* create_options */
190 if (tevent_req_nomem(subreq
, req
)) {
191 return tevent_req_post(req
, ev
);
193 tevent_req_set_callback(subreq
, tstream_cli_np_open_done
, req
);
198 static void tstream_cli_np_open_done(struct tevent_req
*subreq
)
200 struct tevent_req
*req
=
201 tevent_req_callback_data(subreq
, struct tevent_req
);
202 struct tstream_cli_np_open_state
*state
=
203 tevent_req_data(req
, struct tstream_cli_np_open_state
);
206 if (state
->is_smb1
) {
207 status
= cli_ntcreate_recv(subreq
, &state
->fnum
);
209 status
= smb2cli_create_recv(subreq
,
210 &state
->fid_persistent
,
211 &state
->fid_volatile
,
215 if (!NT_STATUS_IS_OK(status
)) {
216 tevent_req_nterror(req
, status
);
220 tevent_req_done(req
);
223 NTSTATUS
_tstream_cli_np_open_recv(struct tevent_req
*req
,
225 struct tstream_context
**_stream
,
226 const char *location
)
228 struct tstream_cli_np_open_state
*state
=
229 tevent_req_data(req
, struct tstream_cli_np_open_state
);
230 struct tstream_context
*stream
;
231 struct tstream_cli_np
*cli_nps
;
234 if (tevent_req_is_nterror(req
, &status
)) {
235 tevent_req_received(req
);
239 stream
= tstream_context_create(mem_ctx
,
242 struct tstream_cli_np
,
245 tevent_req_received(req
);
246 return NT_STATUS_NO_MEMORY
;
248 ZERO_STRUCTP(cli_nps
);
250 cli_nps
->cli
= state
->cli
;
251 cli_nps
->npipe
= talloc_move(cli_nps
, &state
->npipe
);
252 cli_nps
->is_smb1
= state
->is_smb1
;
253 cli_nps
->fnum
= state
->fnum
;
254 cli_nps
->fid_persistent
= state
->fid_persistent
;
255 cli_nps
->fid_volatile
= state
->fid_volatile
;
256 cli_nps
->default_timeout
= cli_set_timeout(state
->cli
, 0);
257 cli_set_timeout(state
->cli
, cli_nps
->default_timeout
);
259 talloc_set_destructor(cli_nps
, tstream_cli_np_destructor
);
261 cli_nps
->trans
.active
= false;
262 cli_nps
->trans
.read_req
= NULL
;
263 cli_nps
->trans
.write_req
= NULL
;
264 SSVAL(cli_nps
->trans
.setup
+0, 0, TRANSACT_DCERPCCMD
);
265 SSVAL(cli_nps
->trans
.setup
+1, 0, cli_nps
->fnum
);
268 tevent_req_received(req
);
272 static ssize_t
tstream_cli_np_pending_bytes(struct tstream_context
*stream
)
274 struct tstream_cli_np
*cli_nps
= tstream_context_data(stream
,
275 struct tstream_cli_np
);
277 if (!cli_state_is_connected(cli_nps
->cli
)) {
282 return cli_nps
->read
.left
;
285 bool tstream_is_cli_np(struct tstream_context
*stream
)
287 struct tstream_cli_np
*cli_nps
=
288 talloc_get_type(_tstream_context_data(stream
),
289 struct tstream_cli_np
);
298 NTSTATUS
tstream_cli_np_use_trans(struct tstream_context
*stream
)
300 struct tstream_cli_np
*cli_nps
= tstream_context_data(stream
,
301 struct tstream_cli_np
);
303 if (cli_nps
->trans
.read_req
) {
304 return NT_STATUS_PIPE_BUSY
;
307 if (cli_nps
->trans
.write_req
) {
308 return NT_STATUS_PIPE_BUSY
;
311 if (cli_nps
->trans
.active
) {
312 return NT_STATUS_PIPE_BUSY
;
315 cli_nps
->trans
.active
= true;
320 unsigned int tstream_cli_np_set_timeout(struct tstream_context
*stream
,
321 unsigned int timeout
)
323 struct tstream_cli_np
*cli_nps
= tstream_context_data(stream
,
324 struct tstream_cli_np
);
326 if (!cli_state_is_connected(cli_nps
->cli
)) {
327 return cli_nps
->default_timeout
;
330 return cli_set_timeout(cli_nps
->cli
, timeout
);
333 struct cli_state
*tstream_cli_np_get_cli_state(struct tstream_context
*stream
)
335 struct tstream_cli_np
*cli_nps
= tstream_context_data(stream
,
336 struct tstream_cli_np
);
341 struct tstream_cli_np_writev_state
{
342 struct tstream_context
*stream
;
343 struct tevent_context
*ev
;
345 struct iovec
*vector
;
352 const char *location
;
356 static int tstream_cli_np_writev_state_destructor(struct tstream_cli_np_writev_state
*state
)
358 struct tstream_cli_np
*cli_nps
=
359 tstream_context_data(state
->stream
,
360 struct tstream_cli_np
);
362 cli_nps
->trans
.write_req
= NULL
;
367 static void tstream_cli_np_writev_write_next(struct tevent_req
*req
);
369 static struct tevent_req
*tstream_cli_np_writev_send(TALLOC_CTX
*mem_ctx
,
370 struct tevent_context
*ev
,
371 struct tstream_context
*stream
,
372 const struct iovec
*vector
,
375 struct tevent_req
*req
;
376 struct tstream_cli_np_writev_state
*state
;
377 struct tstream_cli_np
*cli_nps
= tstream_context_data(stream
,
378 struct tstream_cli_np
);
380 req
= tevent_req_create(mem_ctx
, &state
,
381 struct tstream_cli_np_writev_state
);
385 state
->stream
= stream
;
389 talloc_set_destructor(state
, tstream_cli_np_writev_state_destructor
);
391 if (!cli_state_is_connected(cli_nps
->cli
)) {
392 tevent_req_error(req
, ENOTCONN
);
393 return tevent_req_post(req
, ev
);
397 * we make a copy of the vector so we can change the structure
399 state
->vector
= talloc_array(state
, struct iovec
, count
);
400 if (tevent_req_nomem(state
->vector
, req
)) {
401 return tevent_req_post(req
, ev
);
403 memcpy(state
->vector
, vector
, sizeof(struct iovec
) * count
);
404 state
->count
= count
;
406 tstream_cli_np_writev_write_next(req
);
407 if (!tevent_req_is_in_progress(req
)) {
408 return tevent_req_post(req
, ev
);
414 static void tstream_cli_np_readv_trans_start(struct tevent_req
*req
);
415 static void tstream_cli_np_writev_write_done(struct tevent_req
*subreq
);
417 static void tstream_cli_np_writev_write_next(struct tevent_req
*req
)
419 struct tstream_cli_np_writev_state
*state
=
421 struct tstream_cli_np_writev_state
);
422 struct tstream_cli_np
*cli_nps
=
423 tstream_context_data(state
->stream
,
424 struct tstream_cli_np
);
425 struct tevent_req
*subreq
;
429 for (i
=0; i
< state
->count
; i
++) {
430 left
+= state
->vector
[i
].iov_len
;
434 TALLOC_FREE(cli_nps
->write
.buf
);
435 tevent_req_done(req
);
439 cli_nps
->write
.ofs
= 0;
440 cli_nps
->write
.left
= MIN(left
, TSTREAM_CLI_NP_MAX_BUF_SIZE
);
441 cli_nps
->write
.buf
= talloc_realloc(cli_nps
, cli_nps
->write
.buf
,
442 uint8_t, cli_nps
->write
.left
);
443 if (tevent_req_nomem(cli_nps
->write
.buf
, req
)) {
448 * copy the pending buffer first
450 while (cli_nps
->write
.left
> 0 && state
->count
> 0) {
451 uint8_t *base
= (uint8_t *)state
->vector
[0].iov_base
;
452 size_t len
= MIN(cli_nps
->write
.left
, state
->vector
[0].iov_len
);
454 memcpy(cli_nps
->write
.buf
+ cli_nps
->write
.ofs
, base
, len
);
457 state
->vector
[0].iov_base
= base
;
458 state
->vector
[0].iov_len
-= len
;
460 cli_nps
->write
.ofs
+= len
;
461 cli_nps
->write
.left
-= len
;
463 if (state
->vector
[0].iov_len
== 0) {
471 if (cli_nps
->trans
.active
&& state
->count
== 0) {
472 cli_nps
->trans
.active
= false;
473 cli_nps
->trans
.write_req
= req
;
477 if (cli_nps
->trans
.read_req
&& state
->count
== 0) {
478 cli_nps
->trans
.write_req
= req
;
479 tstream_cli_np_readv_trans_start(cli_nps
->trans
.read_req
);
483 if (cli_nps
->is_smb1
) {
484 subreq
= cli_write_andx_send(state
, state
->ev
, cli_nps
->cli
,
486 8, /* 8 means message mode. */
489 cli_nps
->write
.ofs
); /* size */
491 subreq
= smb2cli_write_send(state
, state
->ev
,
493 cli_nps
->cli
->timeout
,
494 cli_nps
->cli
->smb2
.session
,
495 cli_nps
->cli
->smb2
.tcon
,
496 cli_nps
->write
.ofs
, /* length */
498 cli_nps
->fid_persistent
,
499 cli_nps
->fid_volatile
,
500 0, /* remaining_bytes */
504 if (tevent_req_nomem(subreq
, req
)) {
507 tevent_req_set_callback(subreq
,
508 tstream_cli_np_writev_write_done
,
512 static void tstream_cli_np_writev_disconnect_now(struct tevent_req
*req
,
514 const char *location
);
516 static void tstream_cli_np_writev_write_done(struct tevent_req
*subreq
)
518 struct tevent_req
*req
=
519 tevent_req_callback_data(subreq
, struct tevent_req
);
520 struct tstream_cli_np_writev_state
*state
=
521 tevent_req_data(req
, struct tstream_cli_np_writev_state
);
522 struct tstream_cli_np
*cli_nps
=
523 tstream_context_data(state
->stream
,
524 struct tstream_cli_np
);
528 if (cli_nps
->is_smb1
) {
529 status
= cli_write_andx_recv(subreq
, &written
);
531 uint32_t smb2_written
;
532 status
= smb2cli_write_recv(subreq
, &smb2_written
);
533 if (NT_STATUS_IS_OK(status
)) {
534 written
= smb2_written
;
538 if (!NT_STATUS_IS_OK(status
)) {
539 tstream_cli_np_writev_disconnect_now(req
, EIO
, __location__
);
543 if (written
!= cli_nps
->write
.ofs
) {
544 tstream_cli_np_writev_disconnect_now(req
, EIO
, __location__
);
548 tstream_cli_np_writev_write_next(req
);
551 static void tstream_cli_np_writev_disconnect_done(struct tevent_req
*subreq
);
553 static void tstream_cli_np_writev_disconnect_now(struct tevent_req
*req
,
555 const char *location
)
557 struct tstream_cli_np_writev_state
*state
=
559 struct tstream_cli_np_writev_state
);
560 struct tstream_cli_np
*cli_nps
=
561 tstream_context_data(state
->stream
,
562 struct tstream_cli_np
);
563 struct tevent_req
*subreq
;
565 state
->error
.val
= error
;
566 state
->error
.location
= location
;
568 if (!cli_state_is_connected(cli_nps
->cli
)) {
569 /* return the original error */
570 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
574 if (cli_nps
->is_smb1
) {
575 subreq
= cli_close_send(state
, state
->ev
, cli_nps
->cli
,
578 subreq
= smb2cli_close_send(state
, state
->ev
,
580 cli_nps
->cli
->timeout
,
581 cli_nps
->cli
->smb2
.session
,
582 cli_nps
->cli
->smb2
.tcon
,
584 cli_nps
->fid_persistent
,
585 cli_nps
->fid_volatile
);
587 if (subreq
== NULL
) {
588 /* return the original error */
589 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
592 tevent_req_set_callback(subreq
,
593 tstream_cli_np_writev_disconnect_done
,
597 static void tstream_cli_np_writev_disconnect_done(struct tevent_req
*subreq
)
599 struct tevent_req
*req
=
600 tevent_req_callback_data(subreq
, struct tevent_req
);
601 struct tstream_cli_np_writev_state
*state
=
602 tevent_req_data(req
, struct tstream_cli_np_writev_state
);
603 struct tstream_cli_np
*cli_nps
=
604 tstream_context_data(state
->stream
, struct tstream_cli_np
);
606 if (cli_nps
->is_smb1
) {
607 cli_close_recv(subreq
);
609 smb2cli_close_recv(subreq
);
615 /* return the original error */
616 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
619 static int tstream_cli_np_writev_recv(struct tevent_req
*req
,
622 struct tstream_cli_np_writev_state
*state
=
624 struct tstream_cli_np_writev_state
);
627 ret
= tsocket_simple_int_recv(req
, perrno
);
632 tevent_req_received(req
);
636 struct tstream_cli_np_readv_state
{
637 struct tstream_context
*stream
;
638 struct tevent_context
*ev
;
640 struct iovec
*vector
;
646 struct tevent_immediate
*im
;
651 const char *location
;
655 static int tstream_cli_np_readv_state_destructor(struct tstream_cli_np_readv_state
*state
)
657 struct tstream_cli_np
*cli_nps
=
658 tstream_context_data(state
->stream
,
659 struct tstream_cli_np
);
661 cli_nps
->trans
.read_req
= NULL
;
666 static void tstream_cli_np_readv_read_next(struct tevent_req
*req
);
668 static struct tevent_req
*tstream_cli_np_readv_send(TALLOC_CTX
*mem_ctx
,
669 struct tevent_context
*ev
,
670 struct tstream_context
*stream
,
671 struct iovec
*vector
,
674 struct tevent_req
*req
;
675 struct tstream_cli_np_readv_state
*state
;
676 struct tstream_cli_np
*cli_nps
=
677 tstream_context_data(stream
, struct tstream_cli_np
);
679 req
= tevent_req_create(mem_ctx
, &state
,
680 struct tstream_cli_np_readv_state
);
684 state
->stream
= stream
;
688 talloc_set_destructor(state
, tstream_cli_np_readv_state_destructor
);
690 if (!cli_state_is_connected(cli_nps
->cli
)) {
691 tevent_req_error(req
, ENOTCONN
);
692 return tevent_req_post(req
, ev
);
696 * we make a copy of the vector so we can change the structure
698 state
->vector
= talloc_array(state
, struct iovec
, count
);
699 if (tevent_req_nomem(state
->vector
, req
)) {
700 return tevent_req_post(req
, ev
);
702 memcpy(state
->vector
, vector
, sizeof(struct iovec
) * count
);
703 state
->count
= count
;
705 tstream_cli_np_readv_read_next(req
);
706 if (!tevent_req_is_in_progress(req
)) {
707 return tevent_req_post(req
, ev
);
713 static void tstream_cli_np_readv_read_done(struct tevent_req
*subreq
);
715 static void tstream_cli_np_readv_read_next(struct tevent_req
*req
)
717 struct tstream_cli_np_readv_state
*state
=
719 struct tstream_cli_np_readv_state
);
720 struct tstream_cli_np
*cli_nps
=
721 tstream_context_data(state
->stream
,
722 struct tstream_cli_np
);
723 struct tevent_req
*subreq
;
726 * copy the pending buffer first
728 while (cli_nps
->read
.left
> 0 && state
->count
> 0) {
729 uint8_t *base
= (uint8_t *)state
->vector
[0].iov_base
;
730 size_t len
= MIN(cli_nps
->read
.left
, state
->vector
[0].iov_len
);
732 memcpy(base
, cli_nps
->read
.buf
+ cli_nps
->read
.ofs
, len
);
735 state
->vector
[0].iov_base
= base
;
736 state
->vector
[0].iov_len
-= len
;
738 cli_nps
->read
.ofs
+= len
;
739 cli_nps
->read
.left
-= len
;
741 if (state
->vector
[0].iov_len
== 0) {
749 if (cli_nps
->read
.left
== 0) {
750 TALLOC_FREE(cli_nps
->read
.buf
);
753 if (state
->count
== 0) {
754 tevent_req_done(req
);
758 if (cli_nps
->trans
.active
) {
759 cli_nps
->trans
.active
= false;
760 cli_nps
->trans
.read_req
= req
;
764 if (cli_nps
->trans
.write_req
) {
765 cli_nps
->trans
.read_req
= req
;
766 tstream_cli_np_readv_trans_start(req
);
770 if (cli_nps
->is_smb1
) {
771 subreq
= cli_read_andx_send(state
, state
->ev
, cli_nps
->cli
,
774 TSTREAM_CLI_NP_MAX_BUF_SIZE
);
776 subreq
= smb2cli_read_send(state
, state
->ev
,
778 cli_nps
->cli
->timeout
,
779 cli_nps
->cli
->smb2
.session
,
780 cli_nps
->cli
->smb2
.tcon
,
781 TSTREAM_CLI_NP_MAX_BUF_SIZE
, /* length */
783 cli_nps
->fid_persistent
,
784 cli_nps
->fid_volatile
,
785 0, /* minimum_count */
786 0); /* remaining_bytes */
788 if (tevent_req_nomem(subreq
, req
)) {
791 tevent_req_set_callback(subreq
,
792 tstream_cli_np_readv_read_done
,
796 static void tstream_cli_np_readv_trans_done(struct tevent_req
*subreq
);
798 static void tstream_cli_np_readv_trans_start(struct tevent_req
*req
)
800 struct tstream_cli_np_readv_state
*state
=
802 struct tstream_cli_np_readv_state
);
803 struct tstream_cli_np
*cli_nps
=
804 tstream_context_data(state
->stream
,
805 struct tstream_cli_np
);
806 struct tevent_req
*subreq
;
808 state
->trans
.im
= tevent_create_immediate(state
);
809 if (tevent_req_nomem(state
->trans
.im
, req
)) {
813 if (cli_nps
->is_smb1
) {
814 subreq
= cli_trans_send(state
, state
->ev
,
819 cli_nps
->trans
.setup
, 2,
824 TSTREAM_CLI_NP_MAX_BUF_SIZE
);
826 DATA_BLOB in_input_buffer
= data_blob_null
;
827 DATA_BLOB in_output_buffer
= data_blob_null
;
829 in_input_buffer
= data_blob_const(cli_nps
->write
.buf
,
832 subreq
= smb2cli_ioctl_send(state
, state
->ev
,
834 cli_nps
->cli
->timeout
,
835 cli_nps
->cli
->smb2
.session
,
836 cli_nps
->cli
->smb2
.tcon
,
837 cli_nps
->fid_persistent
,
838 cli_nps
->fid_volatile
,
839 FSCTL_NAMED_PIPE_READ_WRITE
,
840 0, /* in_max_input_length */
842 /* in_max_output_length */
843 TSTREAM_CLI_NP_MAX_BUF_SIZE
,
845 SMB2_IOCTL_FLAG_IS_FSCTL
);
847 if (tevent_req_nomem(subreq
, req
)) {
850 tevent_req_set_callback(subreq
,
851 tstream_cli_np_readv_trans_done
,
855 static void tstream_cli_np_readv_disconnect_now(struct tevent_req
*req
,
857 const char *location
);
858 static void tstream_cli_np_readv_trans_next(struct tevent_context
*ctx
,
859 struct tevent_immediate
*im
,
862 static void tstream_cli_np_readv_trans_done(struct tevent_req
*subreq
)
864 struct tevent_req
*req
=
865 tevent_req_callback_data(subreq
, struct tevent_req
);
866 struct tstream_cli_np_readv_state
*state
=
867 tevent_req_data(req
, struct tstream_cli_np_readv_state
);
868 struct tstream_cli_np
*cli_nps
=
869 tstream_context_data(state
->stream
, struct tstream_cli_np
);
874 if (cli_nps
->is_smb1
) {
875 status
= cli_trans_recv(subreq
, state
, NULL
, NULL
, 0, NULL
,
877 &rcvbuf
, 0, &received
);
879 DATA_BLOB out_input_buffer
= data_blob_null
;
880 DATA_BLOB out_output_buffer
= data_blob_null
;
882 status
= smb2cli_ioctl_recv(subreq
, state
,
886 /* Note that rcvbuf is not a talloc pointer here */
887 rcvbuf
= out_output_buffer
.data
;
888 received
= out_output_buffer
.length
;
891 if (NT_STATUS_EQUAL(status
, NT_STATUS_BUFFER_TOO_SMALL
)) {
892 status
= NT_STATUS_OK
;
894 if (!NT_STATUS_IS_OK(status
)) {
895 tstream_cli_np_readv_disconnect_now(req
, EIO
, __location__
);
899 if (received
> TSTREAM_CLI_NP_MAX_BUF_SIZE
) {
900 tstream_cli_np_readv_disconnect_now(req
, EIO
, __location__
);
905 tstream_cli_np_readv_disconnect_now(req
, EPIPE
, __location__
);
909 cli_nps
->read
.ofs
= 0;
910 cli_nps
->read
.left
= received
;
911 cli_nps
->read
.buf
= talloc_array(cli_nps
, uint8_t, received
);
912 if (cli_nps
->read
.buf
== NULL
) {
914 tevent_req_nomem(cli_nps
->read
.buf
, req
);
917 memcpy(cli_nps
->read
.buf
, rcvbuf
, received
);
919 if (cli_nps
->trans
.write_req
== NULL
) {
920 tstream_cli_np_readv_read_next(req
);
924 tevent_schedule_immediate(state
->trans
.im
, state
->ev
,
925 tstream_cli_np_readv_trans_next
, req
);
927 tevent_req_done(cli_nps
->trans
.write_req
);
930 static void tstream_cli_np_readv_trans_next(struct tevent_context
*ctx
,
931 struct tevent_immediate
*im
,
934 struct tevent_req
*req
=
935 talloc_get_type_abort(private_data
,
938 tstream_cli_np_readv_read_next(req
);
941 static void tstream_cli_np_readv_read_done(struct tevent_req
*subreq
)
943 struct tevent_req
*req
=
944 tevent_req_callback_data(subreq
, struct tevent_req
);
945 struct tstream_cli_np_readv_state
*state
=
946 tevent_req_data(req
, struct tstream_cli_np_readv_state
);
947 struct tstream_cli_np
*cli_nps
=
948 tstream_context_data(state
->stream
, struct tstream_cli_np
);
954 * We must free subreq in this function as there is
955 * a timer event attached to it.
958 if (cli_nps
->is_smb1
) {
959 status
= cli_read_andx_recv(subreq
, &received
, &rcvbuf
);
961 uint32_t data_length
= 0;
962 status
= smb2cli_read_recv(subreq
, state
, &rcvbuf
, &data_length
);
963 received
= data_length
;
966 * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
969 if (NT_STATUS_EQUAL(status
, NT_STATUS_BUFFER_TOO_SMALL
)) {
971 * NT_STATUS_BUFFER_TOO_SMALL means that there's
972 * more data to read when the named pipe is used
973 * in message mode (which is the case here).
975 * But we hide this from the caller.
977 status
= NT_STATUS_OK
;
979 if (!NT_STATUS_IS_OK(status
)) {
981 tstream_cli_np_readv_disconnect_now(req
, EIO
, __location__
);
985 if (received
> TSTREAM_CLI_NP_MAX_BUF_SIZE
) {
987 tstream_cli_np_readv_disconnect_now(req
, EIO
, __location__
);
993 tstream_cli_np_readv_disconnect_now(req
, EPIPE
, __location__
);
997 cli_nps
->read
.ofs
= 0;
998 cli_nps
->read
.left
= received
;
999 cli_nps
->read
.buf
= talloc_array(cli_nps
, uint8_t, received
);
1000 if (cli_nps
->read
.buf
== NULL
) {
1001 TALLOC_FREE(subreq
);
1002 tevent_req_nomem(cli_nps
->read
.buf
, req
);
1005 memcpy(cli_nps
->read
.buf
, rcvbuf
, received
);
1006 TALLOC_FREE(subreq
);
1008 tstream_cli_np_readv_read_next(req
);
1011 static void tstream_cli_np_readv_disconnect_done(struct tevent_req
*subreq
);
1013 static void tstream_cli_np_readv_error(struct tevent_req
*req
);
1015 static void tstream_cli_np_readv_disconnect_now(struct tevent_req
*req
,
1017 const char *location
)
1019 struct tstream_cli_np_readv_state
*state
=
1020 tevent_req_data(req
,
1021 struct tstream_cli_np_readv_state
);
1022 struct tstream_cli_np
*cli_nps
=
1023 tstream_context_data(state
->stream
,
1024 struct tstream_cli_np
);
1025 struct tevent_req
*subreq
;
1027 state
->error
.val
= error
;
1028 state
->error
.location
= location
;
1030 if (!cli_state_is_connected(cli_nps
->cli
)) {
1031 /* return the original error */
1032 tstream_cli_np_readv_error(req
);
1036 if (cli_nps
->is_smb1
) {
1037 subreq
= cli_close_send(state
, state
->ev
, cli_nps
->cli
,
1040 subreq
= smb2cli_close_send(state
, state
->ev
,
1042 cli_nps
->cli
->timeout
,
1043 cli_nps
->cli
->smb2
.session
,
1044 cli_nps
->cli
->smb2
.tcon
,
1046 cli_nps
->fid_persistent
,
1047 cli_nps
->fid_volatile
);
1049 if (subreq
== NULL
) {
1050 /* return the original error */
1051 tstream_cli_np_readv_error(req
);
1054 tevent_req_set_callback(subreq
,
1055 tstream_cli_np_readv_disconnect_done
,
1059 static void tstream_cli_np_readv_disconnect_done(struct tevent_req
*subreq
)
1061 struct tevent_req
*req
=
1062 tevent_req_callback_data(subreq
, struct tevent_req
);
1063 struct tstream_cli_np_readv_state
*state
=
1064 tevent_req_data(req
, struct tstream_cli_np_readv_state
);
1065 struct tstream_cli_np
*cli_nps
=
1066 tstream_context_data(state
->stream
, struct tstream_cli_np
);
1068 if (cli_nps
->is_smb1
) {
1069 cli_close_recv(subreq
);
1071 smb2cli_close_recv(subreq
);
1073 TALLOC_FREE(subreq
);
1075 cli_nps
->cli
= NULL
;
1077 tstream_cli_np_readv_error(req
);
1080 static void tstream_cli_np_readv_error_trigger(struct tevent_context
*ctx
,
1081 struct tevent_immediate
*im
,
1082 void *private_data
);
1084 static void tstream_cli_np_readv_error(struct tevent_req
*req
)
1086 struct tstream_cli_np_readv_state
*state
=
1087 tevent_req_data(req
,
1088 struct tstream_cli_np_readv_state
);
1089 struct tstream_cli_np
*cli_nps
=
1090 tstream_context_data(state
->stream
,
1091 struct tstream_cli_np
);
1093 if (cli_nps
->trans
.write_req
== NULL
) {
1094 /* return the original error */
1095 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
1099 if (state
->trans
.im
== NULL
) {
1100 /* return the original error */
1101 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
1105 tevent_schedule_immediate(state
->trans
.im
, state
->ev
,
1106 tstream_cli_np_readv_error_trigger
, req
);
1108 /* return the original error for writev */
1109 _tevent_req_error(cli_nps
->trans
.write_req
,
1110 state
->error
.val
, state
->error
.location
);
1113 static void tstream_cli_np_readv_error_trigger(struct tevent_context
*ctx
,
1114 struct tevent_immediate
*im
,
1117 struct tevent_req
*req
=
1118 talloc_get_type_abort(private_data
,
1120 struct tstream_cli_np_readv_state
*state
=
1121 tevent_req_data(req
,
1122 struct tstream_cli_np_readv_state
);
1124 /* return the original error */
1125 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
1128 static int tstream_cli_np_readv_recv(struct tevent_req
*req
,
1131 struct tstream_cli_np_readv_state
*state
=
1132 tevent_req_data(req
, struct tstream_cli_np_readv_state
);
1135 ret
= tsocket_simple_int_recv(req
, perrno
);
1140 tevent_req_received(req
);
1144 struct tstream_cli_np_disconnect_state
{
1145 struct tstream_context
*stream
;
1148 static void tstream_cli_np_disconnect_done(struct tevent_req
*subreq
);
1150 static struct tevent_req
*tstream_cli_np_disconnect_send(TALLOC_CTX
*mem_ctx
,
1151 struct tevent_context
*ev
,
1152 struct tstream_context
*stream
)
1154 struct tstream_cli_np
*cli_nps
= tstream_context_data(stream
,
1155 struct tstream_cli_np
);
1156 struct tevent_req
*req
;
1157 struct tstream_cli_np_disconnect_state
*state
;
1158 struct tevent_req
*subreq
;
1160 req
= tevent_req_create(mem_ctx
, &state
,
1161 struct tstream_cli_np_disconnect_state
);
1166 state
->stream
= stream
;
1168 if (!cli_state_is_connected(cli_nps
->cli
)) {
1169 tevent_req_error(req
, ENOTCONN
);
1170 return tevent_req_post(req
, ev
);
1173 if (cli_nps
->is_smb1
) {
1174 subreq
= cli_close_send(state
, ev
, cli_nps
->cli
,
1177 subreq
= smb2cli_close_send(state
, ev
, cli_nps
->cli
->conn
,
1178 cli_nps
->cli
->timeout
,
1179 cli_nps
->cli
->smb2
.session
,
1180 cli_nps
->cli
->smb2
.tcon
,
1182 cli_nps
->fid_persistent
,
1183 cli_nps
->fid_volatile
);
1185 if (tevent_req_nomem(subreq
, req
)) {
1186 return tevent_req_post(req
, ev
);
1188 tevent_req_set_callback(subreq
, tstream_cli_np_disconnect_done
, req
);
1193 static void tstream_cli_np_disconnect_done(struct tevent_req
*subreq
)
1195 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
1197 struct tstream_cli_np_disconnect_state
*state
=
1198 tevent_req_data(req
, struct tstream_cli_np_disconnect_state
);
1199 struct tstream_cli_np
*cli_nps
=
1200 tstream_context_data(state
->stream
, struct tstream_cli_np
);
1203 if (cli_nps
->is_smb1
) {
1204 status
= cli_close_recv(subreq
);
1206 status
= smb2cli_close_recv(subreq
);
1208 TALLOC_FREE(subreq
);
1209 if (!NT_STATUS_IS_OK(status
)) {
1210 tevent_req_error(req
, EIO
);
1214 cli_nps
->cli
= NULL
;
1216 tevent_req_done(req
);
1219 static int tstream_cli_np_disconnect_recv(struct tevent_req
*req
,
1224 ret
= tsocket_simple_int_recv(req
, perrno
);
1226 tevent_req_received(req
);
1230 static const struct tstream_context_ops tstream_cli_np_ops
= {
1233 .pending_bytes
= tstream_cli_np_pending_bytes
,
1235 .readv_send
= tstream_cli_np_readv_send
,
1236 .readv_recv
= tstream_cli_np_readv_recv
,
1238 .writev_send
= tstream_cli_np_writev_send
,
1239 .writev_recv
= tstream_cli_np_writev_recv
,
1241 .disconnect_send
= tstream_cli_np_disconnect_send
,
1242 .disconnect_recv
= tstream_cli_np_disconnect_recv
,