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 tstream_cli_np_writev_state {
334 struct tstream_context *stream;
335 struct tevent_context *ev;
337 struct iovec *vector;
344 const char *location;
348 static int tstream_cli_np_writev_state_destructor(struct tstream_cli_np_writev_state *state)
350 struct tstream_cli_np *cli_nps =
351 tstream_context_data(state->stream,
352 struct tstream_cli_np);
354 cli_nps->trans.write_req = NULL;
359 static void tstream_cli_np_writev_write_next(struct tevent_req *req);
361 static struct tevent_req *tstream_cli_np_writev_send(TALLOC_CTX *mem_ctx,
362 struct tevent_context *ev,
363 struct tstream_context *stream,
364 const struct iovec *vector,
367 struct tevent_req *req;
368 struct tstream_cli_np_writev_state *state;
369 struct tstream_cli_np *cli_nps = tstream_context_data(stream,
370 struct tstream_cli_np);
372 req = tevent_req_create(mem_ctx, &state,
373 struct tstream_cli_np_writev_state);
377 state->stream = stream;
381 talloc_set_destructor(state, tstream_cli_np_writev_state_destructor);
383 if (!cli_state_is_connected(cli_nps->cli)) {
384 tevent_req_error(req, ENOTCONN);
385 return tevent_req_post(req, ev);
389 * we make a copy of the vector so we can change the structure
391 state->vector = talloc_array(state, struct iovec, count);
392 if (tevent_req_nomem(state->vector, req)) {
393 return tevent_req_post(req, ev);
395 memcpy(state->vector, vector, sizeof(struct iovec) * count);
396 state->count = count;
398 tstream_cli_np_writev_write_next(req);
399 if (!tevent_req_is_in_progress(req)) {
400 return tevent_req_post(req, ev);
406 static void tstream_cli_np_readv_trans_start(struct tevent_req *req);
407 static void tstream_cli_np_writev_write_done(struct tevent_req *subreq);
409 static void tstream_cli_np_writev_write_next(struct tevent_req *req)
411 struct tstream_cli_np_writev_state *state =
413 struct tstream_cli_np_writev_state);
414 struct tstream_cli_np *cli_nps =
415 tstream_context_data(state->stream,
416 struct tstream_cli_np);
417 struct tevent_req *subreq;
421 for (i=0; i < state->count; i++) {
422 left += state->vector[i].iov_len;
426 TALLOC_FREE(cli_nps->write.buf);
427 tevent_req_done(req);
431 cli_nps->write.ofs = 0;
432 cli_nps->write.left = MIN(left, TSTREAM_CLI_NP_MAX_BUF_SIZE);
433 cli_nps->write.buf = talloc_realloc(cli_nps, cli_nps->write.buf,
434 uint8_t, cli_nps->write.left);
435 if (tevent_req_nomem(cli_nps->write.buf, req)) {
440 * copy the pending buffer first
442 while (cli_nps->write.left > 0 && state->count > 0) {
443 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
444 size_t len = MIN(cli_nps->write.left, state->vector[0].iov_len);
446 memcpy(cli_nps->write.buf + cli_nps->write.ofs, base, len);
449 state->vector[0].iov_base = base;
450 state->vector[0].iov_len -= len;
452 cli_nps->write.ofs += len;
453 cli_nps->write.left -= len;
455 if (state->vector[0].iov_len == 0) {
463 if (cli_nps->trans.active && state->count == 0) {
464 cli_nps->trans.active = false;
465 cli_nps->trans.write_req = req;
469 if (cli_nps->trans.read_req && state->count == 0) {
470 cli_nps->trans.write_req = req;
471 tstream_cli_np_readv_trans_start(cli_nps->trans.read_req);
475 if (cli_nps->is_smb1) {
476 subreq = cli_write_andx_send(state, state->ev, cli_nps->cli,
478 8, /* 8 means message mode. */
481 cli_nps->write.ofs); /* size */
483 subreq = smb2cli_write_send(state, state->ev,
485 cli_nps->cli->timeout,
486 cli_nps->cli->smb2.session,
487 cli_nps->cli->smb2.tcon,
488 cli_nps->write.ofs, /* length */
490 cli_nps->fid_persistent,
491 cli_nps->fid_volatile,
492 0, /* remaining_bytes */
496 if (tevent_req_nomem(subreq, req)) {
499 tevent_req_set_callback(subreq,
500 tstream_cli_np_writev_write_done,
504 static void tstream_cli_np_writev_disconnect_now(struct tevent_req *req,
506 const char *location);
508 static void tstream_cli_np_writev_write_done(struct tevent_req *subreq)
510 struct tevent_req *req =
511 tevent_req_callback_data(subreq, struct tevent_req);
512 struct tstream_cli_np_writev_state *state =
513 tevent_req_data(req, struct tstream_cli_np_writev_state);
514 struct tstream_cli_np *cli_nps =
515 tstream_context_data(state->stream,
516 struct tstream_cli_np);
520 if (cli_nps->is_smb1) {
521 status = cli_write_andx_recv(subreq, &written);
523 uint32_t smb2_written;
524 status = smb2cli_write_recv(subreq, &smb2_written);
525 if (NT_STATUS_IS_OK(status)) {
526 written = smb2_written;
530 if (!NT_STATUS_IS_OK(status)) {
531 tstream_cli_np_writev_disconnect_now(req, EIO, __location__);
535 if (written != cli_nps->write.ofs) {
536 tstream_cli_np_writev_disconnect_now(req, EIO, __location__);
540 tstream_cli_np_writev_write_next(req);
543 static void tstream_cli_np_writev_disconnect_done(struct tevent_req *subreq);
545 static void tstream_cli_np_writev_disconnect_now(struct tevent_req *req,
547 const char *location)
549 struct tstream_cli_np_writev_state *state =
551 struct tstream_cli_np_writev_state);
552 struct tstream_cli_np *cli_nps =
553 tstream_context_data(state->stream,
554 struct tstream_cli_np);
555 struct tevent_req *subreq;
557 state->error.val = error;
558 state->error.location = location;
560 if (!cli_state_is_connected(cli_nps->cli)) {
561 /* return the original error */
562 _tevent_req_error(req, state->error.val, state->error.location);
566 if (cli_nps->is_smb1) {
567 subreq = cli_close_send(state, state->ev, cli_nps->cli,
570 subreq = smb2cli_close_send(state, state->ev,
572 cli_nps->cli->timeout,
573 cli_nps->cli->smb2.session,
574 cli_nps->cli->smb2.tcon,
576 cli_nps->fid_persistent,
577 cli_nps->fid_volatile);
579 if (subreq == NULL) {
580 /* return the original error */
581 _tevent_req_error(req, state->error.val, state->error.location);
584 tevent_req_set_callback(subreq,
585 tstream_cli_np_writev_disconnect_done,
589 static void tstream_cli_np_writev_disconnect_done(struct tevent_req *subreq)
591 struct tevent_req *req =
592 tevent_req_callback_data(subreq, struct tevent_req);
593 struct tstream_cli_np_writev_state *state =
594 tevent_req_data(req, struct tstream_cli_np_writev_state);
595 struct tstream_cli_np *cli_nps =
596 tstream_context_data(state->stream, struct tstream_cli_np);
598 if (cli_nps->is_smb1) {
599 cli_close_recv(subreq);
601 smb2cli_close_recv(subreq);
607 /* return the original error */
608 _tevent_req_error(req, state->error.val, state->error.location);
611 static int tstream_cli_np_writev_recv(struct tevent_req *req,
614 struct tstream_cli_np_writev_state *state =
616 struct tstream_cli_np_writev_state);
619 ret = tsocket_simple_int_recv(req, perrno);
624 tevent_req_received(req);
628 struct tstream_cli_np_readv_state {
629 struct tstream_context *stream;
630 struct tevent_context *ev;
632 struct iovec *vector;
638 struct tevent_immediate *im;
643 const char *location;
647 static int tstream_cli_np_readv_state_destructor(struct tstream_cli_np_readv_state *state)
649 struct tstream_cli_np *cli_nps =
650 tstream_context_data(state->stream,
651 struct tstream_cli_np);
653 cli_nps->trans.read_req = NULL;
658 static void tstream_cli_np_readv_read_next(struct tevent_req *req);
660 static struct tevent_req *tstream_cli_np_readv_send(TALLOC_CTX *mem_ctx,
661 struct tevent_context *ev,
662 struct tstream_context *stream,
663 struct iovec *vector,
666 struct tevent_req *req;
667 struct tstream_cli_np_readv_state *state;
668 struct tstream_cli_np *cli_nps =
669 tstream_context_data(stream, struct tstream_cli_np);
671 req = tevent_req_create(mem_ctx, &state,
672 struct tstream_cli_np_readv_state);
676 state->stream = stream;
680 talloc_set_destructor(state, tstream_cli_np_readv_state_destructor);
682 if (!cli_state_is_connected(cli_nps->cli)) {
683 tevent_req_error(req, ENOTCONN);
684 return tevent_req_post(req, ev);
688 * we make a copy of the vector so we can change the structure
690 state->vector = talloc_array(state, struct iovec, count);
691 if (tevent_req_nomem(state->vector, req)) {
692 return tevent_req_post(req, ev);
694 memcpy(state->vector, vector, sizeof(struct iovec) * count);
695 state->count = count;
697 tstream_cli_np_readv_read_next(req);
698 if (!tevent_req_is_in_progress(req)) {
699 return tevent_req_post(req, ev);
705 static void tstream_cli_np_readv_read_done(struct tevent_req *subreq);
707 static void tstream_cli_np_readv_read_next(struct tevent_req *req)
709 struct tstream_cli_np_readv_state *state =
711 struct tstream_cli_np_readv_state);
712 struct tstream_cli_np *cli_nps =
713 tstream_context_data(state->stream,
714 struct tstream_cli_np);
715 struct tevent_req *subreq;
718 * copy the pending buffer first
720 while (cli_nps->read.left > 0 && state->count > 0) {
721 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
722 size_t len = MIN(cli_nps->read.left, state->vector[0].iov_len);
724 memcpy(base, cli_nps->read.buf + cli_nps->read.ofs, len);
727 state->vector[0].iov_base = base;
728 state->vector[0].iov_len -= len;
730 cli_nps->read.ofs += len;
731 cli_nps->read.left -= len;
733 if (state->vector[0].iov_len == 0) {
741 if (cli_nps->read.left == 0) {
742 TALLOC_FREE(cli_nps->read.buf);
745 if (state->count == 0) {
746 tevent_req_done(req);
750 if (cli_nps->trans.active) {
751 cli_nps->trans.active = false;
752 cli_nps->trans.read_req = req;
756 if (cli_nps->trans.write_req) {
757 cli_nps->trans.read_req = req;
758 tstream_cli_np_readv_trans_start(req);
762 if (cli_nps->is_smb1) {
763 subreq = cli_read_andx_send(state, state->ev, cli_nps->cli,
766 TSTREAM_CLI_NP_MAX_BUF_SIZE);
768 subreq = smb2cli_read_send(state, state->ev,
770 cli_nps->cli->timeout,
771 cli_nps->cli->smb2.session,
772 cli_nps->cli->smb2.tcon,
773 TSTREAM_CLI_NP_MAX_BUF_SIZE, /* length */
775 cli_nps->fid_persistent,
776 cli_nps->fid_volatile,
777 0, /* minimum_count */
778 0); /* remaining_bytes */
780 if (tevent_req_nomem(subreq, req)) {
783 tevent_req_set_callback(subreq,
784 tstream_cli_np_readv_read_done,
788 static void tstream_cli_np_readv_trans_done(struct tevent_req *subreq);
790 static void tstream_cli_np_readv_trans_start(struct tevent_req *req)
792 struct tstream_cli_np_readv_state *state =
794 struct tstream_cli_np_readv_state);
795 struct tstream_cli_np *cli_nps =
796 tstream_context_data(state->stream,
797 struct tstream_cli_np);
798 struct tevent_req *subreq;
800 state->trans.im = tevent_create_immediate(state);
801 if (tevent_req_nomem(state->trans.im, req)) {
805 if (cli_nps->is_smb1) {
806 subreq = cli_trans_send(state, state->ev,
811 cli_nps->trans.setup, 2,
816 TSTREAM_CLI_NP_MAX_BUF_SIZE);
818 DATA_BLOB in_input_buffer = data_blob_null;
819 DATA_BLOB in_output_buffer = data_blob_null;
821 in_input_buffer = data_blob_const(cli_nps->write.buf,
824 subreq = smb2cli_ioctl_send(state, state->ev,
826 cli_nps->cli->timeout,
827 cli_nps->cli->smb2.session,
828 cli_nps->cli->smb2.tcon,
829 cli_nps->fid_persistent,
830 cli_nps->fid_volatile,
831 FSCTL_NAMED_PIPE_READ_WRITE,
832 0, /* in_max_input_length */
834 /* in_max_output_length */
835 TSTREAM_CLI_NP_MAX_BUF_SIZE,
837 SMB2_IOCTL_FLAG_IS_FSCTL);
839 if (tevent_req_nomem(subreq, req)) {
842 tevent_req_set_callback(subreq,
843 tstream_cli_np_readv_trans_done,
847 static void tstream_cli_np_readv_disconnect_now(struct tevent_req *req,
849 const char *location);
850 static void tstream_cli_np_readv_trans_next(struct tevent_context *ctx,
851 struct tevent_immediate *im,
854 static void tstream_cli_np_readv_trans_done(struct tevent_req *subreq)
856 struct tevent_req *req =
857 tevent_req_callback_data(subreq, struct tevent_req);
858 struct tstream_cli_np_readv_state *state =
859 tevent_req_data(req, struct tstream_cli_np_readv_state);
860 struct tstream_cli_np *cli_nps =
861 tstream_context_data(state->stream, struct tstream_cli_np);
866 if (cli_nps->is_smb1) {
867 status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
869 &rcvbuf, 0, &received);
871 DATA_BLOB out_input_buffer = data_blob_null;
872 DATA_BLOB out_output_buffer = data_blob_null;
874 status = smb2cli_ioctl_recv(subreq, state,
878 /* Note that rcvbuf is not a talloc pointer here */
879 rcvbuf = out_output_buffer.data;
880 received = out_output_buffer.length;
883 if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
884 status = NT_STATUS_OK;
886 if (!NT_STATUS_IS_OK(status)) {
887 tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
891 if (received > TSTREAM_CLI_NP_MAX_BUF_SIZE) {
892 tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
897 tstream_cli_np_readv_disconnect_now(req, EPIPE, __location__);
901 cli_nps->read.ofs = 0;
902 cli_nps->read.left = received;
903 cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received);
904 if (cli_nps->read.buf == NULL) {
906 tevent_req_nomem(cli_nps->read.buf, req);
909 memcpy(cli_nps->read.buf, rcvbuf, received);
911 if (cli_nps->trans.write_req == NULL) {
912 tstream_cli_np_readv_read_next(req);
916 tevent_schedule_immediate(state->trans.im, state->ev,
917 tstream_cli_np_readv_trans_next, req);
919 tevent_req_done(cli_nps->trans.write_req);
922 static void tstream_cli_np_readv_trans_next(struct tevent_context *ctx,
923 struct tevent_immediate *im,
926 struct tevent_req *req =
927 talloc_get_type_abort(private_data,
930 tstream_cli_np_readv_read_next(req);
933 static void tstream_cli_np_readv_read_done(struct tevent_req *subreq)
935 struct tevent_req *req =
936 tevent_req_callback_data(subreq, struct tevent_req);
937 struct tstream_cli_np_readv_state *state =
938 tevent_req_data(req, struct tstream_cli_np_readv_state);
939 struct tstream_cli_np *cli_nps =
940 tstream_context_data(state->stream, struct tstream_cli_np);
946 * We must free subreq in this function as there is
947 * a timer event attached to it.
950 if (cli_nps->is_smb1) {
951 status = cli_read_andx_recv(subreq, &received, &rcvbuf);
953 uint32_t data_length = 0;
954 status = smb2cli_read_recv(subreq, state, &rcvbuf, &data_length);
955 received = data_length;
958 * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
961 if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
963 * NT_STATUS_BUFFER_TOO_SMALL means that there's
964 * more data to read when the named pipe is used
965 * in message mode (which is the case here).
967 * But we hide this from the caller.
969 status = NT_STATUS_OK;
971 if (!NT_STATUS_IS_OK(status)) {
973 tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
977 if (received > TSTREAM_CLI_NP_MAX_BUF_SIZE) {
979 tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
985 tstream_cli_np_readv_disconnect_now(req, EPIPE, __location__);
989 cli_nps->read.ofs = 0;
990 cli_nps->read.left = received;
991 cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received);
992 if (cli_nps->read.buf == NULL) {
994 tevent_req_nomem(cli_nps->read.buf, req);
997 memcpy(cli_nps->read.buf, rcvbuf, received);
1000 tstream_cli_np_readv_read_next(req);
1003 static void tstream_cli_np_readv_disconnect_done(struct tevent_req *subreq);
1005 static void tstream_cli_np_readv_error(struct tevent_req *req);
1007 static void tstream_cli_np_readv_disconnect_now(struct tevent_req *req,
1009 const char *location)
1011 struct tstream_cli_np_readv_state *state =
1012 tevent_req_data(req,
1013 struct tstream_cli_np_readv_state);
1014 struct tstream_cli_np *cli_nps =
1015 tstream_context_data(state->stream,
1016 struct tstream_cli_np);
1017 struct tevent_req *subreq;
1019 state->error.val = error;
1020 state->error.location = location;
1022 if (!cli_state_is_connected(cli_nps->cli)) {
1023 /* return the original error */
1024 tstream_cli_np_readv_error(req);
1028 if (cli_nps->is_smb1) {
1029 subreq = cli_close_send(state, state->ev, cli_nps->cli,
1032 subreq = smb2cli_close_send(state, state->ev,
1034 cli_nps->cli->timeout,
1035 cli_nps->cli->smb2.session,
1036 cli_nps->cli->smb2.tcon,
1038 cli_nps->fid_persistent,
1039 cli_nps->fid_volatile);
1041 if (subreq == NULL) {
1042 /* return the original error */
1043 tstream_cli_np_readv_error(req);
1046 tevent_req_set_callback(subreq,
1047 tstream_cli_np_readv_disconnect_done,
1051 static void tstream_cli_np_readv_disconnect_done(struct tevent_req *subreq)
1053 struct tevent_req *req =
1054 tevent_req_callback_data(subreq, struct tevent_req);
1055 struct tstream_cli_np_readv_state *state =
1056 tevent_req_data(req, struct tstream_cli_np_readv_state);
1057 struct tstream_cli_np *cli_nps =
1058 tstream_context_data(state->stream, struct tstream_cli_np);
1060 if (cli_nps->is_smb1) {
1061 cli_close_recv(subreq);
1063 smb2cli_close_recv(subreq);
1065 TALLOC_FREE(subreq);
1067 cli_nps->cli = NULL;
1069 tstream_cli_np_readv_error(req);
1072 static void tstream_cli_np_readv_error_trigger(struct tevent_context *ctx,
1073 struct tevent_immediate *im,
1074 void *private_data);
1076 static void tstream_cli_np_readv_error(struct tevent_req *req)
1078 struct tstream_cli_np_readv_state *state =
1079 tevent_req_data(req,
1080 struct tstream_cli_np_readv_state);
1081 struct tstream_cli_np *cli_nps =
1082 tstream_context_data(state->stream,
1083 struct tstream_cli_np);
1085 if (cli_nps->trans.write_req == NULL) {
1086 /* return the original error */
1087 _tevent_req_error(req, state->error.val, state->error.location);
1091 if (state->trans.im == NULL) {
1092 /* return the original error */
1093 _tevent_req_error(req, state->error.val, state->error.location);
1097 tevent_schedule_immediate(state->trans.im, state->ev,
1098 tstream_cli_np_readv_error_trigger, req);
1100 /* return the original error for writev */
1101 _tevent_req_error(cli_nps->trans.write_req,
1102 state->error.val, state->error.location);
1105 static void tstream_cli_np_readv_error_trigger(struct tevent_context *ctx,
1106 struct tevent_immediate *im,
1109 struct tevent_req *req =
1110 talloc_get_type_abort(private_data,
1112 struct tstream_cli_np_readv_state *state =
1113 tevent_req_data(req,
1114 struct tstream_cli_np_readv_state);
1116 /* return the original error */
1117 _tevent_req_error(req, state->error.val, state->error.location);
1120 static int tstream_cli_np_readv_recv(struct tevent_req *req,
1123 struct tstream_cli_np_readv_state *state =
1124 tevent_req_data(req, struct tstream_cli_np_readv_state);
1127 ret = tsocket_simple_int_recv(req, perrno);
1132 tevent_req_received(req);
1136 struct tstream_cli_np_disconnect_state {
1137 struct tstream_context *stream;
1140 static void tstream_cli_np_disconnect_done(struct tevent_req *subreq);
1142 static struct tevent_req *tstream_cli_np_disconnect_send(TALLOC_CTX *mem_ctx,
1143 struct tevent_context *ev,
1144 struct tstream_context *stream)
1146 struct tstream_cli_np *cli_nps = tstream_context_data(stream,
1147 struct tstream_cli_np);
1148 struct tevent_req *req;
1149 struct tstream_cli_np_disconnect_state *state;
1150 struct tevent_req *subreq;
1152 req = tevent_req_create(mem_ctx, &state,
1153 struct tstream_cli_np_disconnect_state);
1158 state->stream = stream;
1160 if (!cli_state_is_connected(cli_nps->cli)) {
1161 tevent_req_error(req, ENOTCONN);
1162 return tevent_req_post(req, ev);
1165 if (cli_nps->is_smb1) {
1166 subreq = cli_close_send(state, ev, cli_nps->cli,
1169 subreq = smb2cli_close_send(state, ev, cli_nps->cli->conn,
1170 cli_nps->cli->timeout,
1171 cli_nps->cli->smb2.session,
1172 cli_nps->cli->smb2.tcon,
1174 cli_nps->fid_persistent,
1175 cli_nps->fid_volatile);
1177 if (tevent_req_nomem(subreq, req)) {
1178 return tevent_req_post(req, ev);
1180 tevent_req_set_callback(subreq, tstream_cli_np_disconnect_done, req);
1185 static void tstream_cli_np_disconnect_done(struct tevent_req *subreq)
1187 struct tevent_req *req = tevent_req_callback_data(subreq,
1189 struct tstream_cli_np_disconnect_state *state =
1190 tevent_req_data(req, struct tstream_cli_np_disconnect_state);
1191 struct tstream_cli_np *cli_nps =
1192 tstream_context_data(state->stream, struct tstream_cli_np);
1195 if (cli_nps->is_smb1) {
1196 status = cli_close_recv(subreq);
1198 status = smb2cli_close_recv(subreq);
1200 TALLOC_FREE(subreq);
1201 if (!NT_STATUS_IS_OK(status)) {
1202 tevent_req_error(req, EIO);
1206 cli_nps->cli = NULL;
1208 tevent_req_done(req);
1211 static int tstream_cli_np_disconnect_recv(struct tevent_req *req,
1216 ret = tsocket_simple_int_recv(req, perrno);
1218 tevent_req_received(req);
1222 static const struct tstream_context_ops tstream_cli_np_ops = {
1225 .pending_bytes = tstream_cli_np_pending_bytes,
1227 .readv_send = tstream_cli_np_readv_send,
1228 .readv_recv = tstream_cli_np_readv_recv,
1230 .writev_send = tstream_cli_np_writev_send,
1231 .writev_recv = tstream_cli_np_writev_recv,
1233 .disconnect_send = tstream_cli_np_disconnect_send,
1234 .disconnect_recv = tstream_cli_np_disconnect_recv,