s4:dlz_bind9: let dlz_bind9 use dns_common_replace()
[Samba.git] / source3 / libsmb / cli_np_tstream.c
blobbf9a0c370a8b8443aaf310fc09791358f2ed83a3
1 /*
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/>.
20 #include "includes.h"
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)
41 * via a SMBreadX.
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;
54 const char *npipe;
55 bool is_smb1;
56 uint16_t fnum;
57 uint64_t fid_persistent;
58 uint64_t fid_volatile;
59 unsigned int default_timeout;
61 struct {
62 bool active;
63 struct tevent_req *read_req;
64 struct tevent_req *write_req;
65 uint16_t setup[2];
66 } trans;
68 struct {
69 off_t ofs;
70 size_t left;
71 uint8_t *buf;
72 } read, write;
75 static int tstream_cli_np_destructor(struct tstream_cli_np *cli_nps)
77 NTSTATUS status;
79 if (!cli_state_is_connected(cli_nps->cli)) {
80 return 0;
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
94 * never be called.
96 if (cli_nps->is_smb1) {
97 status = cli_close(cli_nps->cli, cli_nps->fnum);
98 } else {
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,
103 0, /* flags */
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
115 return 0;
118 struct tstream_cli_np_open_state {
119 struct cli_state *cli;
120 bool is_smb1;
121 uint16_t fnum;
122 uint64_t fid_persistent;
123 uint64_t fid_volatile;
124 const char *npipe;
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,
132 const char *npipe)
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);
140 if (!req) {
141 return NULL;
143 state->cli = cli;
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,
168 smb1_npipe,
170 DESIRED_ACCESS_PIPE,
172 FILE_SHARE_READ|FILE_SHARE_WRITE,
173 FILE_OPEN,
176 } else {
177 subreq = smb2cli_create_send(state, ev, cli->conn,
178 cli->timeout, cli->smb2.session,
179 cli->smb2.tcon,
180 npipe,
181 SMB2_OPLOCK_LEVEL_NONE,
182 SMB2_IMPERSONATION_IMPERSONATION,
183 DESIRED_ACCESS_PIPE,
184 0, /* file_attributes */
185 FILE_SHARE_READ|FILE_SHARE_WRITE,
186 FILE_OPEN,
187 0, /* create_options */
188 NULL); /* blobs */
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);
195 return 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);
204 NTSTATUS status;
206 if (state->is_smb1) {
207 status = cli_ntcreate_recv(subreq, &state->fnum, NULL);
208 } else {
209 status = smb2cli_create_recv(subreq,
210 &state->fid_persistent,
211 &state->fid_volatile,
212 NULL);
214 TALLOC_FREE(subreq);
215 if (!NT_STATUS_IS_OK(status)) {
216 tevent_req_nterror(req, status);
217 return;
220 tevent_req_done(req);
223 NTSTATUS _tstream_cli_np_open_recv(struct tevent_req *req,
224 TALLOC_CTX *mem_ctx,
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;
232 NTSTATUS status;
234 if (tevent_req_is_nterror(req, &status)) {
235 tevent_req_received(req);
236 return status;
239 stream = tstream_context_create(mem_ctx,
240 &tstream_cli_np_ops,
241 &cli_nps,
242 struct tstream_cli_np,
243 location);
244 if (!stream) {
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);
267 *_stream = stream;
268 tevent_req_received(req);
269 return NT_STATUS_OK;
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)) {
278 errno = ENOTCONN;
279 return -1;
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);
291 if (!cli_nps) {
292 return false;
295 return true;
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;
317 return NT_STATUS_OK;
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);
338 return cli_nps->cli;
341 struct tstream_cli_np_writev_state {
342 struct tstream_context *stream;
343 struct tevent_context *ev;
345 struct iovec *vector;
346 size_t count;
348 int ret;
350 struct {
351 int val;
352 const char *location;
353 } error;
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;
364 return 0;
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,
373 size_t count)
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);
382 if (!req) {
383 return NULL;
385 state->stream = stream;
386 state->ev = ev;
387 state->ret = 0;
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);
411 return req;
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 =
420 tevent_req_data(req,
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;
426 size_t i;
427 size_t left = 0;
429 for (i=0; i < state->count; i++) {
430 left += state->vector[i].iov_len;
433 if (left == 0) {
434 TALLOC_FREE(cli_nps->write.buf);
435 tevent_req_done(req);
436 return;
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)) {
444 return;
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);
456 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) {
464 state->vector += 1;
465 state->count -= 1;
468 state->ret += len;
471 if (cli_nps->trans.active && state->count == 0) {
472 cli_nps->trans.active = false;
473 cli_nps->trans.write_req = req;
474 return;
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);
480 return;
483 if (cli_nps->is_smb1) {
484 subreq = cli_write_andx_send(state, state->ev, cli_nps->cli,
485 cli_nps->fnum,
486 8, /* 8 means message mode. */
487 cli_nps->write.buf,
488 0, /* offset */
489 cli_nps->write.ofs); /* size */
490 } else {
491 subreq = smb2cli_write_send(state, state->ev,
492 cli_nps->cli->conn,
493 cli_nps->cli->timeout,
494 cli_nps->cli->smb2.session,
495 cli_nps->cli->smb2.tcon,
496 cli_nps->write.ofs, /* length */
497 0, /* offset */
498 cli_nps->fid_persistent,
499 cli_nps->fid_volatile,
500 0, /* remaining_bytes */
501 0, /* flags */
502 cli_nps->write.buf);
504 if (tevent_req_nomem(subreq, req)) {
505 return;
507 tevent_req_set_callback(subreq,
508 tstream_cli_np_writev_write_done,
509 req);
512 static void tstream_cli_np_writev_disconnect_now(struct tevent_req *req,
513 int error,
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);
525 size_t written;
526 NTSTATUS status;
528 if (cli_nps->is_smb1) {
529 status = cli_write_andx_recv(subreq, &written);
530 } else {
531 uint32_t smb2_written;
532 status = smb2cli_write_recv(subreq, &smb2_written);
533 if (NT_STATUS_IS_OK(status)) {
534 written = smb2_written;
537 TALLOC_FREE(subreq);
538 if (!NT_STATUS_IS_OK(status)) {
539 tstream_cli_np_writev_disconnect_now(req, EIO, __location__);
540 return;
543 if (written != cli_nps->write.ofs) {
544 tstream_cli_np_writev_disconnect_now(req, EIO, __location__);
545 return;
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,
554 int error,
555 const char *location)
557 struct tstream_cli_np_writev_state *state =
558 tevent_req_data(req,
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);
571 return;
574 if (cli_nps->is_smb1) {
575 subreq = cli_close_send(state, state->ev, cli_nps->cli,
576 cli_nps->fnum);
577 } else {
578 subreq = smb2cli_close_send(state, state->ev,
579 cli_nps->cli->conn,
580 cli_nps->cli->timeout,
581 cli_nps->cli->smb2.session,
582 cli_nps->cli->smb2.tcon,
583 0, /* flags */
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);
590 return;
592 tevent_req_set_callback(subreq,
593 tstream_cli_np_writev_disconnect_done,
594 req);
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);
608 } else {
609 smb2cli_close_recv(subreq);
611 TALLOC_FREE(subreq);
613 cli_nps->cli = NULL;
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,
620 int *perrno)
622 struct tstream_cli_np_writev_state *state =
623 tevent_req_data(req,
624 struct tstream_cli_np_writev_state);
625 int ret;
627 ret = tsocket_simple_int_recv(req, perrno);
628 if (ret == 0) {
629 ret = state->ret;
632 tevent_req_received(req);
633 return ret;
636 struct tstream_cli_np_readv_state {
637 struct tstream_context *stream;
638 struct tevent_context *ev;
640 struct iovec *vector;
641 size_t count;
643 int ret;
645 struct {
646 struct tevent_immediate *im;
647 } trans;
649 struct {
650 int val;
651 const char *location;
652 } error;
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;
663 return 0;
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,
672 size_t count)
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);
681 if (!req) {
682 return NULL;
684 state->stream = stream;
685 state->ev = ev;
686 state->ret = 0;
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);
710 return req;
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 =
718 tevent_req_data(req,
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);
734 base += 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) {
742 state->vector += 1;
743 state->count -= 1;
746 state->ret += len;
749 if (cli_nps->read.left == 0) {
750 TALLOC_FREE(cli_nps->read.buf);
753 if (state->count == 0) {
754 tevent_req_done(req);
755 return;
758 if (cli_nps->trans.active) {
759 cli_nps->trans.active = false;
760 cli_nps->trans.read_req = req;
761 return;
764 if (cli_nps->trans.write_req) {
765 cli_nps->trans.read_req = req;
766 tstream_cli_np_readv_trans_start(req);
767 return;
770 if (cli_nps->is_smb1) {
771 subreq = cli_read_andx_send(state, state->ev, cli_nps->cli,
772 cli_nps->fnum,
773 0, /* offset */
774 TSTREAM_CLI_NP_MAX_BUF_SIZE);
775 } else {
776 subreq = smb2cli_read_send(state, state->ev,
777 cli_nps->cli->conn,
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 */
782 0, /* offset */
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)) {
789 return;
791 tevent_req_set_callback(subreq,
792 tstream_cli_np_readv_read_done,
793 req);
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 =
801 tevent_req_data(req,
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)) {
810 return;
813 if (cli_nps->is_smb1) {
814 subreq = cli_trans_send(state, state->ev,
815 cli_nps->cli,
816 SMBtrans,
817 "\\PIPE\\",
818 0, 0, 0,
819 cli_nps->trans.setup, 2,
821 NULL, 0, 0,
822 cli_nps->write.buf,
823 cli_nps->write.ofs,
824 TSTREAM_CLI_NP_MAX_BUF_SIZE);
825 } else {
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,
830 cli_nps->write.ofs);
832 subreq = smb2cli_ioctl_send(state, state->ev,
833 cli_nps->cli->conn,
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 */
841 &in_input_buffer,
842 /* in_max_output_length */
843 TSTREAM_CLI_NP_MAX_BUF_SIZE,
844 &in_output_buffer,
845 SMB2_IOCTL_FLAG_IS_FSCTL);
847 if (tevent_req_nomem(subreq, req)) {
848 return;
850 tevent_req_set_callback(subreq,
851 tstream_cli_np_readv_trans_done,
852 req);
855 static void tstream_cli_np_readv_disconnect_now(struct tevent_req *req,
856 int error,
857 const char *location);
858 static void tstream_cli_np_readv_trans_next(struct tevent_context *ctx,
859 struct tevent_immediate *im,
860 void *private_data);
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);
870 uint8_t *rcvbuf;
871 uint32_t received;
872 NTSTATUS status;
874 if (cli_nps->is_smb1) {
875 status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
876 NULL, 0, NULL,
877 &rcvbuf, 0, &received);
878 } else {
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,
883 &out_input_buffer,
884 &out_output_buffer);
886 /* Note that rcvbuf is not a talloc pointer here */
887 rcvbuf = out_output_buffer.data;
888 received = out_output_buffer.length;
890 TALLOC_FREE(subreq);
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__);
896 return;
899 if (received > TSTREAM_CLI_NP_MAX_BUF_SIZE) {
900 tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
901 return;
904 if (received == 0) {
905 tstream_cli_np_readv_disconnect_now(req, EPIPE, __location__);
906 return;
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) {
913 TALLOC_FREE(subreq);
914 tevent_req_nomem(cli_nps->read.buf, req);
915 return;
917 memcpy(cli_nps->read.buf, rcvbuf, received);
919 if (cli_nps->trans.write_req == NULL) {
920 tstream_cli_np_readv_read_next(req);
921 return;
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,
932 void *private_data)
934 struct tevent_req *req =
935 talloc_get_type_abort(private_data,
936 struct tevent_req);
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);
949 uint8_t *rcvbuf;
950 ssize_t received;
951 NTSTATUS status;
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);
960 } else {
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
967 * child of that.
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)) {
980 TALLOC_FREE(subreq);
981 tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
982 return;
985 if (received > TSTREAM_CLI_NP_MAX_BUF_SIZE) {
986 TALLOC_FREE(subreq);
987 tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
988 return;
991 if (received == 0) {
992 TALLOC_FREE(subreq);
993 tstream_cli_np_readv_disconnect_now(req, EPIPE, __location__);
994 return;
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);
1003 return;
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,
1016 int error,
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);
1033 return;
1036 if (cli_nps->is_smb1) {
1037 subreq = cli_close_send(state, state->ev, cli_nps->cli,
1038 cli_nps->fnum);
1039 } else {
1040 subreq = smb2cli_close_send(state, state->ev,
1041 cli_nps->cli->conn,
1042 cli_nps->cli->timeout,
1043 cli_nps->cli->smb2.session,
1044 cli_nps->cli->smb2.tcon,
1045 0, /* flags */
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);
1052 return;
1054 tevent_req_set_callback(subreq,
1055 tstream_cli_np_readv_disconnect_done,
1056 req);
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);
1070 } else {
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);
1096 return;
1099 if (state->trans.im == NULL) {
1100 /* return the original error */
1101 _tevent_req_error(req, state->error.val, state->error.location);
1102 return;
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,
1115 void *private_data)
1117 struct tevent_req *req =
1118 talloc_get_type_abort(private_data,
1119 struct tevent_req);
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,
1129 int *perrno)
1131 struct tstream_cli_np_readv_state *state =
1132 tevent_req_data(req, struct tstream_cli_np_readv_state);
1133 int ret;
1135 ret = tsocket_simple_int_recv(req, perrno);
1136 if (ret == 0) {
1137 ret = state->ret;
1140 tevent_req_received(req);
1141 return ret;
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);
1162 if (req == NULL) {
1163 return NULL;
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,
1175 cli_nps->fnum);
1176 } else {
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,
1181 0, /* flags */
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);
1190 return req;
1193 static void tstream_cli_np_disconnect_done(struct tevent_req *subreq)
1195 struct tevent_req *req = tevent_req_callback_data(subreq,
1196 struct tevent_req);
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);
1201 NTSTATUS status;
1203 if (cli_nps->is_smb1) {
1204 status = cli_close_recv(subreq);
1205 } else {
1206 status = smb2cli_close_recv(subreq);
1208 TALLOC_FREE(subreq);
1209 if (!NT_STATUS_IS_OK(status)) {
1210 tevent_req_error(req, EIO);
1211 return;
1214 cli_nps->cli = NULL;
1216 tevent_req_done(req);
1219 static int tstream_cli_np_disconnect_recv(struct tevent_req *req,
1220 int *perrno)
1222 int ret;
1224 ret = tsocket_simple_int_recv(req, perrno);
1226 tevent_req_received(req);
1227 return ret;
1230 static const struct tstream_context_ops tstream_cli_np_ops = {
1231 .name = "cli_np",
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,