param: Rename variable used for lp_durable_handles bDurableHandles
[Samba.git] / libcli / smb / tstream_smbXcli_np.c
blob2c2cb4b2f5d8b39338b8af860b90103038edb65e
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 "../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_smbXcli_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_SMBXCLI_NP_MAX_BUF_SIZE 4280
52 #define TSTREAM_SMBXCLI_NP_DESIRED_ACCESS ( \
53 SEC_STD_READ_CONTROL | \
54 SEC_FILE_READ_DATA | \
55 SEC_FILE_WRITE_DATA | \
56 SEC_FILE_APPEND_DATA | \
57 SEC_FILE_READ_EA | \
58 SEC_FILE_WRITE_EA | \
59 SEC_FILE_READ_ATTRIBUTE | \
60 SEC_FILE_WRITE_ATTRIBUTE | \
63 struct tstream_smbXcli_np_ref;
65 struct tstream_smbXcli_np {
66 struct tstream_smbXcli_np_ref *ref;
67 struct smbXcli_conn *conn;
68 struct smbXcli_session *session;
69 struct smbXcli_tcon *tcon;
70 uint16_t pid;
71 unsigned int timeout;
73 const char *npipe;
74 bool is_smb1;
75 uint16_t fnum;
76 uint64_t fid_persistent;
77 uint64_t fid_volatile;
79 struct {
80 bool active;
81 struct tevent_req *read_req;
82 struct tevent_req *write_req;
83 uint16_t setup[2];
84 } trans;
86 struct {
87 off_t ofs;
88 size_t left;
89 uint8_t *buf;
90 } read, write;
93 struct tstream_smbXcli_np_ref {
94 struct tstream_smbXcli_np *cli_nps;
97 static int tstream_smbXcli_np_destructor(struct tstream_smbXcli_np *cli_nps)
99 NTSTATUS status;
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)) {
107 return 0;
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
121 * never be called.
123 if (cli_nps->is_smb1) {
124 status = smb1cli_close(cli_nps->conn,
125 cli_nps->timeout,
126 cli_nps->pid,
127 cli_nps->tcon,
128 cli_nps->session,
129 cli_nps->fnum, UINT32_MAX);
130 } else {
131 status = smb2cli_close(cli_nps->conn,
132 cli_nps->timeout,
133 cli_nps->session,
134 cli_nps->tcon,
135 0, /* flags */
136 cli_nps->fid_persistent,
137 cli_nps->fid_volatile);
139 if (!NT_STATUS_IS_OK(status)) {
140 DEBUG(1, ("tstream_smbXcli_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
147 return 0;
150 static int tstream_smbXcli_np_ref_destructor(struct tstream_smbXcli_np_ref *ref)
152 if (ref->cli_nps == NULL) {
153 return 0;
156 ref->cli_nps->conn = NULL;
157 ref->cli_nps->session = NULL;
158 ref->cli_nps->tcon = NULL;
159 ref->cli_nps->ref = NULL;
161 return 0;
164 struct tstream_smbXcli_np_open_state {
165 struct smbXcli_conn *conn;
166 struct smbXcli_session *session;
167 struct smbXcli_tcon *tcon;
168 uint16_t pid;
169 unsigned int timeout;
171 bool is_smb1;
172 uint16_t fnum;
173 uint64_t fid_persistent;
174 uint64_t fid_volatile;
175 const char *npipe;
178 static void tstream_smbXcli_np_open_done(struct tevent_req *subreq);
180 struct tevent_req *tstream_smbXcli_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,
186 unsigned int timeout,
187 const char *npipe)
189 struct tevent_req *req;
190 struct tstream_smbXcli_np_open_state *state;
191 struct tevent_req *subreq;
193 req = tevent_req_create(mem_ctx, &state,
194 struct tstream_smbXcli_np_open_state);
195 if (!req) {
196 return NULL;
198 state->conn = conn;
199 state->tcon = tcon;
200 state->session = session;
201 state->pid = pid;
202 state->timeout = timeout;
204 state->npipe = talloc_strdup(state, npipe);
205 if (tevent_req_nomem(state->npipe, req)) {
206 return tevent_req_post(req, ev);
209 if (smbXcli_conn_protocol(conn) < PROTOCOL_SMB2_02) {
210 state->is_smb1 = true;
213 if (state->is_smb1) {
214 const char *smb1_npipe;
217 * Windows and newer Samba versions allow
218 * the pipe name without leading backslash,
219 * but we should better behave like windows clients
221 smb1_npipe = talloc_asprintf(state, "\\%s", state->npipe);
222 if (tevent_req_nomem(smb1_npipe, req)) {
223 return tevent_req_post(req, ev);
225 subreq = smb1cli_ntcreatex_send(state, ev, state->conn,
226 state->timeout,
227 state->pid,
228 state->tcon,
229 state->session,
230 smb1_npipe,
231 0, /* CreatFlags */
232 0, /* RootDirectoryFid */
233 TSTREAM_SMBXCLI_NP_DESIRED_ACCESS,
234 0, /* AllocationSize */
235 0, /* FileAttributes */
236 FILE_SHARE_READ|FILE_SHARE_WRITE,
237 FILE_OPEN, /* CreateDisposition */
238 0, /* CreateOptions */
239 2, /* NTCREATEX_IMPERSONATION_IMPERSONATION */
240 0); /* SecurityFlags */
241 } else {
242 subreq = smb2cli_create_send(state, ev, state->conn,
243 state->timeout, state->session,
244 state->tcon,
245 npipe,
246 SMB2_OPLOCK_LEVEL_NONE,
247 SMB2_IMPERSONATION_IMPERSONATION,
248 TSTREAM_SMBXCLI_NP_DESIRED_ACCESS,
249 0, /* file_attributes */
250 FILE_SHARE_READ|FILE_SHARE_WRITE,
251 FILE_OPEN,
252 0, /* create_options */
253 NULL); /* blobs */
255 if (tevent_req_nomem(subreq, req)) {
256 return tevent_req_post(req, ev);
258 tevent_req_set_callback(subreq, tstream_smbXcli_np_open_done, req);
260 return req;
263 static void tstream_smbXcli_np_open_done(struct tevent_req *subreq)
265 struct tevent_req *req =
266 tevent_req_callback_data(subreq, struct tevent_req);
267 struct tstream_smbXcli_np_open_state *state =
268 tevent_req_data(req, struct tstream_smbXcli_np_open_state);
269 NTSTATUS status;
271 if (state->is_smb1) {
272 status = smb1cli_ntcreatex_recv(subreq, &state->fnum);
273 } else {
274 status = smb2cli_create_recv(subreq,
275 &state->fid_persistent,
276 &state->fid_volatile,
277 NULL);
279 TALLOC_FREE(subreq);
280 if (!NT_STATUS_IS_OK(status)) {
281 tevent_req_nterror(req, status);
282 return;
285 tevent_req_done(req);
288 NTSTATUS _tstream_smbXcli_np_open_recv(struct tevent_req *req,
289 TALLOC_CTX *mem_ctx,
290 struct tstream_context **_stream,
291 const char *location)
293 struct tstream_smbXcli_np_open_state *state =
294 tevent_req_data(req, struct tstream_smbXcli_np_open_state);
295 struct tstream_context *stream;
296 struct tstream_smbXcli_np *cli_nps;
297 NTSTATUS status;
299 if (tevent_req_is_nterror(req, &status)) {
300 tevent_req_received(req);
301 return status;
304 stream = tstream_context_create(mem_ctx,
305 &tstream_smbXcli_np_ops,
306 &cli_nps,
307 struct tstream_smbXcli_np,
308 location);
309 if (!stream) {
310 tevent_req_received(req);
311 return NT_STATUS_NO_MEMORY;
313 ZERO_STRUCTP(cli_nps);
315 cli_nps->ref = talloc_zero(state->conn, struct tstream_smbXcli_np_ref);
316 if (cli_nps->ref == NULL) {
317 TALLOC_FREE(cli_nps);
318 tevent_req_received(req);
319 return NT_STATUS_NO_MEMORY;
321 cli_nps->ref->cli_nps = cli_nps;
322 cli_nps->conn = state->conn;
323 cli_nps->session = state->session;
324 cli_nps->tcon = state->tcon;
325 cli_nps->pid = state->pid;
326 cli_nps->timeout = state->timeout;
327 cli_nps->npipe = talloc_move(cli_nps, &state->npipe);
328 cli_nps->is_smb1 = state->is_smb1;
329 cli_nps->fnum = state->fnum;
330 cli_nps->fid_persistent = state->fid_persistent;
331 cli_nps->fid_volatile = state->fid_volatile;
333 talloc_set_destructor(cli_nps, tstream_smbXcli_np_destructor);
334 talloc_set_destructor(cli_nps->ref, tstream_smbXcli_np_ref_destructor);
336 cli_nps->trans.active = false;
337 cli_nps->trans.read_req = NULL;
338 cli_nps->trans.write_req = NULL;
339 SSVAL(cli_nps->trans.setup+0, 0, TRANSACT_DCERPCCMD);
340 SSVAL(cli_nps->trans.setup+1, 0, cli_nps->fnum);
342 *_stream = stream;
343 tevent_req_received(req);
344 return NT_STATUS_OK;
347 static ssize_t tstream_smbXcli_np_pending_bytes(struct tstream_context *stream)
349 struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
350 struct tstream_smbXcli_np);
352 if (!smbXcli_conn_is_connected(cli_nps->conn)) {
353 errno = ENOTCONN;
354 return -1;
357 return cli_nps->read.left;
360 bool tstream_is_smbXcli_np(struct tstream_context *stream)
362 struct tstream_smbXcli_np *cli_nps =
363 talloc_get_type(_tstream_context_data(stream),
364 struct tstream_smbXcli_np);
366 if (!cli_nps) {
367 return false;
370 return true;
373 NTSTATUS tstream_smbXcli_np_use_trans(struct tstream_context *stream)
375 struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
376 struct tstream_smbXcli_np);
378 if (cli_nps->trans.read_req) {
379 return NT_STATUS_PIPE_BUSY;
382 if (cli_nps->trans.write_req) {
383 return NT_STATUS_PIPE_BUSY;
386 if (cli_nps->trans.active) {
387 return NT_STATUS_PIPE_BUSY;
390 cli_nps->trans.active = true;
392 return NT_STATUS_OK;
395 unsigned int tstream_smbXcli_np_set_timeout(struct tstream_context *stream,
396 unsigned int timeout)
398 struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
399 struct tstream_smbXcli_np);
400 unsigned int old_timeout = cli_nps->timeout;
402 cli_nps->timeout = timeout;
403 return old_timeout;
406 struct tstream_smbXcli_np_writev_state {
407 struct tstream_context *stream;
408 struct tevent_context *ev;
410 struct iovec *vector;
411 size_t count;
413 int ret;
415 struct {
416 int val;
417 const char *location;
418 } error;
421 static int tstream_smbXcli_np_writev_state_destructor(struct tstream_smbXcli_np_writev_state *state)
423 struct tstream_smbXcli_np *cli_nps =
424 tstream_context_data(state->stream,
425 struct tstream_smbXcli_np);
427 cli_nps->trans.write_req = NULL;
429 return 0;
432 static void tstream_smbXcli_np_writev_write_next(struct tevent_req *req);
434 static struct tevent_req *tstream_smbXcli_np_writev_send(TALLOC_CTX *mem_ctx,
435 struct tevent_context *ev,
436 struct tstream_context *stream,
437 const struct iovec *vector,
438 size_t count)
440 struct tevent_req *req;
441 struct tstream_smbXcli_np_writev_state *state;
442 struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
443 struct tstream_smbXcli_np);
445 req = tevent_req_create(mem_ctx, &state,
446 struct tstream_smbXcli_np_writev_state);
447 if (!req) {
448 return NULL;
450 state->stream = stream;
451 state->ev = ev;
452 state->ret = 0;
454 talloc_set_destructor(state, tstream_smbXcli_np_writev_state_destructor);
456 if (!smbXcli_conn_is_connected(cli_nps->conn)) {
457 tevent_req_error(req, ENOTCONN);
458 return tevent_req_post(req, ev);
462 * we make a copy of the vector so we can change the structure
464 state->vector = talloc_array(state, struct iovec, count);
465 if (tevent_req_nomem(state->vector, req)) {
466 return tevent_req_post(req, ev);
468 memcpy(state->vector, vector, sizeof(struct iovec) * count);
469 state->count = count;
471 tstream_smbXcli_np_writev_write_next(req);
472 if (!tevent_req_is_in_progress(req)) {
473 return tevent_req_post(req, ev);
476 return req;
479 static void tstream_smbXcli_np_readv_trans_start(struct tevent_req *req);
480 static void tstream_smbXcli_np_writev_write_done(struct tevent_req *subreq);
482 static void tstream_smbXcli_np_writev_write_next(struct tevent_req *req)
484 struct tstream_smbXcli_np_writev_state *state =
485 tevent_req_data(req,
486 struct tstream_smbXcli_np_writev_state);
487 struct tstream_smbXcli_np *cli_nps =
488 tstream_context_data(state->stream,
489 struct tstream_smbXcli_np);
490 struct tevent_req *subreq;
491 size_t i;
492 size_t left = 0;
494 for (i=0; i < state->count; i++) {
495 left += state->vector[i].iov_len;
498 if (left == 0) {
499 TALLOC_FREE(cli_nps->write.buf);
500 tevent_req_done(req);
501 return;
504 cli_nps->write.ofs = 0;
505 cli_nps->write.left = MIN(left, TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE);
506 cli_nps->write.buf = talloc_realloc(cli_nps, cli_nps->write.buf,
507 uint8_t, cli_nps->write.left);
508 if (tevent_req_nomem(cli_nps->write.buf, req)) {
509 return;
513 * copy the pending buffer first
515 while (cli_nps->write.left > 0 && state->count > 0) {
516 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
517 size_t len = MIN(cli_nps->write.left, state->vector[0].iov_len);
519 memcpy(cli_nps->write.buf + cli_nps->write.ofs, base, len);
521 base += len;
522 state->vector[0].iov_base = base;
523 state->vector[0].iov_len -= len;
525 cli_nps->write.ofs += len;
526 cli_nps->write.left -= len;
528 if (state->vector[0].iov_len == 0) {
529 state->vector += 1;
530 state->count -= 1;
533 state->ret += len;
536 if (cli_nps->trans.active && state->count == 0) {
537 cli_nps->trans.active = false;
538 cli_nps->trans.write_req = req;
539 return;
542 if (cli_nps->trans.read_req && state->count == 0) {
543 cli_nps->trans.write_req = req;
544 tstream_smbXcli_np_readv_trans_start(cli_nps->trans.read_req);
545 return;
548 if (cli_nps->is_smb1) {
549 subreq = smb1cli_writex_send(state, state->ev,
550 cli_nps->conn,
551 cli_nps->timeout,
552 cli_nps->pid,
553 cli_nps->tcon,
554 cli_nps->session,
555 cli_nps->fnum,
556 8, /* 8 means message mode. */
557 cli_nps->write.buf,
558 0, /* offset */
559 cli_nps->write.ofs); /* size */
560 } else {
561 subreq = smb2cli_write_send(state, state->ev,
562 cli_nps->conn,
563 cli_nps->timeout,
564 cli_nps->session,
565 cli_nps->tcon,
566 cli_nps->write.ofs, /* length */
567 0, /* offset */
568 cli_nps->fid_persistent,
569 cli_nps->fid_volatile,
570 0, /* remaining_bytes */
571 0, /* flags */
572 cli_nps->write.buf);
574 if (tevent_req_nomem(subreq, req)) {
575 return;
577 tevent_req_set_callback(subreq,
578 tstream_smbXcli_np_writev_write_done,
579 req);
582 static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req *req,
583 int error,
584 const char *location);
586 static void tstream_smbXcli_np_writev_write_done(struct tevent_req *subreq)
588 struct tevent_req *req =
589 tevent_req_callback_data(subreq, struct tevent_req);
590 struct tstream_smbXcli_np_writev_state *state =
591 tevent_req_data(req, struct tstream_smbXcli_np_writev_state);
592 struct tstream_smbXcli_np *cli_nps =
593 tstream_context_data(state->stream,
594 struct tstream_smbXcli_np);
595 uint32_t written;
596 NTSTATUS status;
598 if (cli_nps->is_smb1) {
599 status = smb1cli_writex_recv(subreq, &written, NULL);
600 } else {
601 status = smb2cli_write_recv(subreq, &written);
603 TALLOC_FREE(subreq);
604 if (!NT_STATUS_IS_OK(status)) {
605 tstream_smbXcli_np_writev_disconnect_now(req, EIO, __location__);
606 return;
609 if (written != cli_nps->write.ofs) {
610 tstream_smbXcli_np_writev_disconnect_now(req, EIO, __location__);
611 return;
614 tstream_smbXcli_np_writev_write_next(req);
617 static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req *subreq);
619 static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req *req,
620 int error,
621 const char *location)
623 struct tstream_smbXcli_np_writev_state *state =
624 tevent_req_data(req,
625 struct tstream_smbXcli_np_writev_state);
626 struct tstream_smbXcli_np *cli_nps =
627 tstream_context_data(state->stream,
628 struct tstream_smbXcli_np);
629 struct tevent_req *subreq;
631 state->error.val = error;
632 state->error.location = location;
634 if (!smbXcli_conn_is_connected(cli_nps->conn)) {
635 /* return the original error */
636 _tevent_req_error(req, state->error.val, state->error.location);
637 return;
640 if (cli_nps->is_smb1) {
641 subreq = smb1cli_close_send(state, state->ev,
642 cli_nps->conn,
643 cli_nps->timeout,
644 cli_nps->pid,
645 cli_nps->tcon,
646 cli_nps->session,
647 cli_nps->fnum, UINT32_MAX);
648 } else {
649 subreq = smb2cli_close_send(state, state->ev,
650 cli_nps->conn,
651 cli_nps->timeout,
652 cli_nps->session,
653 cli_nps->tcon,
654 0, /* flags */
655 cli_nps->fid_persistent,
656 cli_nps->fid_volatile);
658 if (subreq == NULL) {
659 /* return the original error */
660 _tevent_req_error(req, state->error.val, state->error.location);
661 return;
663 tevent_req_set_callback(subreq,
664 tstream_smbXcli_np_writev_disconnect_done,
665 req);
668 static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req *subreq)
670 struct tevent_req *req =
671 tevent_req_callback_data(subreq, struct tevent_req);
672 struct tstream_smbXcli_np_writev_state *state =
673 tevent_req_data(req, struct tstream_smbXcli_np_writev_state);
674 struct tstream_smbXcli_np *cli_nps =
675 tstream_context_data(state->stream, struct tstream_smbXcli_np);
677 if (cli_nps->is_smb1) {
678 smb1cli_close_recv(subreq);
679 } else {
680 smb2cli_close_recv(subreq);
682 TALLOC_FREE(subreq);
684 cli_nps->conn = NULL;
685 cli_nps->tcon = NULL;
686 cli_nps->session = NULL;
688 /* return the original error */
689 _tevent_req_error(req, state->error.val, state->error.location);
692 static int tstream_smbXcli_np_writev_recv(struct tevent_req *req,
693 int *perrno)
695 struct tstream_smbXcli_np_writev_state *state =
696 tevent_req_data(req,
697 struct tstream_smbXcli_np_writev_state);
698 int ret;
700 ret = tsocket_simple_int_recv(req, perrno);
701 if (ret == 0) {
702 ret = state->ret;
705 tevent_req_received(req);
706 return ret;
709 struct tstream_smbXcli_np_readv_state {
710 struct tstream_context *stream;
711 struct tevent_context *ev;
713 struct iovec *vector;
714 size_t count;
716 int ret;
718 struct {
719 struct tevent_immediate *im;
720 } trans;
722 struct {
723 int val;
724 const char *location;
725 } error;
728 static int tstream_smbXcli_np_readv_state_destructor(struct tstream_smbXcli_np_readv_state *state)
730 struct tstream_smbXcli_np *cli_nps =
731 tstream_context_data(state->stream,
732 struct tstream_smbXcli_np);
734 cli_nps->trans.read_req = NULL;
736 return 0;
739 static void tstream_smbXcli_np_readv_read_next(struct tevent_req *req);
741 static struct tevent_req *tstream_smbXcli_np_readv_send(TALLOC_CTX *mem_ctx,
742 struct tevent_context *ev,
743 struct tstream_context *stream,
744 struct iovec *vector,
745 size_t count)
747 struct tevent_req *req;
748 struct tstream_smbXcli_np_readv_state *state;
749 struct tstream_smbXcli_np *cli_nps =
750 tstream_context_data(stream, struct tstream_smbXcli_np);
752 req = tevent_req_create(mem_ctx, &state,
753 struct tstream_smbXcli_np_readv_state);
754 if (!req) {
755 return NULL;
757 state->stream = stream;
758 state->ev = ev;
759 state->ret = 0;
761 talloc_set_destructor(state, tstream_smbXcli_np_readv_state_destructor);
763 if (!smbXcli_conn_is_connected(cli_nps->conn)) {
764 tevent_req_error(req, ENOTCONN);
765 return tevent_req_post(req, ev);
769 * we make a copy of the vector so we can change the structure
771 state->vector = talloc_array(state, struct iovec, count);
772 if (tevent_req_nomem(state->vector, req)) {
773 return tevent_req_post(req, ev);
775 memcpy(state->vector, vector, sizeof(struct iovec) * count);
776 state->count = count;
778 tstream_smbXcli_np_readv_read_next(req);
779 if (!tevent_req_is_in_progress(req)) {
780 return tevent_req_post(req, ev);
783 return req;
786 static void tstream_smbXcli_np_readv_read_done(struct tevent_req *subreq);
788 static void tstream_smbXcli_np_readv_read_next(struct tevent_req *req)
790 struct tstream_smbXcli_np_readv_state *state =
791 tevent_req_data(req,
792 struct tstream_smbXcli_np_readv_state);
793 struct tstream_smbXcli_np *cli_nps =
794 tstream_context_data(state->stream,
795 struct tstream_smbXcli_np);
796 struct tevent_req *subreq;
799 * copy the pending buffer first
801 while (cli_nps->read.left > 0 && state->count > 0) {
802 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
803 size_t len = MIN(cli_nps->read.left, state->vector[0].iov_len);
805 memcpy(base, cli_nps->read.buf + cli_nps->read.ofs, len);
807 base += len;
808 state->vector[0].iov_base = base;
809 state->vector[0].iov_len -= len;
811 cli_nps->read.ofs += len;
812 cli_nps->read.left -= len;
814 if (state->vector[0].iov_len == 0) {
815 state->vector += 1;
816 state->count -= 1;
819 state->ret += len;
822 if (cli_nps->read.left == 0) {
823 TALLOC_FREE(cli_nps->read.buf);
826 if (state->count == 0) {
827 tevent_req_done(req);
828 return;
831 if (cli_nps->trans.active) {
832 cli_nps->trans.active = false;
833 cli_nps->trans.read_req = req;
834 return;
837 if (cli_nps->trans.write_req) {
838 cli_nps->trans.read_req = req;
839 tstream_smbXcli_np_readv_trans_start(req);
840 return;
843 if (cli_nps->is_smb1) {
844 subreq = smb1cli_readx_send(state, state->ev,
845 cli_nps->conn,
846 cli_nps->timeout,
847 cli_nps->pid,
848 cli_nps->tcon,
849 cli_nps->session,
850 cli_nps->fnum,
851 0, /* offset */
852 TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE);
853 } else {
854 subreq = smb2cli_read_send(state, state->ev,
855 cli_nps->conn,
856 cli_nps->timeout,
857 cli_nps->session,
858 cli_nps->tcon,
859 TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE, /* length */
860 0, /* offset */
861 cli_nps->fid_persistent,
862 cli_nps->fid_volatile,
863 0, /* minimum_count */
864 0); /* remaining_bytes */
866 if (tevent_req_nomem(subreq, req)) {
867 return;
869 tevent_req_set_callback(subreq,
870 tstream_smbXcli_np_readv_read_done,
871 req);
874 static void tstream_smbXcli_np_readv_trans_done(struct tevent_req *subreq);
876 static void tstream_smbXcli_np_readv_trans_start(struct tevent_req *req)
878 struct tstream_smbXcli_np_readv_state *state =
879 tevent_req_data(req,
880 struct tstream_smbXcli_np_readv_state);
881 struct tstream_smbXcli_np *cli_nps =
882 tstream_context_data(state->stream,
883 struct tstream_smbXcli_np);
884 struct tevent_req *subreq;
886 state->trans.im = tevent_create_immediate(state);
887 if (tevent_req_nomem(state->trans.im, req)) {
888 return;
891 if (cli_nps->is_smb1) {
892 subreq = smb1cli_trans_send(state, state->ev,
893 cli_nps->conn, SMBtrans,
894 0, 0, /* *_flags */
895 0, 0, /* *_flags2 */
896 cli_nps->timeout,
897 cli_nps->pid,
898 cli_nps->tcon,
899 cli_nps->session,
900 "\\PIPE\\",
901 0, 0, 0,
902 cli_nps->trans.setup, 2,
904 NULL, 0, 0,
905 cli_nps->write.buf,
906 cli_nps->write.ofs,
907 TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE);
908 } else {
909 DATA_BLOB in_input_buffer = data_blob_null;
910 DATA_BLOB in_output_buffer = data_blob_null;
912 in_input_buffer = data_blob_const(cli_nps->write.buf,
913 cli_nps->write.ofs);
915 subreq = smb2cli_ioctl_send(state, state->ev,
916 cli_nps->conn,
917 cli_nps->timeout,
918 cli_nps->session,
919 cli_nps->tcon,
920 cli_nps->fid_persistent,
921 cli_nps->fid_volatile,
922 FSCTL_NAMED_PIPE_READ_WRITE,
923 0, /* in_max_input_length */
924 &in_input_buffer,
925 /* in_max_output_length */
926 TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE,
927 &in_output_buffer,
928 SMB2_IOCTL_FLAG_IS_FSCTL);
930 if (tevent_req_nomem(subreq, req)) {
931 return;
933 tevent_req_set_callback(subreq,
934 tstream_smbXcli_np_readv_trans_done,
935 req);
938 static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req *req,
939 int error,
940 const char *location);
941 static void tstream_smbXcli_np_readv_trans_next(struct tevent_context *ctx,
942 struct tevent_immediate *im,
943 void *private_data);
945 static void tstream_smbXcli_np_readv_trans_done(struct tevent_req *subreq)
947 struct tevent_req *req =
948 tevent_req_callback_data(subreq, struct tevent_req);
949 struct tstream_smbXcli_np_readv_state *state =
950 tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
951 struct tstream_smbXcli_np *cli_nps =
952 tstream_context_data(state->stream, struct tstream_smbXcli_np);
953 uint8_t *rcvbuf;
954 uint32_t received;
955 NTSTATUS status;
957 if (cli_nps->is_smb1) {
958 status = smb1cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
959 NULL, 0, NULL,
960 &rcvbuf, 0, &received);
961 } else {
962 DATA_BLOB out_input_buffer = data_blob_null;
963 DATA_BLOB out_output_buffer = data_blob_null;
965 status = smb2cli_ioctl_recv(subreq, state,
966 &out_input_buffer,
967 &out_output_buffer);
969 /* Note that rcvbuf is not a talloc pointer here */
970 rcvbuf = out_output_buffer.data;
971 received = out_output_buffer.length;
973 TALLOC_FREE(subreq);
974 if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
975 status = NT_STATUS_OK;
977 if (!NT_STATUS_IS_OK(status)) {
978 tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
979 return;
982 if (received > TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE) {
983 tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
984 return;
987 if (received == 0) {
988 tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
989 return;
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) {
996 TALLOC_FREE(subreq);
997 tevent_req_nomem(cli_nps->read.buf, req);
998 return;
1000 memcpy(cli_nps->read.buf, rcvbuf, received);
1002 if (cli_nps->trans.write_req == NULL) {
1003 tstream_smbXcli_np_readv_read_next(req);
1004 return;
1007 tevent_schedule_immediate(state->trans.im, state->ev,
1008 tstream_smbXcli_np_readv_trans_next, req);
1010 tevent_req_done(cli_nps->trans.write_req);
1013 static void tstream_smbXcli_np_readv_trans_next(struct tevent_context *ctx,
1014 struct tevent_immediate *im,
1015 void *private_data)
1017 struct tevent_req *req =
1018 talloc_get_type_abort(private_data,
1019 struct tevent_req);
1021 tstream_smbXcli_np_readv_read_next(req);
1024 static void tstream_smbXcli_np_readv_read_done(struct tevent_req *subreq)
1026 struct tevent_req *req =
1027 tevent_req_callback_data(subreq, struct tevent_req);
1028 struct tstream_smbXcli_np_readv_state *state =
1029 tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
1030 struct tstream_smbXcli_np *cli_nps =
1031 tstream_context_data(state->stream, struct tstream_smbXcli_np);
1032 uint8_t *rcvbuf;
1033 uint32_t received;
1034 NTSTATUS status;
1037 * We must free subreq in this function as there is
1038 * a timer event attached to it.
1041 if (cli_nps->is_smb1) {
1042 status = smb1cli_readx_recv(subreq, &received, &rcvbuf);
1043 } else {
1044 status = smb2cli_read_recv(subreq, state, &rcvbuf, &received);
1047 * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
1048 * child of that.
1050 if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
1052 * NT_STATUS_BUFFER_TOO_SMALL means that there's
1053 * more data to read when the named pipe is used
1054 * in message mode (which is the case here).
1056 * But we hide this from the caller.
1058 status = NT_STATUS_OK;
1060 if (!NT_STATUS_IS_OK(status)) {
1061 TALLOC_FREE(subreq);
1062 tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
1063 return;
1066 if (received > TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE) {
1067 TALLOC_FREE(subreq);
1068 tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
1069 return;
1072 if (received == 0) {
1073 TALLOC_FREE(subreq);
1074 tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
1075 return;
1078 cli_nps->read.ofs = 0;
1079 cli_nps->read.left = received;
1080 cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received);
1081 if (cli_nps->read.buf == NULL) {
1082 TALLOC_FREE(subreq);
1083 tevent_req_nomem(cli_nps->read.buf, req);
1084 return;
1086 memcpy(cli_nps->read.buf, rcvbuf, received);
1087 TALLOC_FREE(subreq);
1089 tstream_smbXcli_np_readv_read_next(req);
1092 static void tstream_smbXcli_np_readv_disconnect_done(struct tevent_req *subreq);
1094 static void tstream_smbXcli_np_readv_error(struct tevent_req *req);
1096 static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req *req,
1097 int error,
1098 const char *location)
1100 struct tstream_smbXcli_np_readv_state *state =
1101 tevent_req_data(req,
1102 struct tstream_smbXcli_np_readv_state);
1103 struct tstream_smbXcli_np *cli_nps =
1104 tstream_context_data(state->stream,
1105 struct tstream_smbXcli_np);
1106 struct tevent_req *subreq;
1108 state->error.val = error;
1109 state->error.location = location;
1111 if (!smbXcli_conn_is_connected(cli_nps->conn)) {
1112 /* return the original error */
1113 tstream_smbXcli_np_readv_error(req);
1114 return;
1117 if (cli_nps->is_smb1) {
1118 subreq = smb1cli_close_send(state, state->ev,
1119 cli_nps->conn,
1120 cli_nps->timeout,
1121 cli_nps->pid,
1122 cli_nps->tcon,
1123 cli_nps->session,
1124 cli_nps->fnum, UINT32_MAX);
1125 } else {
1126 subreq = smb2cli_close_send(state, state->ev,
1127 cli_nps->conn,
1128 cli_nps->timeout,
1129 cli_nps->session,
1130 cli_nps->tcon,
1131 0, /* flags */
1132 cli_nps->fid_persistent,
1133 cli_nps->fid_volatile);
1135 if (subreq == NULL) {
1136 /* return the original error */
1137 tstream_smbXcli_np_readv_error(req);
1138 return;
1140 tevent_req_set_callback(subreq,
1141 tstream_smbXcli_np_readv_disconnect_done,
1142 req);
1145 static void tstream_smbXcli_np_readv_disconnect_done(struct tevent_req *subreq)
1147 struct tevent_req *req =
1148 tevent_req_callback_data(subreq, struct tevent_req);
1149 struct tstream_smbXcli_np_readv_state *state =
1150 tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
1151 struct tstream_smbXcli_np *cli_nps =
1152 tstream_context_data(state->stream, struct tstream_smbXcli_np);
1154 if (cli_nps->is_smb1) {
1155 smb1cli_close_recv(subreq);
1156 } else {
1157 smb2cli_close_recv(subreq);
1159 TALLOC_FREE(subreq);
1161 cli_nps->conn = NULL;
1162 cli_nps->session = NULL;
1163 cli_nps->tcon = NULL;
1165 tstream_smbXcli_np_readv_error(req);
1168 static void tstream_smbXcli_np_readv_error_trigger(struct tevent_context *ctx,
1169 struct tevent_immediate *im,
1170 void *private_data);
1172 static void tstream_smbXcli_np_readv_error(struct tevent_req *req)
1174 struct tstream_smbXcli_np_readv_state *state =
1175 tevent_req_data(req,
1176 struct tstream_smbXcli_np_readv_state);
1177 struct tstream_smbXcli_np *cli_nps =
1178 tstream_context_data(state->stream,
1179 struct tstream_smbXcli_np);
1181 if (cli_nps->trans.write_req == NULL) {
1182 /* return the original error */
1183 _tevent_req_error(req, state->error.val, state->error.location);
1184 return;
1187 if (state->trans.im == NULL) {
1188 /* return the original error */
1189 _tevent_req_error(req, state->error.val, state->error.location);
1190 return;
1193 tevent_schedule_immediate(state->trans.im, state->ev,
1194 tstream_smbXcli_np_readv_error_trigger, req);
1196 /* return the original error for writev */
1197 _tevent_req_error(cli_nps->trans.write_req,
1198 state->error.val, state->error.location);
1201 static void tstream_smbXcli_np_readv_error_trigger(struct tevent_context *ctx,
1202 struct tevent_immediate *im,
1203 void *private_data)
1205 struct tevent_req *req =
1206 talloc_get_type_abort(private_data,
1207 struct tevent_req);
1208 struct tstream_smbXcli_np_readv_state *state =
1209 tevent_req_data(req,
1210 struct tstream_smbXcli_np_readv_state);
1212 /* return the original error */
1213 _tevent_req_error(req, state->error.val, state->error.location);
1216 static int tstream_smbXcli_np_readv_recv(struct tevent_req *req,
1217 int *perrno)
1219 struct tstream_smbXcli_np_readv_state *state =
1220 tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
1221 int ret;
1223 ret = tsocket_simple_int_recv(req, perrno);
1224 if (ret == 0) {
1225 ret = state->ret;
1228 tevent_req_received(req);
1229 return ret;
1232 struct tstream_smbXcli_np_disconnect_state {
1233 struct tstream_context *stream;
1236 static void tstream_smbXcli_np_disconnect_done(struct tevent_req *subreq);
1238 static struct tevent_req *tstream_smbXcli_np_disconnect_send(TALLOC_CTX *mem_ctx,
1239 struct tevent_context *ev,
1240 struct tstream_context *stream)
1242 struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
1243 struct tstream_smbXcli_np);
1244 struct tevent_req *req;
1245 struct tstream_smbXcli_np_disconnect_state *state;
1246 struct tevent_req *subreq;
1248 req = tevent_req_create(mem_ctx, &state,
1249 struct tstream_smbXcli_np_disconnect_state);
1250 if (req == NULL) {
1251 return NULL;
1254 state->stream = stream;
1256 if (!smbXcli_conn_is_connected(cli_nps->conn)) {
1257 tevent_req_error(req, ENOTCONN);
1258 return tevent_req_post(req, ev);
1261 if (cli_nps->is_smb1) {
1262 subreq = smb1cli_close_send(state, ev, cli_nps->conn,
1263 cli_nps->timeout,
1264 cli_nps->pid,
1265 cli_nps->tcon,
1266 cli_nps->session,
1267 cli_nps->fnum, UINT32_MAX);
1268 } else {
1269 subreq = smb2cli_close_send(state, ev, cli_nps->conn,
1270 cli_nps->timeout,
1271 cli_nps->session,
1272 cli_nps->tcon,
1273 0, /* flags */
1274 cli_nps->fid_persistent,
1275 cli_nps->fid_volatile);
1277 if (tevent_req_nomem(subreq, req)) {
1278 return tevent_req_post(req, ev);
1280 tevent_req_set_callback(subreq, tstream_smbXcli_np_disconnect_done, req);
1282 return req;
1285 static void tstream_smbXcli_np_disconnect_done(struct tevent_req *subreq)
1287 struct tevent_req *req = tevent_req_callback_data(subreq,
1288 struct tevent_req);
1289 struct tstream_smbXcli_np_disconnect_state *state =
1290 tevent_req_data(req, struct tstream_smbXcli_np_disconnect_state);
1291 struct tstream_smbXcli_np *cli_nps =
1292 tstream_context_data(state->stream, struct tstream_smbXcli_np);
1293 NTSTATUS status;
1295 if (cli_nps->is_smb1) {
1296 status = smb1cli_close_recv(subreq);
1297 } else {
1298 status = smb2cli_close_recv(subreq);
1300 TALLOC_FREE(subreq);
1301 if (!NT_STATUS_IS_OK(status)) {
1302 tevent_req_error(req, EIO);
1303 return;
1306 cli_nps->conn = NULL;
1307 cli_nps->session = NULL;
1308 cli_nps->tcon = NULL;
1310 tevent_req_done(req);
1313 static int tstream_smbXcli_np_disconnect_recv(struct tevent_req *req,
1314 int *perrno)
1316 int ret;
1318 ret = tsocket_simple_int_recv(req, perrno);
1320 tevent_req_received(req);
1321 return ret;
1324 static const struct tstream_context_ops tstream_smbXcli_np_ops = {
1325 .name = "smbXcli_np",
1327 .pending_bytes = tstream_smbXcli_np_pending_bytes,
1329 .readv_send = tstream_smbXcli_np_readv_send,
1330 .readv_recv = tstream_smbXcli_np_readv_recv,
1332 .writev_send = tstream_smbXcli_np_writev_send,
1333 .writev_recv = tstream_smbXcli_np_writev_recv,
1335 .disconnect_send = tstream_smbXcli_np_disconnect_send,
1336 .disconnect_recv = tstream_smbXcli_np_disconnect_recv,