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
.tid
, 0,
103 cli_nps
->fid_persistent
,
104 cli_nps
->fid_volatile
);
106 if (!NT_STATUS_IS_OK(status
)) {
107 DEBUG(1, ("tstream_cli_np_destructor: cli_close "
108 "failed on pipe %s. Error was %s\n",
109 cli_nps
->npipe
, nt_errstr(status
)));
112 * We can't do much on failure
117 struct tstream_cli_np_open_state
{
118 struct cli_state
*cli
;
121 uint64_t fid_persistent
;
122 uint64_t fid_volatile
;
126 static void tstream_cli_np_open_done(struct tevent_req
*subreq
);
128 struct tevent_req
*tstream_cli_np_open_send(TALLOC_CTX
*mem_ctx
,
129 struct tevent_context
*ev
,
130 struct cli_state
*cli
,
133 struct tevent_req
*req
;
134 struct tstream_cli_np_open_state
*state
;
135 struct tevent_req
*subreq
;
137 req
= tevent_req_create(mem_ctx
, &state
,
138 struct tstream_cli_np_open_state
);
144 state
->npipe
= talloc_strdup(state
, npipe
);
145 if (tevent_req_nomem(state
->npipe
, req
)) {
146 return tevent_req_post(req
, ev
);
149 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
150 state
->is_smb1
= true;
153 if (state
->is_smb1
) {
154 const char *smb1_npipe
;
157 * Windows and newer Samba versions allow
158 * the pipe name without leading backslash,
159 * but we should better behave like windows clients
161 smb1_npipe
= talloc_asprintf(state
, "\\%s", state
->npipe
);
162 if (tevent_req_nomem(smb1_npipe
, req
)) {
163 return tevent_req_post(req
, ev
);
166 subreq
= cli_ntcreate_send(state
, ev
, cli
,
171 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
176 subreq
= smb2cli_create_send(state
, ev
, cli
->conn
,
177 cli
->timeout
, cli
->smb2
.session
,
180 SMB2_OPLOCK_LEVEL_NONE
,
181 SMB2_IMPERSONATION_IMPERSONATION
,
183 0, /* file_attributes */
184 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
186 0, /* create_options */
189 if (tevent_req_nomem(subreq
, req
)) {
190 return tevent_req_post(req
, ev
);
192 tevent_req_set_callback(subreq
, tstream_cli_np_open_done
, req
);
197 static void tstream_cli_np_open_done(struct tevent_req
*subreq
)
199 struct tevent_req
*req
=
200 tevent_req_callback_data(subreq
, struct tevent_req
);
201 struct tstream_cli_np_open_state
*state
=
202 tevent_req_data(req
, struct tstream_cli_np_open_state
);
205 if (state
->is_smb1
) {
206 status
= cli_ntcreate_recv(subreq
, &state
->fnum
);
208 status
= smb2cli_create_recv(subreq
,
209 &state
->fid_persistent
,
210 &state
->fid_volatile
);
213 if (!NT_STATUS_IS_OK(status
)) {
214 tevent_req_nterror(req
, status
);
218 tevent_req_done(req
);
221 NTSTATUS
_tstream_cli_np_open_recv(struct tevent_req
*req
,
223 struct tstream_context
**_stream
,
224 const char *location
)
226 struct tstream_cli_np_open_state
*state
=
227 tevent_req_data(req
, struct tstream_cli_np_open_state
);
228 struct tstream_context
*stream
;
229 struct tstream_cli_np
*cli_nps
;
232 if (tevent_req_is_nterror(req
, &status
)) {
233 tevent_req_received(req
);
237 stream
= tstream_context_create(mem_ctx
,
240 struct tstream_cli_np
,
243 tevent_req_received(req
);
244 return NT_STATUS_NO_MEMORY
;
246 ZERO_STRUCTP(cli_nps
);
248 cli_nps
->cli
= state
->cli
;
249 cli_nps
->npipe
= talloc_move(cli_nps
, &state
->npipe
);
250 cli_nps
->is_smb1
= state
->is_smb1
;
251 cli_nps
->fnum
= state
->fnum
;
252 cli_nps
->fid_persistent
= state
->fid_persistent
;
253 cli_nps
->fid_volatile
= state
->fid_volatile
;
254 cli_nps
->default_timeout
= cli_set_timeout(state
->cli
, 0);
255 cli_set_timeout(state
->cli
, cli_nps
->default_timeout
);
257 talloc_set_destructor(cli_nps
, tstream_cli_np_destructor
);
259 cli_nps
->trans
.active
= false;
260 cli_nps
->trans
.read_req
= NULL
;
261 cli_nps
->trans
.write_req
= NULL
;
262 SSVAL(cli_nps
->trans
.setup
+0, 0, TRANSACT_DCERPCCMD
);
263 SSVAL(cli_nps
->trans
.setup
+1, 0, cli_nps
->fnum
);
266 tevent_req_received(req
);
270 static ssize_t
tstream_cli_np_pending_bytes(struct tstream_context
*stream
)
272 struct tstream_cli_np
*cli_nps
= tstream_context_data(stream
,
273 struct tstream_cli_np
);
275 if (!cli_state_is_connected(cli_nps
->cli
)) {
280 return cli_nps
->read
.left
;
283 bool tstream_is_cli_np(struct tstream_context
*stream
)
285 struct tstream_cli_np
*cli_nps
=
286 talloc_get_type(_tstream_context_data(stream
),
287 struct tstream_cli_np
);
296 NTSTATUS
tstream_cli_np_use_trans(struct tstream_context
*stream
)
298 struct tstream_cli_np
*cli_nps
= tstream_context_data(stream
,
299 struct tstream_cli_np
);
301 if (cli_nps
->trans
.read_req
) {
302 return NT_STATUS_PIPE_BUSY
;
305 if (cli_nps
->trans
.write_req
) {
306 return NT_STATUS_PIPE_BUSY
;
309 if (cli_nps
->trans
.active
) {
310 return NT_STATUS_PIPE_BUSY
;
313 cli_nps
->trans
.active
= true;
318 unsigned int tstream_cli_np_set_timeout(struct tstream_context
*stream
,
319 unsigned int timeout
)
321 struct tstream_cli_np
*cli_nps
= tstream_context_data(stream
,
322 struct tstream_cli_np
);
324 if (!cli_state_is_connected(cli_nps
->cli
)) {
325 return cli_nps
->default_timeout
;
328 return cli_set_timeout(cli_nps
->cli
, timeout
);
331 struct cli_state
*tstream_cli_np_get_cli_state(struct tstream_context
*stream
)
333 struct tstream_cli_np
*cli_nps
= tstream_context_data(stream
,
334 struct tstream_cli_np
);
339 struct tstream_cli_np_writev_state
{
340 struct tstream_context
*stream
;
341 struct tevent_context
*ev
;
343 struct iovec
*vector
;
350 const char *location
;
354 static int tstream_cli_np_writev_state_destructor(struct tstream_cli_np_writev_state
*state
)
356 struct tstream_cli_np
*cli_nps
=
357 tstream_context_data(state
->stream
,
358 struct tstream_cli_np
);
360 cli_nps
->trans
.write_req
= NULL
;
365 static void tstream_cli_np_writev_write_next(struct tevent_req
*req
);
367 static struct tevent_req
*tstream_cli_np_writev_send(TALLOC_CTX
*mem_ctx
,
368 struct tevent_context
*ev
,
369 struct tstream_context
*stream
,
370 const struct iovec
*vector
,
373 struct tevent_req
*req
;
374 struct tstream_cli_np_writev_state
*state
;
375 struct tstream_cli_np
*cli_nps
= tstream_context_data(stream
,
376 struct tstream_cli_np
);
378 req
= tevent_req_create(mem_ctx
, &state
,
379 struct tstream_cli_np_writev_state
);
383 state
->stream
= stream
;
387 talloc_set_destructor(state
, tstream_cli_np_writev_state_destructor
);
389 if (!cli_state_is_connected(cli_nps
->cli
)) {
390 tevent_req_error(req
, ENOTCONN
);
391 return tevent_req_post(req
, ev
);
395 * we make a copy of the vector so we can change the structure
397 state
->vector
= talloc_array(state
, struct iovec
, count
);
398 if (tevent_req_nomem(state
->vector
, req
)) {
399 return tevent_req_post(req
, ev
);
401 memcpy(state
->vector
, vector
, sizeof(struct iovec
) * count
);
402 state
->count
= count
;
404 tstream_cli_np_writev_write_next(req
);
405 if (!tevent_req_is_in_progress(req
)) {
406 return tevent_req_post(req
, ev
);
412 static void tstream_cli_np_readv_trans_start(struct tevent_req
*req
);
413 static void tstream_cli_np_writev_write_done(struct tevent_req
*subreq
);
415 static void tstream_cli_np_writev_write_next(struct tevent_req
*req
)
417 struct tstream_cli_np_writev_state
*state
=
419 struct tstream_cli_np_writev_state
);
420 struct tstream_cli_np
*cli_nps
=
421 tstream_context_data(state
->stream
,
422 struct tstream_cli_np
);
423 struct tevent_req
*subreq
;
427 for (i
=0; i
< state
->count
; i
++) {
428 left
+= state
->vector
[i
].iov_len
;
432 TALLOC_FREE(cli_nps
->write
.buf
);
433 tevent_req_done(req
);
437 cli_nps
->write
.ofs
= 0;
438 cli_nps
->write
.left
= MIN(left
, TSTREAM_CLI_NP_MAX_BUF_SIZE
);
439 cli_nps
->write
.buf
= talloc_realloc(cli_nps
, cli_nps
->write
.buf
,
440 uint8_t, cli_nps
->write
.left
);
441 if (tevent_req_nomem(cli_nps
->write
.buf
, req
)) {
446 * copy the pending buffer first
448 while (cli_nps
->write
.left
> 0 && state
->count
> 0) {
449 uint8_t *base
= (uint8_t *)state
->vector
[0].iov_base
;
450 size_t len
= MIN(cli_nps
->write
.left
, state
->vector
[0].iov_len
);
452 memcpy(cli_nps
->write
.buf
+ cli_nps
->write
.ofs
, base
, len
);
455 state
->vector
[0].iov_base
= base
;
456 state
->vector
[0].iov_len
-= len
;
458 cli_nps
->write
.ofs
+= len
;
459 cli_nps
->write
.left
-= len
;
461 if (state
->vector
[0].iov_len
== 0) {
469 if (cli_nps
->trans
.active
&& state
->count
== 0) {
470 cli_nps
->trans
.active
= false;
471 cli_nps
->trans
.write_req
= req
;
475 if (cli_nps
->trans
.read_req
&& state
->count
== 0) {
476 cli_nps
->trans
.write_req
= req
;
477 tstream_cli_np_readv_trans_start(cli_nps
->trans
.read_req
);
481 if (cli_nps
->is_smb1
) {
482 subreq
= cli_write_andx_send(state
, state
->ev
, cli_nps
->cli
,
484 8, /* 8 means message mode. */
487 cli_nps
->write
.ofs
); /* size */
489 subreq
= smb2cli_write_send(state
, state
->ev
,
491 cli_nps
->cli
->timeout
,
492 cli_nps
->cli
->smb2
.session
,
493 cli_nps
->cli
->smb2
.tid
,
494 cli_nps
->write
.ofs
, /* length */
496 cli_nps
->fid_persistent
,
497 cli_nps
->fid_volatile
,
498 0, /* remaining_bytes */
502 if (tevent_req_nomem(subreq
, req
)) {
505 tevent_req_set_callback(subreq
,
506 tstream_cli_np_writev_write_done
,
510 static void tstream_cli_np_writev_disconnect_now(struct tevent_req
*req
,
512 const char *location
);
514 static void tstream_cli_np_writev_write_done(struct tevent_req
*subreq
)
516 struct tevent_req
*req
=
517 tevent_req_callback_data(subreq
, struct tevent_req
);
518 struct tstream_cli_np_writev_state
*state
=
519 tevent_req_data(req
, struct tstream_cli_np_writev_state
);
520 struct tstream_cli_np
*cli_nps
=
521 tstream_context_data(state
->stream
,
522 struct tstream_cli_np
);
526 if (cli_nps
->is_smb1
) {
527 status
= cli_write_andx_recv(subreq
, &written
);
529 status
= smb2cli_write_recv(subreq
);
530 written
= cli_nps
->write
.ofs
; // TODO: get the value from the server
533 if (!NT_STATUS_IS_OK(status
)) {
534 tstream_cli_np_writev_disconnect_now(req
, EIO
, __location__
);
538 if (written
!= cli_nps
->write
.ofs
) {
539 tstream_cli_np_writev_disconnect_now(req
, EIO
, __location__
);
543 tstream_cli_np_writev_write_next(req
);
546 static void tstream_cli_np_writev_disconnect_done(struct tevent_req
*subreq
);
548 static void tstream_cli_np_writev_disconnect_now(struct tevent_req
*req
,
550 const char *location
)
552 struct tstream_cli_np_writev_state
*state
=
554 struct tstream_cli_np_writev_state
);
555 struct tstream_cli_np
*cli_nps
=
556 tstream_context_data(state
->stream
,
557 struct tstream_cli_np
);
558 struct tevent_req
*subreq
;
560 state
->error
.val
= error
;
561 state
->error
.location
= location
;
563 if (!cli_state_is_connected(cli_nps
->cli
)) {
564 /* return the original error */
565 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
569 if (cli_nps
->is_smb1
) {
570 subreq
= cli_close_send(state
, state
->ev
, cli_nps
->cli
,
573 subreq
= smb2cli_close_send(state
, state
->ev
,
575 cli_nps
->cli
->timeout
,
576 cli_nps
->cli
->smb2
.session
,
577 cli_nps
->cli
->smb2
.tid
,
579 cli_nps
->fid_persistent
,
580 cli_nps
->fid_volatile
);
582 if (subreq
== NULL
) {
583 /* return the original error */
584 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
587 tevent_req_set_callback(subreq
,
588 tstream_cli_np_writev_disconnect_done
,
592 static void tstream_cli_np_writev_disconnect_done(struct tevent_req
*subreq
)
594 struct tevent_req
*req
=
595 tevent_req_callback_data(subreq
, struct tevent_req
);
596 struct tstream_cli_np_writev_state
*state
=
597 tevent_req_data(req
, struct tstream_cli_np_writev_state
);
598 struct tstream_cli_np
*cli_nps
=
599 tstream_context_data(state
->stream
, struct tstream_cli_np
);
601 if (cli_nps
->is_smb1
) {
602 cli_close_recv(subreq
);
604 smb2cli_close_recv(subreq
);
610 /* return the original error */
611 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
614 static int tstream_cli_np_writev_recv(struct tevent_req
*req
,
617 struct tstream_cli_np_writev_state
*state
=
619 struct tstream_cli_np_writev_state
);
622 ret
= tsocket_simple_int_recv(req
, perrno
);
627 tevent_req_received(req
);
631 struct tstream_cli_np_readv_state
{
632 struct tstream_context
*stream
;
633 struct tevent_context
*ev
;
635 struct iovec
*vector
;
641 struct tevent_immediate
*im
;
646 const char *location
;
650 static int tstream_cli_np_readv_state_destructor(struct tstream_cli_np_readv_state
*state
)
652 struct tstream_cli_np
*cli_nps
=
653 tstream_context_data(state
->stream
,
654 struct tstream_cli_np
);
656 cli_nps
->trans
.read_req
= NULL
;
661 static void tstream_cli_np_readv_read_next(struct tevent_req
*req
);
663 static struct tevent_req
*tstream_cli_np_readv_send(TALLOC_CTX
*mem_ctx
,
664 struct tevent_context
*ev
,
665 struct tstream_context
*stream
,
666 struct iovec
*vector
,
669 struct tevent_req
*req
;
670 struct tstream_cli_np_readv_state
*state
;
671 struct tstream_cli_np
*cli_nps
=
672 tstream_context_data(stream
, struct tstream_cli_np
);
674 req
= tevent_req_create(mem_ctx
, &state
,
675 struct tstream_cli_np_readv_state
);
679 state
->stream
= stream
;
683 talloc_set_destructor(state
, tstream_cli_np_readv_state_destructor
);
685 if (!cli_state_is_connected(cli_nps
->cli
)) {
686 tevent_req_error(req
, ENOTCONN
);
687 return tevent_req_post(req
, ev
);
691 * we make a copy of the vector so we can change the structure
693 state
->vector
= talloc_array(state
, struct iovec
, count
);
694 if (tevent_req_nomem(state
->vector
, req
)) {
695 return tevent_req_post(req
, ev
);
697 memcpy(state
->vector
, vector
, sizeof(struct iovec
) * count
);
698 state
->count
= count
;
700 tstream_cli_np_readv_read_next(req
);
701 if (!tevent_req_is_in_progress(req
)) {
702 return tevent_req_post(req
, ev
);
708 static void tstream_cli_np_readv_read_done(struct tevent_req
*subreq
);
710 static void tstream_cli_np_readv_read_next(struct tevent_req
*req
)
712 struct tstream_cli_np_readv_state
*state
=
714 struct tstream_cli_np_readv_state
);
715 struct tstream_cli_np
*cli_nps
=
716 tstream_context_data(state
->stream
,
717 struct tstream_cli_np
);
718 struct tevent_req
*subreq
;
721 * copy the pending buffer first
723 while (cli_nps
->read
.left
> 0 && state
->count
> 0) {
724 uint8_t *base
= (uint8_t *)state
->vector
[0].iov_base
;
725 size_t len
= MIN(cli_nps
->read
.left
, state
->vector
[0].iov_len
);
727 memcpy(base
, cli_nps
->read
.buf
+ cli_nps
->read
.ofs
, len
);
730 state
->vector
[0].iov_base
= base
;
731 state
->vector
[0].iov_len
-= len
;
733 cli_nps
->read
.ofs
+= len
;
734 cli_nps
->read
.left
-= len
;
736 if (state
->vector
[0].iov_len
== 0) {
744 if (cli_nps
->read
.left
== 0) {
745 TALLOC_FREE(cli_nps
->read
.buf
);
748 if (state
->count
== 0) {
749 tevent_req_done(req
);
753 if (cli_nps
->trans
.active
) {
754 cli_nps
->trans
.active
= false;
755 cli_nps
->trans
.read_req
= req
;
759 if (cli_nps
->trans
.write_req
) {
760 cli_nps
->trans
.read_req
= req
;
761 tstream_cli_np_readv_trans_start(req
);
765 if (cli_nps
->is_smb1
) {
766 subreq
= cli_read_andx_send(state
, state
->ev
, cli_nps
->cli
,
769 TSTREAM_CLI_NP_MAX_BUF_SIZE
);
771 subreq
= smb2cli_read_send(state
, state
->ev
,
773 cli_nps
->cli
->timeout
,
774 cli_nps
->cli
->smb2
.session
,
775 cli_nps
->cli
->smb2
.tid
,
776 TSTREAM_CLI_NP_MAX_BUF_SIZE
, /* length */
778 cli_nps
->fid_persistent
,
779 cli_nps
->fid_volatile
,
780 0, /* minimum_count */
781 0); /* remaining_bytes */
783 if (tevent_req_nomem(subreq
, req
)) {
786 tevent_req_set_callback(subreq
,
787 tstream_cli_np_readv_read_done
,
791 static void tstream_cli_np_readv_trans_done(struct tevent_req
*subreq
);
793 static void tstream_cli_np_readv_trans_start(struct tevent_req
*req
)
795 struct tstream_cli_np_readv_state
*state
=
797 struct tstream_cli_np_readv_state
);
798 struct tstream_cli_np
*cli_nps
=
799 tstream_context_data(state
->stream
,
800 struct tstream_cli_np
);
801 struct tevent_req
*subreq
;
803 state
->trans
.im
= tevent_create_immediate(state
);
804 if (tevent_req_nomem(state
->trans
.im
, req
)) {
808 if (cli_nps
->is_smb1
) {
809 subreq
= cli_trans_send(state
, state
->ev
,
814 cli_nps
->trans
.setup
, 2,
819 TSTREAM_CLI_NP_MAX_BUF_SIZE
);
821 DATA_BLOB in_input_buffer
= data_blob_null
;
822 DATA_BLOB in_output_buffer
= data_blob_null
;
824 in_input_buffer
= data_blob_const(cli_nps
->write
.buf
,
827 subreq
= smb2cli_ioctl_send(state
, state
->ev
,
829 cli_nps
->cli
->timeout
,
830 cli_nps
->cli
->smb2
.session
,
831 cli_nps
->cli
->smb2
.tid
,
832 cli_nps
->fid_persistent
,
833 cli_nps
->fid_volatile
,
834 FSCTL_NAMED_PIPE_READ_WRITE
,
835 0, /* in_max_input_length */
837 /* in_max_output_length */
838 TSTREAM_CLI_NP_MAX_BUF_SIZE
,
840 SMB2_IOCTL_FLAG_IS_FSCTL
);
842 if (tevent_req_nomem(subreq
, req
)) {
845 tevent_req_set_callback(subreq
,
846 tstream_cli_np_readv_trans_done
,
850 static void tstream_cli_np_readv_disconnect_now(struct tevent_req
*req
,
852 const char *location
);
853 static void tstream_cli_np_readv_trans_next(struct tevent_context
*ctx
,
854 struct tevent_immediate
*im
,
857 static void tstream_cli_np_readv_trans_done(struct tevent_req
*subreq
)
859 struct tevent_req
*req
=
860 tevent_req_callback_data(subreq
, struct tevent_req
);
861 struct tstream_cli_np_readv_state
*state
=
862 tevent_req_data(req
, struct tstream_cli_np_readv_state
);
863 struct tstream_cli_np
*cli_nps
=
864 tstream_context_data(state
->stream
, struct tstream_cli_np
);
869 if (cli_nps
->is_smb1
) {
870 status
= cli_trans_recv(subreq
, state
, NULL
, NULL
, 0, NULL
,
872 &rcvbuf
, 0, &received
);
874 DATA_BLOB out_input_buffer
= data_blob_null
;
875 DATA_BLOB out_output_buffer
= data_blob_null
;
877 status
= smb2cli_ioctl_recv(subreq
, state
,
881 /* Note that rcvbuf is not a talloc pointer here */
882 rcvbuf
= out_output_buffer
.data
;
883 received
= out_output_buffer
.length
;
886 if (NT_STATUS_EQUAL(status
, NT_STATUS_BUFFER_TOO_SMALL
)) {
887 status
= NT_STATUS_OK
;
889 if (!NT_STATUS_IS_OK(status
)) {
890 tstream_cli_np_readv_disconnect_now(req
, EIO
, __location__
);
894 if (received
> TSTREAM_CLI_NP_MAX_BUF_SIZE
) {
895 tstream_cli_np_readv_disconnect_now(req
, EIO
, __location__
);
900 tstream_cli_np_readv_disconnect_now(req
, EPIPE
, __location__
);
904 cli_nps
->read
.ofs
= 0;
905 cli_nps
->read
.left
= received
;
906 cli_nps
->read
.buf
= talloc_array(cli_nps
, uint8_t, received
);
907 if (cli_nps
->read
.buf
== NULL
) {
909 tevent_req_nomem(cli_nps
->read
.buf
, req
);
912 memcpy(cli_nps
->read
.buf
, rcvbuf
, received
);
914 if (cli_nps
->trans
.write_req
== NULL
) {
915 tstream_cli_np_readv_read_next(req
);
919 tevent_schedule_immediate(state
->trans
.im
, state
->ev
,
920 tstream_cli_np_readv_trans_next
, req
);
922 tevent_req_done(cli_nps
->trans
.write_req
);
925 static void tstream_cli_np_readv_trans_next(struct tevent_context
*ctx
,
926 struct tevent_immediate
*im
,
929 struct tevent_req
*req
=
930 talloc_get_type_abort(private_data
,
933 tstream_cli_np_readv_read_next(req
);
936 static void tstream_cli_np_readv_read_done(struct tevent_req
*subreq
)
938 struct tevent_req
*req
=
939 tevent_req_callback_data(subreq
, struct tevent_req
);
940 struct tstream_cli_np_readv_state
*state
=
941 tevent_req_data(req
, struct tstream_cli_np_readv_state
);
942 struct tstream_cli_np
*cli_nps
=
943 tstream_context_data(state
->stream
, struct tstream_cli_np
);
949 * We must free subreq in this function as there is
950 * a timer event attached to it.
953 if (cli_nps
->is_smb1
) {
954 status
= cli_read_andx_recv(subreq
, &received
, &rcvbuf
);
956 uint32_t data_length
= 0;
957 status
= smb2cli_read_recv(subreq
, state
, &rcvbuf
, &data_length
);
958 received
= data_length
;
961 * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
964 if (NT_STATUS_EQUAL(status
, NT_STATUS_BUFFER_TOO_SMALL
)) {
966 * NT_STATUS_BUFFER_TOO_SMALL means that there's
967 * more data to read when the named pipe is used
968 * in message mode (which is the case here).
970 * But we hide this from the caller.
972 status
= NT_STATUS_OK
;
974 if (!NT_STATUS_IS_OK(status
)) {
976 tstream_cli_np_readv_disconnect_now(req
, EIO
, __location__
);
980 if (received
> TSTREAM_CLI_NP_MAX_BUF_SIZE
) {
982 tstream_cli_np_readv_disconnect_now(req
, EIO
, __location__
);
988 tstream_cli_np_readv_disconnect_now(req
, EPIPE
, __location__
);
992 cli_nps
->read
.ofs
= 0;
993 cli_nps
->read
.left
= received
;
994 cli_nps
->read
.buf
= talloc_array(cli_nps
, uint8_t, received
);
995 if (cli_nps
->read
.buf
== NULL
) {
997 tevent_req_nomem(cli_nps
->read
.buf
, req
);
1000 memcpy(cli_nps
->read
.buf
, rcvbuf
, received
);
1001 TALLOC_FREE(subreq
);
1003 tstream_cli_np_readv_read_next(req
);
1006 static void tstream_cli_np_readv_disconnect_done(struct tevent_req
*subreq
);
1008 static void tstream_cli_np_readv_error(struct tevent_req
*req
);
1010 static void tstream_cli_np_readv_disconnect_now(struct tevent_req
*req
,
1012 const char *location
)
1014 struct tstream_cli_np_readv_state
*state
=
1015 tevent_req_data(req
,
1016 struct tstream_cli_np_readv_state
);
1017 struct tstream_cli_np
*cli_nps
=
1018 tstream_context_data(state
->stream
,
1019 struct tstream_cli_np
);
1020 struct tevent_req
*subreq
;
1022 state
->error
.val
= error
;
1023 state
->error
.location
= location
;
1025 if (!cli_state_is_connected(cli_nps
->cli
)) {
1026 /* return the original error */
1027 tstream_cli_np_readv_error(req
);
1031 if (cli_nps
->is_smb1
) {
1032 subreq
= cli_close_send(state
, state
->ev
, cli_nps
->cli
,
1035 subreq
= smb2cli_close_send(state
, state
->ev
,
1037 cli_nps
->cli
->timeout
,
1038 cli_nps
->cli
->smb2
.session
,
1039 cli_nps
->cli
->smb2
.tid
,
1041 cli_nps
->fid_persistent
,
1042 cli_nps
->fid_volatile
);
1044 if (subreq
== NULL
) {
1045 /* return the original error */
1046 tstream_cli_np_readv_error(req
);
1049 tevent_req_set_callback(subreq
,
1050 tstream_cli_np_readv_disconnect_done
,
1054 static void tstream_cli_np_readv_disconnect_done(struct tevent_req
*subreq
)
1056 struct tevent_req
*req
=
1057 tevent_req_callback_data(subreq
, struct tevent_req
);
1058 struct tstream_cli_np_readv_state
*state
=
1059 tevent_req_data(req
, struct tstream_cli_np_readv_state
);
1060 struct tstream_cli_np
*cli_nps
=
1061 tstream_context_data(state
->stream
, struct tstream_cli_np
);
1063 if (cli_nps
->is_smb1
) {
1064 cli_close_recv(subreq
);
1066 smb2cli_close_recv(subreq
);
1068 TALLOC_FREE(subreq
);
1070 cli_nps
->cli
= NULL
;
1072 tstream_cli_np_readv_error(req
);
1075 static void tstream_cli_np_readv_error_trigger(struct tevent_context
*ctx
,
1076 struct tevent_immediate
*im
,
1077 void *private_data
);
1079 static void tstream_cli_np_readv_error(struct tevent_req
*req
)
1081 struct tstream_cli_np_readv_state
*state
=
1082 tevent_req_data(req
,
1083 struct tstream_cli_np_readv_state
);
1084 struct tstream_cli_np
*cli_nps
=
1085 tstream_context_data(state
->stream
,
1086 struct tstream_cli_np
);
1088 if (cli_nps
->trans
.write_req
== NULL
) {
1089 /* return the original error */
1090 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
1094 if (state
->trans
.im
== NULL
) {
1095 /* return the original error */
1096 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
1100 tevent_schedule_immediate(state
->trans
.im
, state
->ev
,
1101 tstream_cli_np_readv_error_trigger
, req
);
1103 /* return the original error for writev */
1104 _tevent_req_error(cli_nps
->trans
.write_req
,
1105 state
->error
.val
, state
->error
.location
);
1108 static void tstream_cli_np_readv_error_trigger(struct tevent_context
*ctx
,
1109 struct tevent_immediate
*im
,
1112 struct tevent_req
*req
=
1113 talloc_get_type_abort(private_data
,
1115 struct tstream_cli_np_readv_state
*state
=
1116 tevent_req_data(req
,
1117 struct tstream_cli_np_readv_state
);
1119 /* return the original error */
1120 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
1123 static int tstream_cli_np_readv_recv(struct tevent_req
*req
,
1126 struct tstream_cli_np_readv_state
*state
=
1127 tevent_req_data(req
, struct tstream_cli_np_readv_state
);
1130 ret
= tsocket_simple_int_recv(req
, perrno
);
1135 tevent_req_received(req
);
1139 struct tstream_cli_np_disconnect_state
{
1140 struct tstream_context
*stream
;
1143 static void tstream_cli_np_disconnect_done(struct tevent_req
*subreq
);
1145 static struct tevent_req
*tstream_cli_np_disconnect_send(TALLOC_CTX
*mem_ctx
,
1146 struct tevent_context
*ev
,
1147 struct tstream_context
*stream
)
1149 struct tstream_cli_np
*cli_nps
= tstream_context_data(stream
,
1150 struct tstream_cli_np
);
1151 struct tevent_req
*req
;
1152 struct tstream_cli_np_disconnect_state
*state
;
1153 struct tevent_req
*subreq
;
1155 req
= tevent_req_create(mem_ctx
, &state
,
1156 struct tstream_cli_np_disconnect_state
);
1161 state
->stream
= stream
;
1163 if (!cli_state_is_connected(cli_nps
->cli
)) {
1164 tevent_req_error(req
, ENOTCONN
);
1165 return tevent_req_post(req
, ev
);
1168 if (cli_nps
->is_smb1
) {
1169 subreq
= cli_close_send(state
, ev
, cli_nps
->cli
,
1172 subreq
= smb2cli_close_send(state
, ev
, cli_nps
->cli
->conn
,
1173 cli_nps
->cli
->timeout
,
1174 cli_nps
->cli
->smb2
.session
,
1175 cli_nps
->cli
->smb2
.tid
,
1177 cli_nps
->fid_persistent
,
1178 cli_nps
->fid_volatile
);
1180 if (tevent_req_nomem(subreq
, req
)) {
1181 return tevent_req_post(req
, ev
);
1183 tevent_req_set_callback(subreq
, tstream_cli_np_disconnect_done
, req
);
1188 static void tstream_cli_np_disconnect_done(struct tevent_req
*subreq
)
1190 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
1192 struct tstream_cli_np_disconnect_state
*state
=
1193 tevent_req_data(req
, struct tstream_cli_np_disconnect_state
);
1194 struct tstream_cli_np
*cli_nps
=
1195 tstream_context_data(state
->stream
, struct tstream_cli_np
);
1198 if (cli_nps
->is_smb1
) {
1199 status
= cli_close_recv(subreq
);
1201 status
= smb2cli_close_recv(subreq
);
1203 TALLOC_FREE(subreq
);
1204 if (!NT_STATUS_IS_OK(status
)) {
1205 tevent_req_error(req
, EIO
);
1209 cli_nps
->cli
= NULL
;
1211 tevent_req_done(req
);
1214 static int tstream_cli_np_disconnect_recv(struct tevent_req
*req
,
1219 ret
= tsocket_simple_int_recv(req
, perrno
);
1221 tevent_req_received(req
);
1225 static const struct tstream_context_ops tstream_cli_np_ops
= {
1228 .pending_bytes
= tstream_cli_np_pending_bytes
,
1230 .readv_send
= tstream_cli_np_readv_send
,
1231 .readv_recv
= tstream_cli_np_readv_recv
,
1233 .writev_send
= tstream_cli_np_writev_send
,
1234 .writev_recv
= tstream_cli_np_writev_recv
,
1236 .disconnect_send
= tstream_cli_np_disconnect_send
,
1237 .disconnect_recv
= tstream_cli_np_disconnect_recv
,