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 "../lib/util/tevent_ntstatus.h"
23 #include "../lib/tsocket/tsocket.h"
24 #include "../lib/tsocket/tsocket_internal.h"
25 #include "smb_common.h"
26 #include "smbXcli_base.h"
27 #include "tstream_smbXcli_np.h"
28 #include "libcli/security/security.h"
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 #define TSTREAM_CLI_NP_DESIRED_ACCESS ( \
53 SEC_STD_READ_CONTROL | \
54 SEC_FILE_READ_DATA | \
55 SEC_FILE_WRITE_DATA | \
56 SEC_FILE_APPEND_DATA | \
59 SEC_FILE_READ_ATTRIBUTE | \
60 SEC_FILE_WRITE_ATTRIBUTE | \
63 struct tstream_cli_np_ref;
65 struct tstream_cli_np {
66 struct tstream_cli_np_ref *ref;
67 struct smbXcli_conn *conn;
68 struct smbXcli_session *session;
69 struct smbXcli_tcon *tcon;
76 uint64_t fid_persistent;
77 uint64_t fid_volatile;
81 struct tevent_req *read_req;
82 struct tevent_req *write_req;
93 struct tstream_cli_np_ref {
94 struct tstream_cli_np *cli_nps;
97 static int tstream_cli_np_destructor(struct tstream_cli_np *cli_nps)
101 if (cli_nps->ref != NULL) {
102 cli_nps->ref->cli_nps = NULL;
103 TALLOC_FREE(cli_nps->ref);
106 if (!smbXcli_conn_is_connected(cli_nps->conn)) {
111 * TODO: do not use a sync call with a destructor!!!
113 * This only happens, if a caller does talloc_free(),
114 * while the everything was still ok.
116 * If we get an unexpected failure within a normal
117 * operation, we already do an async cli_close_send()/_recv().
119 * Once we've fixed all callers to call
120 * tstream_disconnect_send()/_recv(), this will
123 if (cli_nps->is_smb1) {
124 status = smb1cli_close(cli_nps->conn,
129 cli_nps->fnum, UINT32_MAX);
131 status = smb2cli_close(cli_nps->conn,
136 cli_nps->fid_persistent,
137 cli_nps->fid_volatile);
139 if (!NT_STATUS_IS_OK(status)) {
140 DEBUG(1, ("tstream_cli_np_destructor: cli_close "
141 "failed on pipe %s. Error was %s\n",
142 cli_nps->npipe, nt_errstr(status)));
145 * We can't do much on failure
150 static int tstream_cli_np_ref_destructor(struct tstream_cli_np_ref *ref)
152 if (ref->cli_nps == NULL) {
156 ref->cli_nps->conn = NULL;
157 ref->cli_nps->session = NULL;
158 ref->cli_nps->tcon = NULL;
159 ref->cli_nps->ref = NULL;
164 struct tstream_cli_np_open_state {
165 struct smbXcli_conn *conn;
166 struct smbXcli_session *session;
167 struct smbXcli_tcon *tcon;
169 unsigned int timeout;
173 uint64_t fid_persistent;
174 uint64_t fid_volatile;
178 static void tstream_cli_np_open_done(struct tevent_req *subreq);
180 struct tevent_req *tstream_cli_np_open_send(TALLOC_CTX *mem_ctx,
181 struct tevent_context *ev,
182 struct smbXcli_conn *conn,
183 struct smbXcli_session *session,
184 struct smbXcli_tcon *tcon,
185 uint16_t pid, unsigned int timeout,
188 struct tevent_req *req;
189 struct tstream_cli_np_open_state *state;
190 struct tevent_req *subreq;
192 req = tevent_req_create(mem_ctx, &state,
193 struct tstream_cli_np_open_state);
199 state->session = session;
201 state->timeout = timeout;
203 state->npipe = talloc_strdup(state, npipe);
204 if (tevent_req_nomem(state->npipe, req)) {
205 return tevent_req_post(req, ev);
208 if (smbXcli_conn_protocol(conn) < PROTOCOL_SMB2_02) {
209 state->is_smb1 = true;
212 if (state->is_smb1) {
213 const char *smb1_npipe;
216 * Windows and newer Samba versions allow
217 * the pipe name without leading backslash,
218 * but we should better behave like windows clients
220 smb1_npipe = talloc_asprintf(state, "\\%s", state->npipe);
221 if (tevent_req_nomem(smb1_npipe, req)) {
222 return tevent_req_post(req, ev);
224 subreq = smb1cli_ntcreatex_send(state, ev, state->conn,
231 0, /* RootDirectoryFid */
232 TSTREAM_CLI_NP_DESIRED_ACCESS,
233 0, /* AllocationSize */
234 0, /* FileAttributes */
235 FILE_SHARE_READ|FILE_SHARE_WRITE,
236 FILE_OPEN, /* CreateDisposition */
237 0, /* CreateOptions */
238 2, /* NTCREATEX_IMPERSONATION_IMPERSONATION */
239 0); /* SecurityFlags */
241 subreq = smb2cli_create_send(state, ev, state->conn,
242 state->timeout, state->session,
245 SMB2_OPLOCK_LEVEL_NONE,
246 SMB2_IMPERSONATION_IMPERSONATION,
247 TSTREAM_CLI_NP_DESIRED_ACCESS,
248 0, /* file_attributes */
249 FILE_SHARE_READ|FILE_SHARE_WRITE,
251 0, /* create_options */
254 if (tevent_req_nomem(subreq, req)) {
255 return tevent_req_post(req, ev);
257 tevent_req_set_callback(subreq, tstream_cli_np_open_done, req);
262 static void tstream_cli_np_open_done(struct tevent_req *subreq)
264 struct tevent_req *req =
265 tevent_req_callback_data(subreq, struct tevent_req);
266 struct tstream_cli_np_open_state *state =
267 tevent_req_data(req, struct tstream_cli_np_open_state);
270 if (state->is_smb1) {
271 status = smb1cli_ntcreatex_recv(subreq, &state->fnum);
273 status = smb2cli_create_recv(subreq,
274 &state->fid_persistent,
275 &state->fid_volatile,
279 if (!NT_STATUS_IS_OK(status)) {
280 tevent_req_nterror(req, status);
284 tevent_req_done(req);
287 NTSTATUS _tstream_cli_np_open_recv(struct tevent_req *req,
289 struct tstream_context **_stream,
290 const char *location)
292 struct tstream_cli_np_open_state *state =
293 tevent_req_data(req, struct tstream_cli_np_open_state);
294 struct tstream_context *stream;
295 struct tstream_cli_np *cli_nps;
298 if (tevent_req_is_nterror(req, &status)) {
299 tevent_req_received(req);
303 stream = tstream_context_create(mem_ctx,
306 struct tstream_cli_np,
309 tevent_req_received(req);
310 return NT_STATUS_NO_MEMORY;
312 ZERO_STRUCTP(cli_nps);
314 cli_nps->ref = talloc_zero(state->conn, struct tstream_cli_np_ref);
315 if (cli_nps->ref == NULL) {
316 TALLOC_FREE(cli_nps);
317 tevent_req_received(req);
318 return NT_STATUS_NO_MEMORY;
320 cli_nps->ref->cli_nps = cli_nps;
321 cli_nps->conn = state->conn;
322 cli_nps->session = state->session;
323 cli_nps->tcon = state->tcon;
324 cli_nps->pid = state->pid;
325 cli_nps->timeout = state->timeout;
326 cli_nps->npipe = talloc_move(cli_nps, &state->npipe);
327 cli_nps->is_smb1 = state->is_smb1;
328 cli_nps->fnum = state->fnum;
329 cli_nps->fid_persistent = state->fid_persistent;
330 cli_nps->fid_volatile = state->fid_volatile;
332 talloc_set_destructor(cli_nps, tstream_cli_np_destructor);
333 talloc_set_destructor(cli_nps->ref, tstream_cli_np_ref_destructor);
335 cli_nps->trans.active = false;
336 cli_nps->trans.read_req = NULL;
337 cli_nps->trans.write_req = NULL;
338 SSVAL(cli_nps->trans.setup+0, 0, TRANSACT_DCERPCCMD);
339 SSVAL(cli_nps->trans.setup+1, 0, cli_nps->fnum);
342 tevent_req_received(req);
346 static ssize_t tstream_cli_np_pending_bytes(struct tstream_context *stream)
348 struct tstream_cli_np *cli_nps = tstream_context_data(stream,
349 struct tstream_cli_np);
351 if (!smbXcli_conn_is_connected(cli_nps->conn)) {
356 return cli_nps->read.left;
359 bool tstream_is_cli_np(struct tstream_context *stream)
361 struct tstream_cli_np *cli_nps =
362 talloc_get_type(_tstream_context_data(stream),
363 struct tstream_cli_np);
372 NTSTATUS tstream_cli_np_use_trans(struct tstream_context *stream)
374 struct tstream_cli_np *cli_nps = tstream_context_data(stream,
375 struct tstream_cli_np);
377 if (cli_nps->trans.read_req) {
378 return NT_STATUS_PIPE_BUSY;
381 if (cli_nps->trans.write_req) {
382 return NT_STATUS_PIPE_BUSY;
385 if (cli_nps->trans.active) {
386 return NT_STATUS_PIPE_BUSY;
389 cli_nps->trans.active = true;
394 unsigned int tstream_cli_np_set_timeout(struct tstream_context *stream,
395 unsigned int timeout)
397 struct tstream_cli_np *cli_nps = tstream_context_data(stream,
398 struct tstream_cli_np);
399 unsigned int old_timeout = cli_nps->timeout;
401 cli_nps->timeout = timeout;
405 struct tstream_cli_np_writev_state {
406 struct tstream_context *stream;
407 struct tevent_context *ev;
409 struct iovec *vector;
416 const char *location;
420 static int tstream_cli_np_writev_state_destructor(struct tstream_cli_np_writev_state *state)
422 struct tstream_cli_np *cli_nps =
423 tstream_context_data(state->stream,
424 struct tstream_cli_np);
426 cli_nps->trans.write_req = NULL;
431 static void tstream_cli_np_writev_write_next(struct tevent_req *req);
433 static struct tevent_req *tstream_cli_np_writev_send(TALLOC_CTX *mem_ctx,
434 struct tevent_context *ev,
435 struct tstream_context *stream,
436 const struct iovec *vector,
439 struct tevent_req *req;
440 struct tstream_cli_np_writev_state *state;
441 struct tstream_cli_np *cli_nps = tstream_context_data(stream,
442 struct tstream_cli_np);
444 req = tevent_req_create(mem_ctx, &state,
445 struct tstream_cli_np_writev_state);
449 state->stream = stream;
453 talloc_set_destructor(state, tstream_cli_np_writev_state_destructor);
455 if (!smbXcli_conn_is_connected(cli_nps->conn)) {
456 tevent_req_error(req, ENOTCONN);
457 return tevent_req_post(req, ev);
461 * we make a copy of the vector so we can change the structure
463 state->vector = talloc_array(state, struct iovec, count);
464 if (tevent_req_nomem(state->vector, req)) {
465 return tevent_req_post(req, ev);
467 memcpy(state->vector, vector, sizeof(struct iovec) * count);
468 state->count = count;
470 tstream_cli_np_writev_write_next(req);
471 if (!tevent_req_is_in_progress(req)) {
472 return tevent_req_post(req, ev);
478 static void tstream_cli_np_readv_trans_start(struct tevent_req *req);
479 static void tstream_cli_np_writev_write_done(struct tevent_req *subreq);
481 static void tstream_cli_np_writev_write_next(struct tevent_req *req)
483 struct tstream_cli_np_writev_state *state =
485 struct tstream_cli_np_writev_state);
486 struct tstream_cli_np *cli_nps =
487 tstream_context_data(state->stream,
488 struct tstream_cli_np);
489 struct tevent_req *subreq;
493 for (i=0; i < state->count; i++) {
494 left += state->vector[i].iov_len;
498 TALLOC_FREE(cli_nps->write.buf);
499 tevent_req_done(req);
503 cli_nps->write.ofs = 0;
504 cli_nps->write.left = MIN(left, TSTREAM_CLI_NP_MAX_BUF_SIZE);
505 cli_nps->write.buf = talloc_realloc(cli_nps, cli_nps->write.buf,
506 uint8_t, cli_nps->write.left);
507 if (tevent_req_nomem(cli_nps->write.buf, req)) {
512 * copy the pending buffer first
514 while (cli_nps->write.left > 0 && state->count > 0) {
515 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
516 size_t len = MIN(cli_nps->write.left, state->vector[0].iov_len);
518 memcpy(cli_nps->write.buf + cli_nps->write.ofs, base, len);
521 state->vector[0].iov_base = base;
522 state->vector[0].iov_len -= len;
524 cli_nps->write.ofs += len;
525 cli_nps->write.left -= len;
527 if (state->vector[0].iov_len == 0) {
535 if (cli_nps->trans.active && state->count == 0) {
536 cli_nps->trans.active = false;
537 cli_nps->trans.write_req = req;
541 if (cli_nps->trans.read_req && state->count == 0) {
542 cli_nps->trans.write_req = req;
543 tstream_cli_np_readv_trans_start(cli_nps->trans.read_req);
547 if (cli_nps->is_smb1) {
548 subreq = smb1cli_writex_send(state, state->ev,
555 8, /* 8 means message mode. */
558 cli_nps->write.ofs); /* size */
560 subreq = smb2cli_write_send(state, state->ev,
565 cli_nps->write.ofs, /* length */
567 cli_nps->fid_persistent,
568 cli_nps->fid_volatile,
569 0, /* remaining_bytes */
573 if (tevent_req_nomem(subreq, req)) {
576 tevent_req_set_callback(subreq,
577 tstream_cli_np_writev_write_done,
581 static void tstream_cli_np_writev_disconnect_now(struct tevent_req *req,
583 const char *location);
585 static void tstream_cli_np_writev_write_done(struct tevent_req *subreq)
587 struct tevent_req *req =
588 tevent_req_callback_data(subreq, struct tevent_req);
589 struct tstream_cli_np_writev_state *state =
590 tevent_req_data(req, struct tstream_cli_np_writev_state);
591 struct tstream_cli_np *cli_nps =
592 tstream_context_data(state->stream,
593 struct tstream_cli_np);
597 if (cli_nps->is_smb1) {
598 status = smb1cli_writex_recv(subreq, &written, NULL);
600 status = smb2cli_write_recv(subreq, &written);
603 if (!NT_STATUS_IS_OK(status)) {
604 tstream_cli_np_writev_disconnect_now(req, EIO, __location__);
608 if (written != cli_nps->write.ofs) {
609 tstream_cli_np_writev_disconnect_now(req, EIO, __location__);
613 tstream_cli_np_writev_write_next(req);
616 static void tstream_cli_np_writev_disconnect_done(struct tevent_req *subreq);
618 static void tstream_cli_np_writev_disconnect_now(struct tevent_req *req,
620 const char *location)
622 struct tstream_cli_np_writev_state *state =
624 struct tstream_cli_np_writev_state);
625 struct tstream_cli_np *cli_nps =
626 tstream_context_data(state->stream,
627 struct tstream_cli_np);
628 struct tevent_req *subreq;
630 state->error.val = error;
631 state->error.location = location;
633 if (!smbXcli_conn_is_connected(cli_nps->conn)) {
634 /* return the original error */
635 _tevent_req_error(req, state->error.val, state->error.location);
639 if (cli_nps->is_smb1) {
640 subreq = smb1cli_close_send(state, state->ev,
646 cli_nps->fnum, UINT32_MAX);
648 subreq = smb2cli_close_send(state, state->ev,
654 cli_nps->fid_persistent,
655 cli_nps->fid_volatile);
657 if (subreq == NULL) {
658 /* return the original error */
659 _tevent_req_error(req, state->error.val, state->error.location);
662 tevent_req_set_callback(subreq,
663 tstream_cli_np_writev_disconnect_done,
667 static void tstream_cli_np_writev_disconnect_done(struct tevent_req *subreq)
669 struct tevent_req *req =
670 tevent_req_callback_data(subreq, struct tevent_req);
671 struct tstream_cli_np_writev_state *state =
672 tevent_req_data(req, struct tstream_cli_np_writev_state);
673 struct tstream_cli_np *cli_nps =
674 tstream_context_data(state->stream, struct tstream_cli_np);
676 if (cli_nps->is_smb1) {
677 smb1cli_close_recv(subreq);
679 smb2cli_close_recv(subreq);
683 cli_nps->conn = NULL;
684 cli_nps->tcon = NULL;
685 cli_nps->session = NULL;
687 /* return the original error */
688 _tevent_req_error(req, state->error.val, state->error.location);
691 static int tstream_cli_np_writev_recv(struct tevent_req *req,
694 struct tstream_cli_np_writev_state *state =
696 struct tstream_cli_np_writev_state);
699 ret = tsocket_simple_int_recv(req, perrno);
704 tevent_req_received(req);
708 struct tstream_cli_np_readv_state {
709 struct tstream_context *stream;
710 struct tevent_context *ev;
712 struct iovec *vector;
718 struct tevent_immediate *im;
723 const char *location;
727 static int tstream_cli_np_readv_state_destructor(struct tstream_cli_np_readv_state *state)
729 struct tstream_cli_np *cli_nps =
730 tstream_context_data(state->stream,
731 struct tstream_cli_np);
733 cli_nps->trans.read_req = NULL;
738 static void tstream_cli_np_readv_read_next(struct tevent_req *req);
740 static struct tevent_req *tstream_cli_np_readv_send(TALLOC_CTX *mem_ctx,
741 struct tevent_context *ev,
742 struct tstream_context *stream,
743 struct iovec *vector,
746 struct tevent_req *req;
747 struct tstream_cli_np_readv_state *state;
748 struct tstream_cli_np *cli_nps =
749 tstream_context_data(stream, struct tstream_cli_np);
751 req = tevent_req_create(mem_ctx, &state,
752 struct tstream_cli_np_readv_state);
756 state->stream = stream;
760 talloc_set_destructor(state, tstream_cli_np_readv_state_destructor);
762 if (!smbXcli_conn_is_connected(cli_nps->conn)) {
763 tevent_req_error(req, ENOTCONN);
764 return tevent_req_post(req, ev);
768 * we make a copy of the vector so we can change the structure
770 state->vector = talloc_array(state, struct iovec, count);
771 if (tevent_req_nomem(state->vector, req)) {
772 return tevent_req_post(req, ev);
774 memcpy(state->vector, vector, sizeof(struct iovec) * count);
775 state->count = count;
777 tstream_cli_np_readv_read_next(req);
778 if (!tevent_req_is_in_progress(req)) {
779 return tevent_req_post(req, ev);
785 static void tstream_cli_np_readv_read_done(struct tevent_req *subreq);
787 static void tstream_cli_np_readv_read_next(struct tevent_req *req)
789 struct tstream_cli_np_readv_state *state =
791 struct tstream_cli_np_readv_state);
792 struct tstream_cli_np *cli_nps =
793 tstream_context_data(state->stream,
794 struct tstream_cli_np);
795 struct tevent_req *subreq;
798 * copy the pending buffer first
800 while (cli_nps->read.left > 0 && state->count > 0) {
801 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
802 size_t len = MIN(cli_nps->read.left, state->vector[0].iov_len);
804 memcpy(base, cli_nps->read.buf + cli_nps->read.ofs, len);
807 state->vector[0].iov_base = base;
808 state->vector[0].iov_len -= len;
810 cli_nps->read.ofs += len;
811 cli_nps->read.left -= len;
813 if (state->vector[0].iov_len == 0) {
821 if (cli_nps->read.left == 0) {
822 TALLOC_FREE(cli_nps->read.buf);
825 if (state->count == 0) {
826 tevent_req_done(req);
830 if (cli_nps->trans.active) {
831 cli_nps->trans.active = false;
832 cli_nps->trans.read_req = req;
836 if (cli_nps->trans.write_req) {
837 cli_nps->trans.read_req = req;
838 tstream_cli_np_readv_trans_start(req);
842 if (cli_nps->is_smb1) {
843 subreq = smb1cli_readx_send(state, state->ev,
851 TSTREAM_CLI_NP_MAX_BUF_SIZE);
853 subreq = smb2cli_read_send(state, state->ev,
858 TSTREAM_CLI_NP_MAX_BUF_SIZE, /* length */
860 cli_nps->fid_persistent,
861 cli_nps->fid_volatile,
862 0, /* minimum_count */
863 0); /* remaining_bytes */
865 if (tevent_req_nomem(subreq, req)) {
868 tevent_req_set_callback(subreq,
869 tstream_cli_np_readv_read_done,
873 static void tstream_cli_np_readv_trans_done(struct tevent_req *subreq);
875 static void tstream_cli_np_readv_trans_start(struct tevent_req *req)
877 struct tstream_cli_np_readv_state *state =
879 struct tstream_cli_np_readv_state);
880 struct tstream_cli_np *cli_nps =
881 tstream_context_data(state->stream,
882 struct tstream_cli_np);
883 struct tevent_req *subreq;
885 state->trans.im = tevent_create_immediate(state);
886 if (tevent_req_nomem(state->trans.im, req)) {
890 if (cli_nps->is_smb1) {
891 subreq = smb1cli_trans_send(state, state->ev,
892 cli_nps->conn, SMBtrans,
901 cli_nps->trans.setup, 2,
906 TSTREAM_CLI_NP_MAX_BUF_SIZE);
908 DATA_BLOB in_input_buffer = data_blob_null;
909 DATA_BLOB in_output_buffer = data_blob_null;
911 in_input_buffer = data_blob_const(cli_nps->write.buf,
914 subreq = smb2cli_ioctl_send(state, state->ev,
919 cli_nps->fid_persistent,
920 cli_nps->fid_volatile,
921 FSCTL_NAMED_PIPE_READ_WRITE,
922 0, /* in_max_input_length */
924 /* in_max_output_length */
925 TSTREAM_CLI_NP_MAX_BUF_SIZE,
927 SMB2_IOCTL_FLAG_IS_FSCTL);
929 if (tevent_req_nomem(subreq, req)) {
932 tevent_req_set_callback(subreq,
933 tstream_cli_np_readv_trans_done,
937 static void tstream_cli_np_readv_disconnect_now(struct tevent_req *req,
939 const char *location);
940 static void tstream_cli_np_readv_trans_next(struct tevent_context *ctx,
941 struct tevent_immediate *im,
944 static void tstream_cli_np_readv_trans_done(struct tevent_req *subreq)
946 struct tevent_req *req =
947 tevent_req_callback_data(subreq, struct tevent_req);
948 struct tstream_cli_np_readv_state *state =
949 tevent_req_data(req, struct tstream_cli_np_readv_state);
950 struct tstream_cli_np *cli_nps =
951 tstream_context_data(state->stream, struct tstream_cli_np);
956 if (cli_nps->is_smb1) {
957 status = smb1cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
959 &rcvbuf, 0, &received);
961 DATA_BLOB out_input_buffer = data_blob_null;
962 DATA_BLOB out_output_buffer = data_blob_null;
964 status = smb2cli_ioctl_recv(subreq, state,
968 /* Note that rcvbuf is not a talloc pointer here */
969 rcvbuf = out_output_buffer.data;
970 received = out_output_buffer.length;
973 if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
974 status = NT_STATUS_OK;
976 if (!NT_STATUS_IS_OK(status)) {
977 tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
981 if (received > TSTREAM_CLI_NP_MAX_BUF_SIZE) {
982 tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
987 tstream_cli_np_readv_disconnect_now(req, EPIPE, __location__);
991 cli_nps->read.ofs = 0;
992 cli_nps->read.left = received;
993 cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received);
994 if (cli_nps->read.buf == NULL) {
996 tevent_req_nomem(cli_nps->read.buf, req);
999 memcpy(cli_nps->read.buf, rcvbuf, received);
1001 if (cli_nps->trans.write_req == NULL) {
1002 tstream_cli_np_readv_read_next(req);
1006 tevent_schedule_immediate(state->trans.im, state->ev,
1007 tstream_cli_np_readv_trans_next, req);
1009 tevent_req_done(cli_nps->trans.write_req);
1012 static void tstream_cli_np_readv_trans_next(struct tevent_context *ctx,
1013 struct tevent_immediate *im,
1016 struct tevent_req *req =
1017 talloc_get_type_abort(private_data,
1020 tstream_cli_np_readv_read_next(req);
1023 static void tstream_cli_np_readv_read_done(struct tevent_req *subreq)
1025 struct tevent_req *req =
1026 tevent_req_callback_data(subreq, struct tevent_req);
1027 struct tstream_cli_np_readv_state *state =
1028 tevent_req_data(req, struct tstream_cli_np_readv_state);
1029 struct tstream_cli_np *cli_nps =
1030 tstream_context_data(state->stream, struct tstream_cli_np);
1036 * We must free subreq in this function as there is
1037 * a timer event attached to it.
1040 if (cli_nps->is_smb1) {
1041 status = smb1cli_readx_recv(subreq, &received, &rcvbuf);
1043 status = smb2cli_read_recv(subreq, state, &rcvbuf, &received);
1046 * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
1049 if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
1051 * NT_STATUS_BUFFER_TOO_SMALL means that there's
1052 * more data to read when the named pipe is used
1053 * in message mode (which is the case here).
1055 * But we hide this from the caller.
1057 status = NT_STATUS_OK;
1059 if (!NT_STATUS_IS_OK(status)) {
1060 TALLOC_FREE(subreq);
1061 tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
1065 if (received > TSTREAM_CLI_NP_MAX_BUF_SIZE) {
1066 TALLOC_FREE(subreq);
1067 tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
1071 if (received == 0) {
1072 TALLOC_FREE(subreq);
1073 tstream_cli_np_readv_disconnect_now(req, EPIPE, __location__);
1077 cli_nps->read.ofs = 0;
1078 cli_nps->read.left = received;
1079 cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received);
1080 if (cli_nps->read.buf == NULL) {
1081 TALLOC_FREE(subreq);
1082 tevent_req_nomem(cli_nps->read.buf, req);
1085 memcpy(cli_nps->read.buf, rcvbuf, received);
1086 TALLOC_FREE(subreq);
1088 tstream_cli_np_readv_read_next(req);
1091 static void tstream_cli_np_readv_disconnect_done(struct tevent_req *subreq);
1093 static void tstream_cli_np_readv_error(struct tevent_req *req);
1095 static void tstream_cli_np_readv_disconnect_now(struct tevent_req *req,
1097 const char *location)
1099 struct tstream_cli_np_readv_state *state =
1100 tevent_req_data(req,
1101 struct tstream_cli_np_readv_state);
1102 struct tstream_cli_np *cli_nps =
1103 tstream_context_data(state->stream,
1104 struct tstream_cli_np);
1105 struct tevent_req *subreq;
1107 state->error.val = error;
1108 state->error.location = location;
1110 if (!smbXcli_conn_is_connected(cli_nps->conn)) {
1111 /* return the original error */
1112 tstream_cli_np_readv_error(req);
1116 if (cli_nps->is_smb1) {
1117 subreq = smb1cli_close_send(state, state->ev,
1123 cli_nps->fnum, UINT32_MAX);
1125 subreq = smb2cli_close_send(state, state->ev,
1131 cli_nps->fid_persistent,
1132 cli_nps->fid_volatile);
1134 if (subreq == NULL) {
1135 /* return the original error */
1136 tstream_cli_np_readv_error(req);
1139 tevent_req_set_callback(subreq,
1140 tstream_cli_np_readv_disconnect_done,
1144 static void tstream_cli_np_readv_disconnect_done(struct tevent_req *subreq)
1146 struct tevent_req *req =
1147 tevent_req_callback_data(subreq, struct tevent_req);
1148 struct tstream_cli_np_readv_state *state =
1149 tevent_req_data(req, struct tstream_cli_np_readv_state);
1150 struct tstream_cli_np *cli_nps =
1151 tstream_context_data(state->stream, struct tstream_cli_np);
1153 if (cli_nps->is_smb1) {
1154 smb1cli_close_recv(subreq);
1156 smb2cli_close_recv(subreq);
1158 TALLOC_FREE(subreq);
1160 cli_nps->conn = NULL;
1161 cli_nps->session = NULL;
1162 cli_nps->tcon = NULL;
1164 tstream_cli_np_readv_error(req);
1167 static void tstream_cli_np_readv_error_trigger(struct tevent_context *ctx,
1168 struct tevent_immediate *im,
1169 void *private_data);
1171 static void tstream_cli_np_readv_error(struct tevent_req *req)
1173 struct tstream_cli_np_readv_state *state =
1174 tevent_req_data(req,
1175 struct tstream_cli_np_readv_state);
1176 struct tstream_cli_np *cli_nps =
1177 tstream_context_data(state->stream,
1178 struct tstream_cli_np);
1180 if (cli_nps->trans.write_req == NULL) {
1181 /* return the original error */
1182 _tevent_req_error(req, state->error.val, state->error.location);
1186 if (state->trans.im == NULL) {
1187 /* return the original error */
1188 _tevent_req_error(req, state->error.val, state->error.location);
1192 tevent_schedule_immediate(state->trans.im, state->ev,
1193 tstream_cli_np_readv_error_trigger, req);
1195 /* return the original error for writev */
1196 _tevent_req_error(cli_nps->trans.write_req,
1197 state->error.val, state->error.location);
1200 static void tstream_cli_np_readv_error_trigger(struct tevent_context *ctx,
1201 struct tevent_immediate *im,
1204 struct tevent_req *req =
1205 talloc_get_type_abort(private_data,
1207 struct tstream_cli_np_readv_state *state =
1208 tevent_req_data(req,
1209 struct tstream_cli_np_readv_state);
1211 /* return the original error */
1212 _tevent_req_error(req, state->error.val, state->error.location);
1215 static int tstream_cli_np_readv_recv(struct tevent_req *req,
1218 struct tstream_cli_np_readv_state *state =
1219 tevent_req_data(req, struct tstream_cli_np_readv_state);
1222 ret = tsocket_simple_int_recv(req, perrno);
1227 tevent_req_received(req);
1231 struct tstream_cli_np_disconnect_state {
1232 struct tstream_context *stream;
1235 static void tstream_cli_np_disconnect_done(struct tevent_req *subreq);
1237 static struct tevent_req *tstream_cli_np_disconnect_send(TALLOC_CTX *mem_ctx,
1238 struct tevent_context *ev,
1239 struct tstream_context *stream)
1241 struct tstream_cli_np *cli_nps = tstream_context_data(stream,
1242 struct tstream_cli_np);
1243 struct tevent_req *req;
1244 struct tstream_cli_np_disconnect_state *state;
1245 struct tevent_req *subreq;
1247 req = tevent_req_create(mem_ctx, &state,
1248 struct tstream_cli_np_disconnect_state);
1253 state->stream = stream;
1255 if (!smbXcli_conn_is_connected(cli_nps->conn)) {
1256 tevent_req_error(req, ENOTCONN);
1257 return tevent_req_post(req, ev);
1260 if (cli_nps->is_smb1) {
1261 subreq = smb1cli_close_send(state, ev, cli_nps->conn,
1266 cli_nps->fnum, UINT32_MAX);
1268 subreq = smb2cli_close_send(state, ev, cli_nps->conn,
1273 cli_nps->fid_persistent,
1274 cli_nps->fid_volatile);
1276 if (tevent_req_nomem(subreq, req)) {
1277 return tevent_req_post(req, ev);
1279 tevent_req_set_callback(subreq, tstream_cli_np_disconnect_done, req);
1284 static void tstream_cli_np_disconnect_done(struct tevent_req *subreq)
1286 struct tevent_req *req = tevent_req_callback_data(subreq,
1288 struct tstream_cli_np_disconnect_state *state =
1289 tevent_req_data(req, struct tstream_cli_np_disconnect_state);
1290 struct tstream_cli_np *cli_nps =
1291 tstream_context_data(state->stream, struct tstream_cli_np);
1294 if (cli_nps->is_smb1) {
1295 status = smb1cli_close_recv(subreq);
1297 status = smb2cli_close_recv(subreq);
1299 TALLOC_FREE(subreq);
1300 if (!NT_STATUS_IS_OK(status)) {
1301 tevent_req_error(req, EIO);
1305 cli_nps->conn = NULL;
1306 cli_nps->session = NULL;
1307 cli_nps->tcon = NULL;
1309 tevent_req_done(req);
1312 static int tstream_cli_np_disconnect_recv(struct tevent_req *req,
1317 ret = tsocket_simple_int_recv(req, perrno);
1319 tevent_req_received(req);
1323 static const struct tstream_context_ops tstream_cli_np_ops = {
1326 .pending_bytes = tstream_cli_np_pending_bytes,
1328 .readv_send = tstream_cli_np_readv_send,
1329 .readv_recv = tstream_cli_np_readv_recv,
1331 .writev_send = tstream_cli_np_writev_send,
1332 .writev_recv = tstream_cli_np_writev_recv,
1334 .disconnect_send = tstream_cli_np_disconnect_send,
1335 .disconnect_recv = tstream_cli_np_disconnect_recv,