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_smbXcli_np_ops
;
32 #define TSTREAM_SMBXCLI_NP_DESIRED_ACCESS ( \
33 SEC_STD_READ_CONTROL | \
34 SEC_FILE_READ_DATA | \
35 SEC_FILE_WRITE_DATA | \
36 SEC_FILE_APPEND_DATA | \
39 SEC_FILE_READ_ATTRIBUTE | \
40 SEC_FILE_WRITE_ATTRIBUTE | \
43 struct tstream_smbXcli_np_ref
;
45 struct tstream_smbXcli_np
{
46 struct smbXcli_conn
*conn
;
47 struct tstream_smbXcli_np_ref
*conn_ref
;
48 struct smbXcli_session
*session
;
49 struct tstream_smbXcli_np_ref
*session_ref
;
50 struct smbXcli_tcon
*tcon
;
51 struct tstream_smbXcli_np_ref
*tcon_ref
;
58 uint64_t fid_persistent
;
59 uint64_t fid_volatile
;
63 struct tevent_req
*read_req
;
64 struct tevent_req
*write_req
;
75 struct tstream_smbXcli_np_ref
{
76 struct tstream_smbXcli_np
*cli_nps
;
79 static int tstream_smbXcli_np_destructor(struct tstream_smbXcli_np
*cli_nps
)
83 if (cli_nps
->conn_ref
!= NULL
) {
84 cli_nps
->conn_ref
->cli_nps
= NULL
;
85 TALLOC_FREE(cli_nps
->conn_ref
);
88 if (cli_nps
->session_ref
!= NULL
) {
89 cli_nps
->session_ref
->cli_nps
= NULL
;
90 TALLOC_FREE(cli_nps
->session_ref
);
93 if (cli_nps
->tcon_ref
!= NULL
) {
94 cli_nps
->tcon_ref
->cli_nps
= NULL
;
95 TALLOC_FREE(cli_nps
->tcon_ref
);
98 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
103 * TODO: do not use a sync call with a destructor!!!
105 * This only happens, if a caller does talloc_free(),
106 * while the everything was still ok.
108 * If we get an unexpected failure within a normal
109 * operation, we already do an async cli_close_send()/_recv().
111 * Once we've fixed all callers to call
112 * tstream_disconnect_send()/_recv(), this will
115 if (cli_nps
->is_smb1
) {
116 status
= smb1cli_close(cli_nps
->conn
,
121 cli_nps
->fnum
, UINT32_MAX
);
123 status
= smb2cli_close(cli_nps
->conn
,
128 cli_nps
->fid_persistent
,
129 cli_nps
->fid_volatile
);
131 if (!NT_STATUS_IS_OK(status
)) {
132 DEBUG(1, ("tstream_smbXcli_np_destructor: cli_close "
133 "failed on pipe %s. Error was %s\n",
134 cli_nps
->npipe
, nt_errstr(status
)));
137 * We can't do much on failure
142 static int tstream_smbXcli_np_ref_destructor(struct tstream_smbXcli_np_ref
*ref
)
144 if (ref
->cli_nps
== NULL
) {
148 if (ref
->cli_nps
->conn
== NULL
) {
152 ref
->cli_nps
->conn
= NULL
;
153 ref
->cli_nps
->session
= NULL
;
154 ref
->cli_nps
->tcon
= NULL
;
156 TALLOC_FREE(ref
->cli_nps
->conn_ref
);
157 TALLOC_FREE(ref
->cli_nps
->session_ref
);
158 TALLOC_FREE(ref
->cli_nps
->tcon_ref
);
163 static struct tevent_req
*tstream_smbXcli_np_disconnect_send(TALLOC_CTX
*mem_ctx
,
164 struct tevent_context
*ev
,
165 struct tstream_context
*stream
);
166 static int tstream_smbXcli_np_disconnect_recv(struct tevent_req
*req
,
169 struct tstream_smbXcli_np_open_state
{
170 struct smbXcli_conn
*conn
;
171 struct smbXcli_session
*session
;
172 struct smbXcli_tcon
*tcon
;
174 unsigned int timeout
;
178 uint64_t fid_persistent
;
179 uint64_t fid_volatile
;
183 static void tstream_smbXcli_np_open_done(struct tevent_req
*subreq
);
185 struct tevent_req
*tstream_smbXcli_np_open_send(TALLOC_CTX
*mem_ctx
,
186 struct tevent_context
*ev
,
187 struct smbXcli_conn
*conn
,
188 struct smbXcli_session
*session
,
189 struct smbXcli_tcon
*tcon
,
191 unsigned int timeout
,
194 struct tevent_req
*req
;
195 struct tstream_smbXcli_np_open_state
*state
;
196 struct tevent_req
*subreq
;
198 req
= tevent_req_create(mem_ctx
, &state
,
199 struct tstream_smbXcli_np_open_state
);
205 state
->session
= session
;
207 state
->timeout
= timeout
;
209 state
->npipe
= talloc_strdup(state
, npipe
);
210 if (tevent_req_nomem(state
->npipe
, req
)) {
211 return tevent_req_post(req
, ev
);
214 if (smbXcli_conn_protocol(conn
) < PROTOCOL_SMB2_02
) {
215 state
->is_smb1
= true;
218 if (state
->is_smb1
) {
219 const char *smb1_npipe
;
222 * Windows and newer Samba versions allow
223 * the pipe name without leading backslash,
224 * but we should better behave like windows clients
226 smb1_npipe
= talloc_asprintf(state
, "\\%s", state
->npipe
);
227 if (tevent_req_nomem(smb1_npipe
, req
)) {
228 return tevent_req_post(req
, ev
);
230 subreq
= smb1cli_ntcreatex_send(state
, ev
, state
->conn
,
237 0, /* RootDirectoryFid */
238 TSTREAM_SMBXCLI_NP_DESIRED_ACCESS
,
239 0, /* AllocationSize */
240 0, /* FileAttributes */
241 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
242 FILE_OPEN
, /* CreateDisposition */
243 0, /* CreateOptions */
244 2, /* NTCREATEX_IMPERSONATION_IMPERSONATION */
245 0); /* SecurityFlags */
247 subreq
= smb2cli_create_send(state
, ev
, state
->conn
,
248 state
->timeout
, state
->session
,
251 SMB2_OPLOCK_LEVEL_NONE
,
252 SMB2_IMPERSONATION_IMPERSONATION
,
253 TSTREAM_SMBXCLI_NP_DESIRED_ACCESS
,
254 0, /* file_attributes */
255 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
257 0, /* create_options */
260 if (tevent_req_nomem(subreq
, req
)) {
261 return tevent_req_post(req
, ev
);
263 tevent_req_set_callback(subreq
, tstream_smbXcli_np_open_done
, req
);
268 static void tstream_smbXcli_np_open_done(struct tevent_req
*subreq
)
270 struct tevent_req
*req
=
271 tevent_req_callback_data(subreq
, struct tevent_req
);
272 struct tstream_smbXcli_np_open_state
*state
=
273 tevent_req_data(req
, struct tstream_smbXcli_np_open_state
);
276 if (state
->is_smb1
) {
277 status
= smb1cli_ntcreatex_recv(subreq
, &state
->fnum
);
279 status
= smb2cli_create_recv(subreq
,
280 &state
->fid_persistent
,
281 &state
->fid_volatile
,
285 if (!NT_STATUS_IS_OK(status
)) {
286 tevent_req_nterror(req
, status
);
290 tevent_req_done(req
);
293 NTSTATUS
_tstream_smbXcli_np_open_recv(struct tevent_req
*req
,
295 struct tstream_context
**_stream
,
296 const char *location
)
298 struct tstream_smbXcli_np_open_state
*state
=
299 tevent_req_data(req
, struct tstream_smbXcli_np_open_state
);
300 struct tstream_context
*stream
;
301 struct tstream_smbXcli_np
*cli_nps
;
304 if (tevent_req_is_nterror(req
, &status
)) {
305 tevent_req_received(req
);
309 stream
= tstream_context_create(mem_ctx
,
310 &tstream_smbXcli_np_ops
,
312 struct tstream_smbXcli_np
,
315 tevent_req_received(req
);
316 return NT_STATUS_NO_MEMORY
;
318 ZERO_STRUCTP(cli_nps
);
320 cli_nps
->conn_ref
= talloc_zero(state
->conn
,
321 struct tstream_smbXcli_np_ref
);
322 if (cli_nps
->conn_ref
== NULL
) {
323 TALLOC_FREE(cli_nps
);
324 tevent_req_received(req
);
325 return NT_STATUS_NO_MEMORY
;
327 cli_nps
->conn_ref
->cli_nps
= cli_nps
;
329 cli_nps
->session_ref
= talloc_zero(state
->session
,
330 struct tstream_smbXcli_np_ref
);
331 if (cli_nps
->session_ref
== NULL
) {
332 TALLOC_FREE(cli_nps
);
333 tevent_req_received(req
);
334 return NT_STATUS_NO_MEMORY
;
336 cli_nps
->session_ref
->cli_nps
= cli_nps
;
338 cli_nps
->tcon_ref
= talloc_zero(state
->tcon
,
339 struct tstream_smbXcli_np_ref
);
340 if (cli_nps
->tcon_ref
== NULL
) {
341 TALLOC_FREE(cli_nps
);
342 tevent_req_received(req
);
343 return NT_STATUS_NO_MEMORY
;
345 cli_nps
->tcon_ref
->cli_nps
= cli_nps
;
347 cli_nps
->conn
= state
->conn
;
348 cli_nps
->session
= state
->session
;
349 cli_nps
->tcon
= state
->tcon
;
350 cli_nps
->pid
= state
->pid
;
351 cli_nps
->timeout
= state
->timeout
;
352 cli_nps
->npipe
= talloc_move(cli_nps
, &state
->npipe
);
353 cli_nps
->is_smb1
= state
->is_smb1
;
354 cli_nps
->fnum
= state
->fnum
;
355 cli_nps
->fid_persistent
= state
->fid_persistent
;
356 cli_nps
->fid_volatile
= state
->fid_volatile
;
358 talloc_set_destructor(cli_nps
, tstream_smbXcli_np_destructor
);
359 talloc_set_destructor(cli_nps
->conn_ref
,
360 tstream_smbXcli_np_ref_destructor
);
361 talloc_set_destructor(cli_nps
->session_ref
,
362 tstream_smbXcli_np_ref_destructor
);
363 talloc_set_destructor(cli_nps
->tcon_ref
,
364 tstream_smbXcli_np_ref_destructor
);
366 cli_nps
->trans
.active
= false;
367 cli_nps
->trans
.read_req
= NULL
;
368 cli_nps
->trans
.write_req
= NULL
;
369 SSVAL(cli_nps
->trans
.setup
+0, 0, TRANSACT_DCERPCCMD
);
370 SSVAL(cli_nps
->trans
.setup
+1, 0, cli_nps
->fnum
);
373 tevent_req_received(req
);
377 static ssize_t
tstream_smbXcli_np_pending_bytes(struct tstream_context
*stream
)
379 struct tstream_smbXcli_np
*cli_nps
= tstream_context_data(stream
,
380 struct tstream_smbXcli_np
);
382 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
387 return cli_nps
->read
.left
;
390 bool tstream_is_smbXcli_np(struct tstream_context
*stream
)
392 struct tstream_smbXcli_np
*cli_nps
=
393 talloc_get_type(_tstream_context_data(stream
),
394 struct tstream_smbXcli_np
);
403 NTSTATUS
tstream_smbXcli_np_use_trans(struct tstream_context
*stream
)
405 struct tstream_smbXcli_np
*cli_nps
= tstream_context_data(stream
,
406 struct tstream_smbXcli_np
);
408 if (cli_nps
->trans
.read_req
) {
409 return NT_STATUS_PIPE_BUSY
;
412 if (cli_nps
->trans
.write_req
) {
413 return NT_STATUS_PIPE_BUSY
;
416 if (cli_nps
->trans
.active
) {
417 return NT_STATUS_PIPE_BUSY
;
420 cli_nps
->trans
.active
= true;
425 unsigned int tstream_smbXcli_np_set_timeout(struct tstream_context
*stream
,
426 unsigned int timeout
)
428 struct tstream_smbXcli_np
*cli_nps
= tstream_context_data(stream
,
429 struct tstream_smbXcli_np
);
430 unsigned int old_timeout
= cli_nps
->timeout
;
432 cli_nps
->timeout
= timeout
;
436 struct tstream_smbXcli_np_writev_state
{
437 struct tstream_context
*stream
;
438 struct tevent_context
*ev
;
440 struct iovec
*vector
;
447 const char *location
;
451 static int tstream_smbXcli_np_writev_state_destructor(struct tstream_smbXcli_np_writev_state
*state
)
453 struct tstream_smbXcli_np
*cli_nps
=
454 tstream_context_data(state
->stream
,
455 struct tstream_smbXcli_np
);
457 cli_nps
->trans
.write_req
= NULL
;
462 static void tstream_smbXcli_np_writev_write_next(struct tevent_req
*req
);
464 static struct tevent_req
*tstream_smbXcli_np_writev_send(TALLOC_CTX
*mem_ctx
,
465 struct tevent_context
*ev
,
466 struct tstream_context
*stream
,
467 const struct iovec
*vector
,
470 struct tevent_req
*req
;
471 struct tstream_smbXcli_np_writev_state
*state
;
472 struct tstream_smbXcli_np
*cli_nps
= tstream_context_data(stream
,
473 struct tstream_smbXcli_np
);
475 req
= tevent_req_create(mem_ctx
, &state
,
476 struct tstream_smbXcli_np_writev_state
);
480 state
->stream
= stream
;
484 talloc_set_destructor(state
, tstream_smbXcli_np_writev_state_destructor
);
486 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
487 tevent_req_error(req
, ENOTCONN
);
488 return tevent_req_post(req
, ev
);
492 * we make a copy of the vector so we can change the structure
494 state
->vector
= talloc_array(state
, struct iovec
, count
);
495 if (tevent_req_nomem(state
->vector
, req
)) {
496 return tevent_req_post(req
, ev
);
498 memcpy(state
->vector
, vector
, sizeof(struct iovec
) * count
);
499 state
->count
= count
;
501 tstream_smbXcli_np_writev_write_next(req
);
502 if (!tevent_req_is_in_progress(req
)) {
503 return tevent_req_post(req
, ev
);
509 static void tstream_smbXcli_np_readv_trans_start(struct tevent_req
*req
);
510 static void tstream_smbXcli_np_writev_write_done(struct tevent_req
*subreq
);
512 static void tstream_smbXcli_np_writev_write_next(struct tevent_req
*req
)
514 struct tstream_smbXcli_np_writev_state
*state
=
516 struct tstream_smbXcli_np_writev_state
);
517 struct tstream_smbXcli_np
*cli_nps
=
518 tstream_context_data(state
->stream
,
519 struct tstream_smbXcli_np
);
520 struct tevent_req
*subreq
;
524 for (i
=0; i
< state
->count
; i
++) {
525 left
+= state
->vector
[i
].iov_len
;
529 TALLOC_FREE(cli_nps
->write
.buf
);
530 tevent_req_done(req
);
534 cli_nps
->write
.ofs
= 0;
535 cli_nps
->write
.left
= MIN(left
, TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE
);
536 cli_nps
->write
.buf
= talloc_realloc(cli_nps
, cli_nps
->write
.buf
,
537 uint8_t, cli_nps
->write
.left
);
538 if (tevent_req_nomem(cli_nps
->write
.buf
, req
)) {
543 * copy the pending buffer first
545 while (cli_nps
->write
.left
> 0 && state
->count
> 0) {
546 uint8_t *base
= (uint8_t *)state
->vector
[0].iov_base
;
547 size_t len
= MIN(cli_nps
->write
.left
, state
->vector
[0].iov_len
);
549 memcpy(cli_nps
->write
.buf
+ cli_nps
->write
.ofs
, base
, len
);
552 state
->vector
[0].iov_base
= base
;
553 state
->vector
[0].iov_len
-= len
;
555 cli_nps
->write
.ofs
+= len
;
556 cli_nps
->write
.left
-= len
;
558 if (state
->vector
[0].iov_len
== 0) {
566 if (cli_nps
->trans
.active
&& state
->count
== 0) {
567 cli_nps
->trans
.active
= false;
568 cli_nps
->trans
.write_req
= req
;
572 if (cli_nps
->trans
.read_req
&& state
->count
== 0) {
573 cli_nps
->trans
.write_req
= req
;
574 tstream_smbXcli_np_readv_trans_start(cli_nps
->trans
.read_req
);
578 if (cli_nps
->is_smb1
) {
579 subreq
= smb1cli_writex_send(state
, state
->ev
,
586 8, /* 8 means message mode. */
589 cli_nps
->write
.ofs
); /* size */
591 subreq
= smb2cli_write_send(state
, state
->ev
,
596 cli_nps
->write
.ofs
, /* length */
598 cli_nps
->fid_persistent
,
599 cli_nps
->fid_volatile
,
600 0, /* remaining_bytes */
604 if (tevent_req_nomem(subreq
, req
)) {
607 tevent_req_set_callback(subreq
,
608 tstream_smbXcli_np_writev_write_done
,
612 static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req
*req
,
614 const char *location
);
616 static void tstream_smbXcli_np_writev_write_done(struct tevent_req
*subreq
)
618 struct tevent_req
*req
=
619 tevent_req_callback_data(subreq
, struct tevent_req
);
620 struct tstream_smbXcli_np_writev_state
*state
=
621 tevent_req_data(req
, struct tstream_smbXcli_np_writev_state
);
622 struct tstream_smbXcli_np
*cli_nps
=
623 tstream_context_data(state
->stream
,
624 struct tstream_smbXcli_np
);
628 if (cli_nps
->is_smb1
) {
629 status
= smb1cli_writex_recv(subreq
, &written
, NULL
);
631 status
= smb2cli_write_recv(subreq
, &written
);
634 if (!NT_STATUS_IS_OK(status
)) {
635 tstream_smbXcli_np_writev_disconnect_now(req
, EIO
, __location__
);
639 if (written
!= cli_nps
->write
.ofs
) {
640 tstream_smbXcli_np_writev_disconnect_now(req
, EIO
, __location__
);
644 tstream_smbXcli_np_writev_write_next(req
);
647 static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req
*subreq
);
649 static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req
*req
,
651 const char *location
)
653 struct tstream_smbXcli_np_writev_state
*state
=
655 struct tstream_smbXcli_np_writev_state
);
656 struct tstream_smbXcli_np
*cli_nps
=
657 tstream_context_data(state
->stream
,
658 struct tstream_smbXcli_np
);
659 struct tevent_req
*subreq
;
661 state
->error
.val
= error
;
662 state
->error
.location
= location
;
664 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
665 /* return the original error */
666 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
670 subreq
= tstream_smbXcli_np_disconnect_send(state
, state
->ev
,
672 if (subreq
== NULL
) {
673 /* return the original error */
674 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
677 tevent_req_set_callback(subreq
,
678 tstream_smbXcli_np_writev_disconnect_done
,
682 static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req
*subreq
)
684 struct tevent_req
*req
=
685 tevent_req_callback_data(subreq
, struct tevent_req
);
686 struct tstream_smbXcli_np_writev_state
*state
=
687 tevent_req_data(req
, struct tstream_smbXcli_np_writev_state
);
690 tstream_smbXcli_np_disconnect_recv(subreq
, &error
);
693 /* return the original error */
694 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
697 static int tstream_smbXcli_np_writev_recv(struct tevent_req
*req
,
700 struct tstream_smbXcli_np_writev_state
*state
=
702 struct tstream_smbXcli_np_writev_state
);
705 ret
= tsocket_simple_int_recv(req
, perrno
);
710 tevent_req_received(req
);
714 struct tstream_smbXcli_np_readv_state
{
715 struct tstream_context
*stream
;
716 struct tevent_context
*ev
;
718 struct iovec
*vector
;
724 struct tevent_immediate
*im
;
729 const char *location
;
733 static int tstream_smbXcli_np_readv_state_destructor(struct tstream_smbXcli_np_readv_state
*state
)
735 struct tstream_smbXcli_np
*cli_nps
=
736 tstream_context_data(state
->stream
,
737 struct tstream_smbXcli_np
);
739 cli_nps
->trans
.read_req
= NULL
;
744 static void tstream_smbXcli_np_readv_read_next(struct tevent_req
*req
);
746 static struct tevent_req
*tstream_smbXcli_np_readv_send(TALLOC_CTX
*mem_ctx
,
747 struct tevent_context
*ev
,
748 struct tstream_context
*stream
,
749 struct iovec
*vector
,
752 struct tevent_req
*req
;
753 struct tstream_smbXcli_np_readv_state
*state
;
754 struct tstream_smbXcli_np
*cli_nps
=
755 tstream_context_data(stream
, struct tstream_smbXcli_np
);
757 req
= tevent_req_create(mem_ctx
, &state
,
758 struct tstream_smbXcli_np_readv_state
);
762 state
->stream
= stream
;
766 talloc_set_destructor(state
, tstream_smbXcli_np_readv_state_destructor
);
768 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
769 tevent_req_error(req
, ENOTCONN
);
770 return tevent_req_post(req
, ev
);
774 * we make a copy of the vector so we can change the structure
776 state
->vector
= talloc_array(state
, struct iovec
, count
);
777 if (tevent_req_nomem(state
->vector
, req
)) {
778 return tevent_req_post(req
, ev
);
780 memcpy(state
->vector
, vector
, sizeof(struct iovec
) * count
);
781 state
->count
= count
;
783 tstream_smbXcli_np_readv_read_next(req
);
784 if (!tevent_req_is_in_progress(req
)) {
785 return tevent_req_post(req
, ev
);
791 static void tstream_smbXcli_np_readv_read_done(struct tevent_req
*subreq
);
793 static void tstream_smbXcli_np_readv_read_next(struct tevent_req
*req
)
795 struct tstream_smbXcli_np_readv_state
*state
=
797 struct tstream_smbXcli_np_readv_state
);
798 struct tstream_smbXcli_np
*cli_nps
=
799 tstream_context_data(state
->stream
,
800 struct tstream_smbXcli_np
);
801 struct tevent_req
*subreq
;
804 * copy the pending buffer first
806 while (cli_nps
->read
.left
> 0 && state
->count
> 0) {
807 uint8_t *base
= (uint8_t *)state
->vector
[0].iov_base
;
808 size_t len
= MIN(cli_nps
->read
.left
, state
->vector
[0].iov_len
);
810 memcpy(base
, cli_nps
->read
.buf
+ cli_nps
->read
.ofs
, len
);
813 state
->vector
[0].iov_base
= base
;
814 state
->vector
[0].iov_len
-= len
;
816 cli_nps
->read
.ofs
+= len
;
817 cli_nps
->read
.left
-= len
;
819 if (state
->vector
[0].iov_len
== 0) {
827 if (cli_nps
->read
.left
== 0) {
828 TALLOC_FREE(cli_nps
->read
.buf
);
831 if (state
->count
== 0) {
832 tevent_req_done(req
);
836 if (cli_nps
->trans
.active
) {
837 cli_nps
->trans
.active
= false;
838 cli_nps
->trans
.read_req
= req
;
842 if (cli_nps
->trans
.write_req
) {
843 cli_nps
->trans
.read_req
= req
;
844 tstream_smbXcli_np_readv_trans_start(req
);
848 if (cli_nps
->is_smb1
) {
849 subreq
= smb1cli_readx_send(state
, state
->ev
,
857 TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE
);
859 subreq
= smb2cli_read_send(state
, state
->ev
,
864 TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE
, /* length */
866 cli_nps
->fid_persistent
,
867 cli_nps
->fid_volatile
,
868 0, /* minimum_count */
869 0); /* remaining_bytes */
871 if (tevent_req_nomem(subreq
, req
)) {
874 tevent_req_set_callback(subreq
,
875 tstream_smbXcli_np_readv_read_done
,
879 static void tstream_smbXcli_np_readv_trans_done(struct tevent_req
*subreq
);
881 static void tstream_smbXcli_np_readv_trans_start(struct tevent_req
*req
)
883 struct tstream_smbXcli_np_readv_state
*state
=
885 struct tstream_smbXcli_np_readv_state
);
886 struct tstream_smbXcli_np
*cli_nps
=
887 tstream_context_data(state
->stream
,
888 struct tstream_smbXcli_np
);
889 struct tevent_req
*subreq
;
891 state
->trans
.im
= tevent_create_immediate(state
);
892 if (tevent_req_nomem(state
->trans
.im
, req
)) {
896 if (cli_nps
->is_smb1
) {
897 subreq
= smb1cli_trans_send(state
, state
->ev
,
898 cli_nps
->conn
, SMBtrans
,
907 cli_nps
->trans
.setup
, 2,
912 TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE
);
914 DATA_BLOB in_input_buffer
= data_blob_null
;
915 DATA_BLOB in_output_buffer
= data_blob_null
;
917 in_input_buffer
= data_blob_const(cli_nps
->write
.buf
,
920 subreq
= smb2cli_ioctl_send(state
, state
->ev
,
925 cli_nps
->fid_persistent
,
926 cli_nps
->fid_volatile
,
927 FSCTL_NAMED_PIPE_READ_WRITE
,
928 0, /* in_max_input_length */
930 /* in_max_output_length */
931 TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE
,
933 SMB2_IOCTL_FLAG_IS_FSCTL
);
935 if (tevent_req_nomem(subreq
, req
)) {
938 tevent_req_set_callback(subreq
,
939 tstream_smbXcli_np_readv_trans_done
,
943 static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req
*req
,
945 const char *location
);
946 static void tstream_smbXcli_np_readv_trans_next(struct tevent_context
*ctx
,
947 struct tevent_immediate
*im
,
950 static void tstream_smbXcli_np_readv_trans_done(struct tevent_req
*subreq
)
952 struct tevent_req
*req
=
953 tevent_req_callback_data(subreq
, struct tevent_req
);
954 struct tstream_smbXcli_np_readv_state
*state
=
955 tevent_req_data(req
, struct tstream_smbXcli_np_readv_state
);
956 struct tstream_smbXcli_np
*cli_nps
=
957 tstream_context_data(state
->stream
, struct tstream_smbXcli_np
);
962 if (cli_nps
->is_smb1
) {
963 status
= smb1cli_trans_recv(subreq
, state
, NULL
, NULL
, 0, NULL
,
965 &rcvbuf
, 0, &received
);
967 DATA_BLOB out_input_buffer
= data_blob_null
;
968 DATA_BLOB out_output_buffer
= data_blob_null
;
970 status
= smb2cli_ioctl_recv(subreq
, state
,
974 /* Note that rcvbuf is not a talloc pointer here */
975 rcvbuf
= out_output_buffer
.data
;
976 received
= out_output_buffer
.length
;
979 if (NT_STATUS_EQUAL(status
, NT_STATUS_BUFFER_TOO_SMALL
)) {
980 status
= NT_STATUS_OK
;
982 if (!NT_STATUS_IS_OK(status
)) {
983 tstream_smbXcli_np_readv_disconnect_now(req
, EIO
, __location__
);
987 if (received
> TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE
) {
988 tstream_smbXcli_np_readv_disconnect_now(req
, EIO
, __location__
);
993 tstream_smbXcli_np_readv_disconnect_now(req
, EPIPE
, __location__
);
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
);
1005 memcpy(cli_nps
->read
.buf
, rcvbuf
, received
);
1007 if (cli_nps
->trans
.write_req
== NULL
) {
1008 tstream_smbXcli_np_readv_read_next(req
);
1012 tevent_schedule_immediate(state
->trans
.im
, state
->ev
,
1013 tstream_smbXcli_np_readv_trans_next
, req
);
1015 tevent_req_done(cli_nps
->trans
.write_req
);
1018 static void tstream_smbXcli_np_readv_trans_next(struct tevent_context
*ctx
,
1019 struct tevent_immediate
*im
,
1022 struct tevent_req
*req
=
1023 talloc_get_type_abort(private_data
,
1026 tstream_smbXcli_np_readv_read_next(req
);
1029 static void tstream_smbXcli_np_readv_read_done(struct tevent_req
*subreq
)
1031 struct tevent_req
*req
=
1032 tevent_req_callback_data(subreq
, struct tevent_req
);
1033 struct tstream_smbXcli_np_readv_state
*state
=
1034 tevent_req_data(req
, struct tstream_smbXcli_np_readv_state
);
1035 struct tstream_smbXcli_np
*cli_nps
=
1036 tstream_context_data(state
->stream
, struct tstream_smbXcli_np
);
1042 * We must free subreq in this function as there is
1043 * a timer event attached to it.
1046 if (cli_nps
->is_smb1
) {
1047 status
= smb1cli_readx_recv(subreq
, &received
, &rcvbuf
);
1049 status
= smb2cli_read_recv(subreq
, state
, &rcvbuf
, &received
);
1052 * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
1055 if (NT_STATUS_EQUAL(status
, NT_STATUS_BUFFER_TOO_SMALL
)) {
1057 * NT_STATUS_BUFFER_TOO_SMALL means that there's
1058 * more data to read when the named pipe is used
1059 * in message mode (which is the case here).
1061 * But we hide this from the caller.
1063 status
= NT_STATUS_OK
;
1065 if (!NT_STATUS_IS_OK(status
)) {
1066 TALLOC_FREE(subreq
);
1067 tstream_smbXcli_np_readv_disconnect_now(req
, EIO
, __location__
);
1071 if (received
> TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE
) {
1072 TALLOC_FREE(subreq
);
1073 tstream_smbXcli_np_readv_disconnect_now(req
, EIO
, __location__
);
1077 if (received
== 0) {
1078 TALLOC_FREE(subreq
);
1079 tstream_smbXcli_np_readv_disconnect_now(req
, EPIPE
, __location__
);
1083 cli_nps
->read
.ofs
= 0;
1084 cli_nps
->read
.left
= received
;
1085 cli_nps
->read
.buf
= talloc_array(cli_nps
, uint8_t, received
);
1086 if (cli_nps
->read
.buf
== NULL
) {
1087 TALLOC_FREE(subreq
);
1088 tevent_req_nomem(cli_nps
->read
.buf
, req
);
1091 memcpy(cli_nps
->read
.buf
, rcvbuf
, received
);
1092 TALLOC_FREE(subreq
);
1094 tstream_smbXcli_np_readv_read_next(req
);
1097 static void tstream_smbXcli_np_readv_disconnect_done(struct tevent_req
*subreq
);
1099 static void tstream_smbXcli_np_readv_error(struct tevent_req
*req
);
1101 static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req
*req
,
1103 const char *location
)
1105 struct tstream_smbXcli_np_readv_state
*state
=
1106 tevent_req_data(req
,
1107 struct tstream_smbXcli_np_readv_state
);
1108 struct tstream_smbXcli_np
*cli_nps
=
1109 tstream_context_data(state
->stream
,
1110 struct tstream_smbXcli_np
);
1111 struct tevent_req
*subreq
;
1113 state
->error
.val
= error
;
1114 state
->error
.location
= location
;
1116 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
1117 /* return the original error */
1118 tstream_smbXcli_np_readv_error(req
);
1122 subreq
= tstream_smbXcli_np_disconnect_send(state
, state
->ev
,
1124 if (subreq
== NULL
) {
1125 /* return the original error */
1126 tstream_smbXcli_np_readv_error(req
);
1129 tevent_req_set_callback(subreq
,
1130 tstream_smbXcli_np_readv_disconnect_done
,
1134 static void tstream_smbXcli_np_readv_disconnect_done(struct tevent_req
*subreq
)
1136 struct tevent_req
*req
=
1137 tevent_req_callback_data(subreq
, struct tevent_req
);
1140 tstream_smbXcli_np_disconnect_recv(subreq
, &error
);
1141 TALLOC_FREE(subreq
);
1143 tstream_smbXcli_np_readv_error(req
);
1146 static void tstream_smbXcli_np_readv_error_trigger(struct tevent_context
*ctx
,
1147 struct tevent_immediate
*im
,
1148 void *private_data
);
1150 static void tstream_smbXcli_np_readv_error(struct tevent_req
*req
)
1152 struct tstream_smbXcli_np_readv_state
*state
=
1153 tevent_req_data(req
,
1154 struct tstream_smbXcli_np_readv_state
);
1155 struct tstream_smbXcli_np
*cli_nps
=
1156 tstream_context_data(state
->stream
,
1157 struct tstream_smbXcli_np
);
1159 if (cli_nps
->trans
.write_req
== NULL
) {
1160 /* return the original error */
1161 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
1165 if (state
->trans
.im
== NULL
) {
1166 /* return the original error */
1167 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
1171 tevent_schedule_immediate(state
->trans
.im
, state
->ev
,
1172 tstream_smbXcli_np_readv_error_trigger
, req
);
1174 /* return the original error for writev */
1175 _tevent_req_error(cli_nps
->trans
.write_req
,
1176 state
->error
.val
, state
->error
.location
);
1179 static void tstream_smbXcli_np_readv_error_trigger(struct tevent_context
*ctx
,
1180 struct tevent_immediate
*im
,
1183 struct tevent_req
*req
=
1184 talloc_get_type_abort(private_data
,
1186 struct tstream_smbXcli_np_readv_state
*state
=
1187 tevent_req_data(req
,
1188 struct tstream_smbXcli_np_readv_state
);
1190 /* return the original error */
1191 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
1194 static int tstream_smbXcli_np_readv_recv(struct tevent_req
*req
,
1197 struct tstream_smbXcli_np_readv_state
*state
=
1198 tevent_req_data(req
, struct tstream_smbXcli_np_readv_state
);
1201 ret
= tsocket_simple_int_recv(req
, perrno
);
1206 tevent_req_received(req
);
1210 struct tstream_smbXcli_np_disconnect_state
{
1211 struct tstream_context
*stream
;
1212 struct tevent_req
*subreq
;
1215 static void tstream_smbXcli_np_disconnect_done(struct tevent_req
*subreq
);
1216 static void tstream_smbXcli_np_disconnect_cleanup(struct tevent_req
*req
,
1217 enum tevent_req_state req_state
);
1219 static struct tevent_req
*tstream_smbXcli_np_disconnect_send(TALLOC_CTX
*mem_ctx
,
1220 struct tevent_context
*ev
,
1221 struct tstream_context
*stream
)
1223 struct tstream_smbXcli_np
*cli_nps
= tstream_context_data(stream
,
1224 struct tstream_smbXcli_np
);
1225 struct tevent_req
*req
;
1226 struct tstream_smbXcli_np_disconnect_state
*state
;
1227 struct tevent_req
*subreq
;
1229 req
= tevent_req_create(mem_ctx
, &state
,
1230 struct tstream_smbXcli_np_disconnect_state
);
1235 state
->stream
= stream
;
1237 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
1238 tevent_req_error(req
, ENOTCONN
);
1239 return tevent_req_post(req
, ev
);
1242 if (cli_nps
->is_smb1
) {
1243 subreq
= smb1cli_close_send(state
, ev
, cli_nps
->conn
,
1248 cli_nps
->fnum
, UINT32_MAX
);
1250 subreq
= smb2cli_close_send(state
, ev
, cli_nps
->conn
,
1255 cli_nps
->fid_persistent
,
1256 cli_nps
->fid_volatile
);
1258 if (tevent_req_nomem(subreq
, req
)) {
1259 return tevent_req_post(req
, ev
);
1261 tevent_req_set_callback(subreq
, tstream_smbXcli_np_disconnect_done
, req
);
1262 state
->subreq
= subreq
;
1264 tevent_req_set_cleanup_fn(req
, tstream_smbXcli_np_disconnect_cleanup
);
1267 * Make sure we don't send any requests anymore.
1269 cli_nps
->conn
= NULL
;
1274 static void tstream_smbXcli_np_disconnect_done(struct tevent_req
*subreq
)
1276 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
1278 struct tstream_smbXcli_np_disconnect_state
*state
=
1279 tevent_req_data(req
, struct tstream_smbXcli_np_disconnect_state
);
1280 struct tstream_smbXcli_np
*cli_nps
=
1281 tstream_context_data(state
->stream
, struct tstream_smbXcli_np
);
1284 state
->subreq
= NULL
;
1286 if (cli_nps
->is_smb1
) {
1287 status
= smb1cli_close_recv(subreq
);
1289 status
= smb2cli_close_recv(subreq
);
1291 TALLOC_FREE(subreq
);
1292 if (!NT_STATUS_IS_OK(status
)) {
1293 tevent_req_error(req
, EIO
);
1297 cli_nps
->conn
= NULL
;
1298 cli_nps
->session
= NULL
;
1299 cli_nps
->tcon
= NULL
;
1301 tevent_req_done(req
);
1304 static void tstream_smbXcli_np_disconnect_free(struct tevent_req
*subreq
);
1306 static void tstream_smbXcli_np_disconnect_cleanup(struct tevent_req
*req
,
1307 enum tevent_req_state req_state
)
1309 struct tstream_smbXcli_np_disconnect_state
*state
=
1310 tevent_req_data(req
, struct tstream_smbXcli_np_disconnect_state
);
1311 struct tstream_smbXcli_np
*cli_nps
= NULL
;
1313 if (state
->subreq
== NULL
) {
1317 cli_nps
= tstream_context_data(state
->stream
, struct tstream_smbXcli_np
);
1319 if (cli_nps
->tcon
== NULL
) {
1324 * We're no longer interested in the result
1325 * any more, but need to make sure that the close
1326 * request arrives at the server if the smb connection,
1327 * session and tcon are still alive.
1329 * We move the low level request to the tcon,
1330 * which means that it stays as long as the tcon
1333 talloc_steal(cli_nps
->tcon
, state
->subreq
);
1334 tevent_req_set_callback(state
->subreq
,
1335 tstream_smbXcli_np_disconnect_free
,
1337 state
->subreq
= NULL
;
1339 cli_nps
->conn
= NULL
;
1340 cli_nps
->session
= NULL
;
1341 cli_nps
->tcon
= NULL
;
1344 static void tstream_smbXcli_np_disconnect_free(struct tevent_req
*subreq
)
1346 TALLOC_FREE(subreq
);
1349 static int tstream_smbXcli_np_disconnect_recv(struct tevent_req
*req
,
1354 ret
= tsocket_simple_int_recv(req
, perrno
);
1356 tevent_req_received(req
);
1360 static const struct tstream_context_ops tstream_smbXcli_np_ops
= {
1361 .name
= "smbXcli_np",
1363 .pending_bytes
= tstream_smbXcli_np_pending_bytes
,
1365 .readv_send
= tstream_smbXcli_np_readv_send
,
1366 .readv_recv
= tstream_smbXcli_np_readv_recv
,
1368 .writev_send
= tstream_smbXcli_np_writev_send
,
1369 .writev_recv
= tstream_smbXcli_np_writev_recv
,
1371 .disconnect_send
= tstream_smbXcli_np_disconnect_send
,
1372 .disconnect_recv
= tstream_smbXcli_np_disconnect_recv
,