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
;
64 struct tevent_req
*read_req
;
65 struct tevent_req
*write_req
;
76 struct tstream_smbXcli_np_ref
{
77 struct tstream_smbXcli_np
*cli_nps
;
80 static int tstream_smbXcli_np_destructor(struct tstream_smbXcli_np
*cli_nps
)
84 if (cli_nps
->conn_ref
!= NULL
) {
85 cli_nps
->conn_ref
->cli_nps
= NULL
;
86 TALLOC_FREE(cli_nps
->conn_ref
);
89 if (cli_nps
->session_ref
!= NULL
) {
90 cli_nps
->session_ref
->cli_nps
= NULL
;
91 TALLOC_FREE(cli_nps
->session_ref
);
94 if (cli_nps
->tcon_ref
!= NULL
) {
95 cli_nps
->tcon_ref
->cli_nps
= NULL
;
96 TALLOC_FREE(cli_nps
->tcon_ref
);
99 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
104 * TODO: do not use a sync call with a destructor!!!
106 * This only happens, if a caller does talloc_free(),
107 * while the everything was still ok.
109 * If we get an unexpected failure within a normal
110 * operation, we already do an async cli_close_send()/_recv().
112 * Once we've fixed all callers to call
113 * tstream_disconnect_send()/_recv(), this will
116 * We use a maximum timeout of 1 second == 1000 msec.
118 cli_nps
->timeout
= MIN(cli_nps
->timeout
, 1000);
120 if (cli_nps
->is_smb1
) {
121 status
= smb1cli_close(cli_nps
->conn
,
126 cli_nps
->fnum
, UINT32_MAX
);
128 status
= smb2cli_close(cli_nps
->conn
,
133 cli_nps
->fid_persistent
,
134 cli_nps
->fid_volatile
);
136 if (!NT_STATUS_IS_OK(status
)) {
137 DEBUG(1, ("tstream_smbXcli_np_destructor: cli_close "
138 "failed on pipe %s. Error was %s\n",
139 cli_nps
->npipe
, nt_errstr(status
)));
142 * We can't do much on failure
147 static int tstream_smbXcli_np_ref_destructor(struct tstream_smbXcli_np_ref
*ref
)
149 if (ref
->cli_nps
== NULL
) {
153 if (ref
->cli_nps
->conn
== NULL
) {
157 ref
->cli_nps
->conn
= NULL
;
158 ref
->cli_nps
->session
= NULL
;
159 ref
->cli_nps
->tcon
= NULL
;
161 TALLOC_FREE(ref
->cli_nps
->conn_ref
);
162 TALLOC_FREE(ref
->cli_nps
->session_ref
);
163 TALLOC_FREE(ref
->cli_nps
->tcon_ref
);
168 static struct tevent_req
*tstream_smbXcli_np_disconnect_send(TALLOC_CTX
*mem_ctx
,
169 struct tevent_context
*ev
,
170 struct tstream_context
*stream
);
171 static int tstream_smbXcli_np_disconnect_recv(struct tevent_req
*req
,
174 struct tstream_smbXcli_np_open_state
{
175 struct smbXcli_conn
*conn
;
176 struct smbXcli_session
*session
;
177 struct smbXcli_tcon
*tcon
;
179 unsigned int timeout
;
183 uint64_t fid_persistent
;
184 uint64_t fid_volatile
;
188 static void tstream_smbXcli_np_open_done(struct tevent_req
*subreq
);
190 struct tevent_req
*tstream_smbXcli_np_open_send(TALLOC_CTX
*mem_ctx
,
191 struct tevent_context
*ev
,
192 struct smbXcli_conn
*conn
,
193 struct smbXcli_session
*session
,
194 struct smbXcli_tcon
*tcon
,
196 unsigned int timeout
,
199 struct tevent_req
*req
;
200 struct tstream_smbXcli_np_open_state
*state
;
201 struct tevent_req
*subreq
;
203 req
= tevent_req_create(mem_ctx
, &state
,
204 struct tstream_smbXcli_np_open_state
);
210 state
->session
= session
;
212 state
->timeout
= timeout
;
214 state
->npipe
= talloc_strdup(state
, npipe
);
215 if (tevent_req_nomem(state
->npipe
, req
)) {
216 return tevent_req_post(req
, ev
);
219 if (smbXcli_conn_protocol(conn
) < PROTOCOL_SMB2_02
) {
220 state
->is_smb1
= true;
223 if (state
->is_smb1
) {
224 const char *smb1_npipe
;
227 * Windows and newer Samba versions allow
228 * the pipe name without leading backslash,
229 * but we should better behave like windows clients
231 smb1_npipe
= talloc_asprintf(state
, "\\%s", state
->npipe
);
232 if (tevent_req_nomem(smb1_npipe
, req
)) {
233 return tevent_req_post(req
, ev
);
235 subreq
= smb1cli_ntcreatex_send(state
, ev
, state
->conn
,
242 0, /* RootDirectoryFid */
243 TSTREAM_SMBXCLI_NP_DESIRED_ACCESS
,
244 0, /* AllocationSize */
245 0, /* FileAttributes */
246 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
247 FILE_OPEN
, /* CreateDisposition */
248 0, /* CreateOptions */
249 2, /* NTCREATEX_IMPERSONATION_IMPERSONATION */
250 0); /* SecurityFlags */
252 subreq
= smb2cli_create_send(state
, ev
, state
->conn
,
253 state
->timeout
, state
->session
,
256 SMB2_OPLOCK_LEVEL_NONE
,
257 SMB2_IMPERSONATION_IMPERSONATION
,
258 TSTREAM_SMBXCLI_NP_DESIRED_ACCESS
,
259 0, /* file_attributes */
260 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
262 0, /* create_options */
265 if (tevent_req_nomem(subreq
, req
)) {
266 return tevent_req_post(req
, ev
);
268 tevent_req_set_callback(subreq
, tstream_smbXcli_np_open_done
, req
);
273 static void tstream_smbXcli_np_open_done(struct tevent_req
*subreq
)
275 struct tevent_req
*req
=
276 tevent_req_callback_data(subreq
, struct tevent_req
);
277 struct tstream_smbXcli_np_open_state
*state
=
278 tevent_req_data(req
, struct tstream_smbXcli_np_open_state
);
281 if (state
->is_smb1
) {
282 status
= smb1cli_ntcreatex_recv(subreq
, &state
->fnum
);
284 status
= smb2cli_create_recv(
286 &state
->fid_persistent
,
287 &state
->fid_volatile
,
294 if (!NT_STATUS_IS_OK(status
)) {
295 tevent_req_nterror(req
, status
);
299 tevent_req_done(req
);
302 NTSTATUS
_tstream_smbXcli_np_open_recv(struct tevent_req
*req
,
304 struct tstream_context
**_stream
,
305 const char *location
)
307 struct tstream_smbXcli_np_open_state
*state
=
308 tevent_req_data(req
, struct tstream_smbXcli_np_open_state
);
309 struct tstream_context
*stream
;
310 struct tstream_smbXcli_np
*cli_nps
;
313 if (tevent_req_is_nterror(req
, &status
)) {
314 tevent_req_received(req
);
318 stream
= tstream_context_create(mem_ctx
,
319 &tstream_smbXcli_np_ops
,
321 struct tstream_smbXcli_np
,
324 tevent_req_received(req
);
325 return NT_STATUS_NO_MEMORY
;
327 ZERO_STRUCTP(cli_nps
);
329 cli_nps
->conn_ref
= talloc_zero(state
->conn
,
330 struct tstream_smbXcli_np_ref
);
331 if (cli_nps
->conn_ref
== NULL
) {
332 TALLOC_FREE(cli_nps
);
333 tevent_req_received(req
);
334 return NT_STATUS_NO_MEMORY
;
336 cli_nps
->conn_ref
->cli_nps
= cli_nps
;
338 cli_nps
->session_ref
= talloc_zero(state
->session
,
339 struct tstream_smbXcli_np_ref
);
340 if (cli_nps
->session_ref
== NULL
) {
341 TALLOC_FREE(cli_nps
);
342 tevent_req_received(req
);
343 return NT_STATUS_NO_MEMORY
;
345 cli_nps
->session_ref
->cli_nps
= cli_nps
;
347 cli_nps
->tcon_ref
= talloc_zero(state
->tcon
,
348 struct tstream_smbXcli_np_ref
);
349 if (cli_nps
->tcon_ref
== NULL
) {
350 TALLOC_FREE(cli_nps
);
351 tevent_req_received(req
);
352 return NT_STATUS_NO_MEMORY
;
354 cli_nps
->tcon_ref
->cli_nps
= cli_nps
;
356 cli_nps
->conn
= state
->conn
;
357 cli_nps
->session
= state
->session
;
358 cli_nps
->tcon
= state
->tcon
;
359 cli_nps
->pid
= state
->pid
;
360 cli_nps
->timeout
= state
->timeout
;
361 cli_nps
->npipe
= talloc_move(cli_nps
, &state
->npipe
);
362 cli_nps
->is_smb1
= state
->is_smb1
;
363 cli_nps
->fnum
= state
->fnum
;
364 cli_nps
->fid_persistent
= state
->fid_persistent
;
365 cli_nps
->fid_volatile
= state
->fid_volatile
;
366 cli_nps
->max_data
= TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE
;
368 talloc_set_destructor(cli_nps
, tstream_smbXcli_np_destructor
);
369 talloc_set_destructor(cli_nps
->conn_ref
,
370 tstream_smbXcli_np_ref_destructor
);
371 talloc_set_destructor(cli_nps
->session_ref
,
372 tstream_smbXcli_np_ref_destructor
);
373 talloc_set_destructor(cli_nps
->tcon_ref
,
374 tstream_smbXcli_np_ref_destructor
);
376 cli_nps
->trans
.active
= false;
377 cli_nps
->trans
.read_req
= NULL
;
378 cli_nps
->trans
.write_req
= NULL
;
379 SSVAL(cli_nps
->trans
.setup
+0, 0, TRANSACT_DCERPCCMD
);
380 SSVAL(cli_nps
->trans
.setup
+1, 0, cli_nps
->fnum
);
383 tevent_req_received(req
);
387 static ssize_t
tstream_smbXcli_np_pending_bytes(struct tstream_context
*stream
)
389 struct tstream_smbXcli_np
*cli_nps
= tstream_context_data(stream
,
390 struct tstream_smbXcli_np
);
392 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
397 return cli_nps
->read
.left
;
400 bool tstream_is_smbXcli_np(struct tstream_context
*stream
)
402 struct tstream_smbXcli_np
*cli_nps
=
403 talloc_get_type(_tstream_context_data(stream
),
404 struct tstream_smbXcli_np
);
413 NTSTATUS
tstream_smbXcli_np_use_trans(struct tstream_context
*stream
)
415 struct tstream_smbXcli_np
*cli_nps
= tstream_context_data(stream
,
416 struct tstream_smbXcli_np
);
418 if (cli_nps
->trans
.read_req
) {
419 return NT_STATUS_PIPE_BUSY
;
422 if (cli_nps
->trans
.write_req
) {
423 return NT_STATUS_PIPE_BUSY
;
426 if (cli_nps
->trans
.active
) {
427 return NT_STATUS_PIPE_BUSY
;
430 cli_nps
->trans
.active
= true;
435 void tstream_smbXcli_np_set_max_data(struct tstream_context
*stream
,
438 struct tstream_smbXcli_np
*cli_nps
= tstream_context_data(
439 stream
, struct tstream_smbXcli_np
);
441 cli_nps
->max_data
= max_data
;
444 unsigned int tstream_smbXcli_np_set_timeout(struct tstream_context
*stream
,
445 unsigned int timeout
)
447 struct tstream_smbXcli_np
*cli_nps
= tstream_context_data(stream
,
448 struct tstream_smbXcli_np
);
449 unsigned int old_timeout
= cli_nps
->timeout
;
451 cli_nps
->timeout
= timeout
;
455 struct tstream_smbXcli_np_writev_state
{
456 struct tstream_context
*stream
;
457 struct tevent_context
*ev
;
459 struct iovec
*vector
;
466 const char *location
;
470 static int tstream_smbXcli_np_writev_state_destructor(struct tstream_smbXcli_np_writev_state
*state
)
472 struct tstream_smbXcli_np
*cli_nps
=
473 tstream_context_data(state
->stream
,
474 struct tstream_smbXcli_np
);
476 cli_nps
->trans
.write_req
= NULL
;
481 static void tstream_smbXcli_np_writev_write_next(struct tevent_req
*req
);
483 static struct tevent_req
*tstream_smbXcli_np_writev_send(TALLOC_CTX
*mem_ctx
,
484 struct tevent_context
*ev
,
485 struct tstream_context
*stream
,
486 const struct iovec
*vector
,
489 struct tevent_req
*req
;
490 struct tstream_smbXcli_np_writev_state
*state
;
491 struct tstream_smbXcli_np
*cli_nps
= tstream_context_data(stream
,
492 struct tstream_smbXcli_np
);
494 req
= tevent_req_create(mem_ctx
, &state
,
495 struct tstream_smbXcli_np_writev_state
);
499 state
->stream
= stream
;
503 talloc_set_destructor(state
, tstream_smbXcli_np_writev_state_destructor
);
505 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
506 tevent_req_error(req
, ENOTCONN
);
507 return tevent_req_post(req
, ev
);
511 * we make a copy of the vector so we can change the structure
513 state
->vector
= talloc_array(state
, struct iovec
, count
);
514 if (tevent_req_nomem(state
->vector
, req
)) {
515 return tevent_req_post(req
, ev
);
517 memcpy(state
->vector
, vector
, sizeof(struct iovec
) * count
);
518 state
->count
= count
;
520 tstream_smbXcli_np_writev_write_next(req
);
521 if (!tevent_req_is_in_progress(req
)) {
522 return tevent_req_post(req
, ev
);
528 static void tstream_smbXcli_np_readv_trans_start(struct tevent_req
*req
);
529 static void tstream_smbXcli_np_writev_write_done(struct tevent_req
*subreq
);
531 static void tstream_smbXcli_np_writev_write_next(struct tevent_req
*req
)
533 struct tstream_smbXcli_np_writev_state
*state
=
535 struct tstream_smbXcli_np_writev_state
);
536 struct tstream_smbXcli_np
*cli_nps
=
537 tstream_context_data(state
->stream
,
538 struct tstream_smbXcli_np
);
539 struct tevent_req
*subreq
;
543 for (i
=0; i
< state
->count
; i
++) {
544 left
+= state
->vector
[i
].iov_len
;
548 TALLOC_FREE(cli_nps
->write
.buf
);
549 tevent_req_done(req
);
553 cli_nps
->write
.ofs
= 0;
554 cli_nps
->write
.left
= MIN(left
, cli_nps
->max_data
);
555 cli_nps
->write
.buf
= talloc_realloc(cli_nps
, cli_nps
->write
.buf
,
556 uint8_t, cli_nps
->write
.left
);
557 if (tevent_req_nomem(cli_nps
->write
.buf
, req
)) {
562 * copy the pending buffer first
564 while (cli_nps
->write
.left
> 0 && state
->count
> 0) {
565 uint8_t *base
= (uint8_t *)state
->vector
[0].iov_base
;
566 size_t len
= MIN(cli_nps
->write
.left
, state
->vector
[0].iov_len
);
568 memcpy(cli_nps
->write
.buf
+ cli_nps
->write
.ofs
, base
, len
);
571 state
->vector
[0].iov_base
= base
;
572 state
->vector
[0].iov_len
-= len
;
574 cli_nps
->write
.ofs
+= len
;
575 cli_nps
->write
.left
-= len
;
577 if (state
->vector
[0].iov_len
== 0) {
585 if (cli_nps
->trans
.active
&& state
->count
== 0) {
586 cli_nps
->trans
.active
= false;
587 cli_nps
->trans
.write_req
= req
;
591 if (cli_nps
->trans
.read_req
&& state
->count
== 0) {
592 cli_nps
->trans
.write_req
= req
;
593 tstream_smbXcli_np_readv_trans_start(cli_nps
->trans
.read_req
);
597 if (cli_nps
->is_smb1
) {
598 subreq
= smb1cli_writex_send(state
, state
->ev
,
605 8, /* 8 means message mode. */
608 cli_nps
->write
.ofs
); /* size */
610 subreq
= smb2cli_write_send(state
, state
->ev
,
615 cli_nps
->write
.ofs
, /* length */
617 cli_nps
->fid_persistent
,
618 cli_nps
->fid_volatile
,
619 0, /* remaining_bytes */
623 if (tevent_req_nomem(subreq
, req
)) {
626 tevent_req_set_callback(subreq
,
627 tstream_smbXcli_np_writev_write_done
,
631 static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req
*req
,
633 const char *location
);
635 static void tstream_smbXcli_np_writev_write_done(struct tevent_req
*subreq
)
637 struct tevent_req
*req
=
638 tevent_req_callback_data(subreq
, struct tevent_req
);
639 struct tstream_smbXcli_np_writev_state
*state
=
640 tevent_req_data(req
, struct tstream_smbXcli_np_writev_state
);
641 struct tstream_smbXcli_np
*cli_nps
=
642 tstream_context_data(state
->stream
,
643 struct tstream_smbXcli_np
);
647 if (cli_nps
->is_smb1
) {
648 status
= smb1cli_writex_recv(subreq
, &written
, NULL
);
650 status
= smb2cli_write_recv(subreq
, &written
);
653 if (!NT_STATUS_IS_OK(status
)) {
654 tstream_smbXcli_np_writev_disconnect_now(req
, EPIPE
, __location__
);
658 if (written
!= cli_nps
->write
.ofs
) {
659 tstream_smbXcli_np_writev_disconnect_now(req
, EIO
, __location__
);
663 tstream_smbXcli_np_writev_write_next(req
);
666 static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req
*subreq
);
668 static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req
*req
,
670 const char *location
)
672 struct tstream_smbXcli_np_writev_state
*state
=
674 struct tstream_smbXcli_np_writev_state
);
675 struct tstream_smbXcli_np
*cli_nps
=
676 tstream_context_data(state
->stream
,
677 struct tstream_smbXcli_np
);
678 struct tevent_req
*subreq
;
680 state
->error
.val
= error
;
681 state
->error
.location
= location
;
683 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
684 /* return the original error */
685 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
689 subreq
= tstream_smbXcli_np_disconnect_send(state
, state
->ev
,
691 if (subreq
== NULL
) {
692 /* return the original error */
693 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
696 tevent_req_set_callback(subreq
,
697 tstream_smbXcli_np_writev_disconnect_done
,
701 static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req
*subreq
)
703 struct tevent_req
*req
=
704 tevent_req_callback_data(subreq
, struct tevent_req
);
705 struct tstream_smbXcli_np_writev_state
*state
=
706 tevent_req_data(req
, struct tstream_smbXcli_np_writev_state
);
709 tstream_smbXcli_np_disconnect_recv(subreq
, &error
);
712 /* return the original error */
713 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
716 static int tstream_smbXcli_np_writev_recv(struct tevent_req
*req
,
719 struct tstream_smbXcli_np_writev_state
*state
=
721 struct tstream_smbXcli_np_writev_state
);
724 ret
= tsocket_simple_int_recv(req
, perrno
);
729 tevent_req_received(req
);
733 struct tstream_smbXcli_np_readv_state
{
734 struct tstream_context
*stream
;
735 struct tevent_context
*ev
;
737 struct iovec
*vector
;
743 struct tevent_immediate
*im
;
748 const char *location
;
752 static int tstream_smbXcli_np_readv_state_destructor(struct tstream_smbXcli_np_readv_state
*state
)
754 struct tstream_smbXcli_np
*cli_nps
=
755 tstream_context_data(state
->stream
,
756 struct tstream_smbXcli_np
);
758 cli_nps
->trans
.read_req
= NULL
;
763 static void tstream_smbXcli_np_readv_read_next(struct tevent_req
*req
);
765 static struct tevent_req
*tstream_smbXcli_np_readv_send(TALLOC_CTX
*mem_ctx
,
766 struct tevent_context
*ev
,
767 struct tstream_context
*stream
,
768 struct iovec
*vector
,
771 struct tevent_req
*req
;
772 struct tstream_smbXcli_np_readv_state
*state
;
773 struct tstream_smbXcli_np
*cli_nps
=
774 tstream_context_data(stream
, struct tstream_smbXcli_np
);
776 req
= tevent_req_create(mem_ctx
, &state
,
777 struct tstream_smbXcli_np_readv_state
);
781 state
->stream
= stream
;
785 talloc_set_destructor(state
, tstream_smbXcli_np_readv_state_destructor
);
787 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
788 tevent_req_error(req
, ENOTCONN
);
789 return tevent_req_post(req
, ev
);
793 * we make a copy of the vector so we can change the structure
795 state
->vector
= talloc_array(state
, struct iovec
, count
);
796 if (tevent_req_nomem(state
->vector
, req
)) {
797 return tevent_req_post(req
, ev
);
799 memcpy(state
->vector
, vector
, sizeof(struct iovec
) * count
);
800 state
->count
= count
;
802 tstream_smbXcli_np_readv_read_next(req
);
803 if (!tevent_req_is_in_progress(req
)) {
804 return tevent_req_post(req
, ev
);
810 static void tstream_smbXcli_np_readv_read_done(struct tevent_req
*subreq
);
812 static void tstream_smbXcli_np_readv_read_next(struct tevent_req
*req
)
814 struct tstream_smbXcli_np_readv_state
*state
=
816 struct tstream_smbXcli_np_readv_state
);
817 struct tstream_smbXcli_np
*cli_nps
=
818 tstream_context_data(state
->stream
,
819 struct tstream_smbXcli_np
);
820 struct tevent_req
*subreq
;
823 * copy the pending buffer first
825 while (cli_nps
->read
.left
> 0 && state
->count
> 0) {
826 uint8_t *base
= (uint8_t *)state
->vector
[0].iov_base
;
827 size_t len
= MIN(cli_nps
->read
.left
, state
->vector
[0].iov_len
);
829 memcpy(base
, cli_nps
->read
.buf
+ cli_nps
->read
.ofs
, len
);
832 state
->vector
[0].iov_base
= base
;
833 state
->vector
[0].iov_len
-= len
;
835 cli_nps
->read
.ofs
+= len
;
836 cli_nps
->read
.left
-= len
;
838 if (state
->vector
[0].iov_len
== 0) {
846 if (cli_nps
->read
.left
== 0) {
847 TALLOC_FREE(cli_nps
->read
.buf
);
850 if (state
->count
== 0) {
851 tevent_req_done(req
);
855 if (cli_nps
->trans
.active
) {
856 cli_nps
->trans
.active
= false;
857 cli_nps
->trans
.read_req
= req
;
861 if (cli_nps
->trans
.write_req
) {
862 cli_nps
->trans
.read_req
= req
;
863 tstream_smbXcli_np_readv_trans_start(req
);
867 if (cli_nps
->is_smb1
) {
868 subreq
= smb1cli_readx_send(state
, state
->ev
,
878 subreq
= smb2cli_read_send(state
, state
->ev
,
883 cli_nps
->max_data
, /* length */
885 cli_nps
->fid_persistent
,
886 cli_nps
->fid_volatile
,
887 0, /* minimum_count */
888 0); /* remaining_bytes */
890 if (tevent_req_nomem(subreq
, req
)) {
893 tevent_req_set_callback(subreq
,
894 tstream_smbXcli_np_readv_read_done
,
898 static void tstream_smbXcli_np_readv_trans_done(struct tevent_req
*subreq
);
900 static void tstream_smbXcli_np_readv_trans_start(struct tevent_req
*req
)
902 struct tstream_smbXcli_np_readv_state
*state
=
904 struct tstream_smbXcli_np_readv_state
);
905 struct tstream_smbXcli_np
*cli_nps
=
906 tstream_context_data(state
->stream
,
907 struct tstream_smbXcli_np
);
908 struct tevent_req
*subreq
;
910 state
->trans
.im
= tevent_create_immediate(state
);
911 if (tevent_req_nomem(state
->trans
.im
, req
)) {
915 if (cli_nps
->is_smb1
) {
916 subreq
= smb1cli_trans_send(state
, state
->ev
,
917 cli_nps
->conn
, SMBtrans
,
926 cli_nps
->trans
.setup
, 2,
933 DATA_BLOB in_input_buffer
= data_blob_null
;
934 DATA_BLOB in_output_buffer
= data_blob_null
;
936 in_input_buffer
= data_blob_const(cli_nps
->write
.buf
,
939 subreq
= smb2cli_ioctl_send(state
, state
->ev
,
944 cli_nps
->fid_persistent
,
945 cli_nps
->fid_volatile
,
946 FSCTL_NAMED_PIPE_READ_WRITE
,
947 0, /* in_max_input_length */
949 /* in_max_output_length */
952 SMB2_IOCTL_FLAG_IS_FSCTL
);
954 if (tevent_req_nomem(subreq
, req
)) {
957 tevent_req_set_callback(subreq
,
958 tstream_smbXcli_np_readv_trans_done
,
962 static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req
*req
,
964 const char *location
);
965 static void tstream_smbXcli_np_readv_trans_next(struct tevent_context
*ctx
,
966 struct tevent_immediate
*im
,
969 static void tstream_smbXcli_np_readv_trans_done(struct tevent_req
*subreq
)
971 struct tevent_req
*req
=
972 tevent_req_callback_data(subreq
, struct tevent_req
);
973 struct tstream_smbXcli_np_readv_state
*state
=
974 tevent_req_data(req
, struct tstream_smbXcli_np_readv_state
);
975 struct tstream_smbXcli_np
*cli_nps
=
976 tstream_context_data(state
->stream
, struct tstream_smbXcli_np
);
981 if (cli_nps
->is_smb1
) {
982 status
= smb1cli_trans_recv(subreq
, state
, NULL
, NULL
, 0, NULL
,
984 &rcvbuf
, 0, &received
);
986 DATA_BLOB out_input_buffer
= data_blob_null
;
987 DATA_BLOB out_output_buffer
= data_blob_null
;
989 status
= smb2cli_ioctl_recv(subreq
, state
,
993 /* Note that rcvbuf is not a talloc pointer here */
994 rcvbuf
= out_output_buffer
.data
;
995 received
= out_output_buffer
.length
;
998 if (NT_STATUS_EQUAL(status
, STATUS_BUFFER_OVERFLOW
)) {
1000 * STATUS_BUFFER_OVERFLOW means that there's
1001 * more data to read when the named pipe is used
1002 * in message mode (which is the case here).
1004 * But we hide this from the caller.
1006 status
= NT_STATUS_OK
;
1008 if (!NT_STATUS_IS_OK(status
)) {
1009 tstream_smbXcli_np_readv_disconnect_now(req
, EPIPE
, __location__
);
1013 if (received
> cli_nps
->max_data
) {
1014 tstream_smbXcli_np_readv_disconnect_now(req
, EIO
, __location__
);
1018 if (received
== 0) {
1019 tstream_smbXcli_np_readv_disconnect_now(req
, EPIPE
, __location__
);
1023 cli_nps
->read
.ofs
= 0;
1024 cli_nps
->read
.left
= received
;
1025 cli_nps
->read
.buf
= talloc_array(cli_nps
, uint8_t, received
);
1026 if (cli_nps
->read
.buf
== NULL
) {
1027 TALLOC_FREE(subreq
);
1028 tevent_req_oom(req
);
1031 memcpy(cli_nps
->read
.buf
, rcvbuf
, received
);
1033 if (cli_nps
->trans
.write_req
== NULL
) {
1034 tstream_smbXcli_np_readv_read_next(req
);
1038 tevent_schedule_immediate(state
->trans
.im
, state
->ev
,
1039 tstream_smbXcli_np_readv_trans_next
, req
);
1041 tevent_req_done(cli_nps
->trans
.write_req
);
1044 static void tstream_smbXcli_np_readv_trans_next(struct tevent_context
*ctx
,
1045 struct tevent_immediate
*im
,
1048 struct tevent_req
*req
=
1049 talloc_get_type_abort(private_data
,
1052 tstream_smbXcli_np_readv_read_next(req
);
1055 static void tstream_smbXcli_np_readv_read_done(struct tevent_req
*subreq
)
1057 struct tevent_req
*req
=
1058 tevent_req_callback_data(subreq
, struct tevent_req
);
1059 struct tstream_smbXcli_np_readv_state
*state
=
1060 tevent_req_data(req
, struct tstream_smbXcli_np_readv_state
);
1061 struct tstream_smbXcli_np
*cli_nps
=
1062 tstream_context_data(state
->stream
, struct tstream_smbXcli_np
);
1068 * We must free subreq in this function as there is
1069 * a timer event attached to it.
1072 if (cli_nps
->is_smb1
) {
1073 status
= smb1cli_readx_recv(subreq
, &received
, &rcvbuf
);
1075 status
= smb2cli_read_recv(subreq
, state
, &rcvbuf
, &received
);
1078 * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
1081 if (NT_STATUS_EQUAL(status
, STATUS_BUFFER_OVERFLOW
)) {
1083 * STATUS_BUFFER_OVERFLOW means that there's
1084 * more data to read when the named pipe is used
1085 * in message mode (which is the case here).
1087 * But we hide this from the caller.
1089 status
= NT_STATUS_OK
;
1091 if (!NT_STATUS_IS_OK(status
)) {
1092 TALLOC_FREE(subreq
);
1093 tstream_smbXcli_np_readv_disconnect_now(req
, EPIPE
, __location__
);
1097 if (received
> cli_nps
->max_data
) {
1098 TALLOC_FREE(subreq
);
1099 tstream_smbXcli_np_readv_disconnect_now(req
, EIO
, __location__
);
1103 if (received
== 0) {
1104 TALLOC_FREE(subreq
);
1105 tstream_smbXcli_np_readv_disconnect_now(req
, EPIPE
, __location__
);
1109 cli_nps
->read
.ofs
= 0;
1110 cli_nps
->read
.left
= received
;
1111 cli_nps
->read
.buf
= talloc_array(cli_nps
, uint8_t, received
);
1112 if (cli_nps
->read
.buf
== NULL
) {
1113 TALLOC_FREE(subreq
);
1114 tevent_req_oom(req
);
1117 memcpy(cli_nps
->read
.buf
, rcvbuf
, received
);
1118 TALLOC_FREE(subreq
);
1120 tstream_smbXcli_np_readv_read_next(req
);
1123 static void tstream_smbXcli_np_readv_disconnect_done(struct tevent_req
*subreq
);
1125 static void tstream_smbXcli_np_readv_error(struct tevent_req
*req
);
1127 static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req
*req
,
1129 const char *location
)
1131 struct tstream_smbXcli_np_readv_state
*state
=
1132 tevent_req_data(req
,
1133 struct tstream_smbXcli_np_readv_state
);
1134 struct tstream_smbXcli_np
*cli_nps
=
1135 tstream_context_data(state
->stream
,
1136 struct tstream_smbXcli_np
);
1137 struct tevent_req
*subreq
;
1139 state
->error
.val
= error
;
1140 state
->error
.location
= location
;
1142 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
1143 /* return the original error */
1144 tstream_smbXcli_np_readv_error(req
);
1148 subreq
= tstream_smbXcli_np_disconnect_send(state
, state
->ev
,
1150 if (subreq
== NULL
) {
1151 /* return the original error */
1152 tstream_smbXcli_np_readv_error(req
);
1155 tevent_req_set_callback(subreq
,
1156 tstream_smbXcli_np_readv_disconnect_done
,
1160 static void tstream_smbXcli_np_readv_disconnect_done(struct tevent_req
*subreq
)
1162 struct tevent_req
*req
=
1163 tevent_req_callback_data(subreq
, struct tevent_req
);
1166 tstream_smbXcli_np_disconnect_recv(subreq
, &error
);
1167 TALLOC_FREE(subreq
);
1169 tstream_smbXcli_np_readv_error(req
);
1172 static void tstream_smbXcli_np_readv_error_trigger(struct tevent_context
*ctx
,
1173 struct tevent_immediate
*im
,
1174 void *private_data
);
1176 static void tstream_smbXcli_np_readv_error(struct tevent_req
*req
)
1178 struct tstream_smbXcli_np_readv_state
*state
=
1179 tevent_req_data(req
,
1180 struct tstream_smbXcli_np_readv_state
);
1181 struct tstream_smbXcli_np
*cli_nps
=
1182 tstream_context_data(state
->stream
,
1183 struct tstream_smbXcli_np
);
1185 if (cli_nps
->trans
.write_req
== NULL
) {
1186 /* return the original error */
1187 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
1191 if (state
->trans
.im
== NULL
) {
1192 /* return the original error */
1193 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
1197 tevent_schedule_immediate(state
->trans
.im
, state
->ev
,
1198 tstream_smbXcli_np_readv_error_trigger
, req
);
1200 /* return the original error for writev */
1201 _tevent_req_error(cli_nps
->trans
.write_req
,
1202 state
->error
.val
, state
->error
.location
);
1205 static void tstream_smbXcli_np_readv_error_trigger(struct tevent_context
*ctx
,
1206 struct tevent_immediate
*im
,
1209 struct tevent_req
*req
=
1210 talloc_get_type_abort(private_data
,
1212 struct tstream_smbXcli_np_readv_state
*state
=
1213 tevent_req_data(req
,
1214 struct tstream_smbXcli_np_readv_state
);
1216 /* return the original error */
1217 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
1220 static int tstream_smbXcli_np_readv_recv(struct tevent_req
*req
,
1223 struct tstream_smbXcli_np_readv_state
*state
=
1224 tevent_req_data(req
, struct tstream_smbXcli_np_readv_state
);
1227 ret
= tsocket_simple_int_recv(req
, perrno
);
1232 tevent_req_received(req
);
1236 struct tstream_smbXcli_np_disconnect_state
{
1237 struct tstream_context
*stream
;
1238 struct tevent_req
*subreq
;
1241 static void tstream_smbXcli_np_disconnect_done(struct tevent_req
*subreq
);
1242 static void tstream_smbXcli_np_disconnect_cleanup(struct tevent_req
*req
,
1243 enum tevent_req_state req_state
);
1245 static struct tevent_req
*tstream_smbXcli_np_disconnect_send(TALLOC_CTX
*mem_ctx
,
1246 struct tevent_context
*ev
,
1247 struct tstream_context
*stream
)
1249 struct tstream_smbXcli_np
*cli_nps
= tstream_context_data(stream
,
1250 struct tstream_smbXcli_np
);
1251 struct tevent_req
*req
;
1252 struct tstream_smbXcli_np_disconnect_state
*state
;
1253 struct tevent_req
*subreq
;
1255 req
= tevent_req_create(mem_ctx
, &state
,
1256 struct tstream_smbXcli_np_disconnect_state
);
1261 state
->stream
= stream
;
1263 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
1264 tevent_req_error(req
, ENOTCONN
);
1265 return tevent_req_post(req
, ev
);
1268 if (cli_nps
->is_smb1
) {
1269 subreq
= smb1cli_close_send(state
, ev
, cli_nps
->conn
,
1274 cli_nps
->fnum
, UINT32_MAX
);
1276 subreq
= smb2cli_close_send(state
, ev
, cli_nps
->conn
,
1281 cli_nps
->fid_persistent
,
1282 cli_nps
->fid_volatile
);
1284 if (tevent_req_nomem(subreq
, req
)) {
1285 return tevent_req_post(req
, ev
);
1287 tevent_req_set_callback(subreq
, tstream_smbXcli_np_disconnect_done
, req
);
1288 state
->subreq
= subreq
;
1290 tevent_req_set_cleanup_fn(req
, tstream_smbXcli_np_disconnect_cleanup
);
1293 * Make sure we don't send any requests anymore.
1295 cli_nps
->conn
= NULL
;
1300 static void tstream_smbXcli_np_disconnect_done(struct tevent_req
*subreq
)
1302 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
1304 struct tstream_smbXcli_np_disconnect_state
*state
=
1305 tevent_req_data(req
, struct tstream_smbXcli_np_disconnect_state
);
1306 struct tstream_smbXcli_np
*cli_nps
=
1307 tstream_context_data(state
->stream
, struct tstream_smbXcli_np
);
1310 state
->subreq
= NULL
;
1312 if (cli_nps
->is_smb1
) {
1313 status
= smb1cli_close_recv(subreq
);
1315 status
= smb2cli_close_recv(subreq
);
1317 TALLOC_FREE(subreq
);
1318 if (!NT_STATUS_IS_OK(status
)) {
1319 tevent_req_error(req
, EPIPE
);
1323 cli_nps
->conn
= NULL
;
1324 cli_nps
->session
= NULL
;
1325 cli_nps
->tcon
= NULL
;
1327 tevent_req_done(req
);
1330 static void tstream_smbXcli_np_disconnect_free(struct tevent_req
*subreq
);
1332 static void tstream_smbXcli_np_disconnect_cleanup(struct tevent_req
*req
,
1333 enum tevent_req_state req_state
)
1335 struct tstream_smbXcli_np_disconnect_state
*state
=
1336 tevent_req_data(req
, struct tstream_smbXcli_np_disconnect_state
);
1337 struct tstream_smbXcli_np
*cli_nps
= NULL
;
1339 if (state
->subreq
== NULL
) {
1343 cli_nps
= tstream_context_data(state
->stream
, struct tstream_smbXcli_np
);
1345 if (cli_nps
->tcon
== NULL
) {
1350 * We're no longer interested in the result
1351 * any more, but need to make sure that the close
1352 * request arrives at the server if the smb connection,
1353 * session and tcon are still alive.
1355 * We move the low level request to the tcon,
1356 * which means that it stays as long as the tcon
1359 talloc_steal(cli_nps
->tcon
, state
->subreq
);
1360 tevent_req_set_callback(state
->subreq
,
1361 tstream_smbXcli_np_disconnect_free
,
1363 state
->subreq
= NULL
;
1365 cli_nps
->conn
= NULL
;
1366 cli_nps
->session
= NULL
;
1367 cli_nps
->tcon
= NULL
;
1370 static void tstream_smbXcli_np_disconnect_free(struct tevent_req
*subreq
)
1372 TALLOC_FREE(subreq
);
1375 static int tstream_smbXcli_np_disconnect_recv(struct tevent_req
*req
,
1380 ret
= tsocket_simple_int_recv(req
, perrno
);
1382 tevent_req_received(req
);
1386 static const struct tstream_context_ops tstream_smbXcli_np_ops
= {
1387 .name
= "smbXcli_np",
1389 .pending_bytes
= tstream_smbXcli_np_pending_bytes
,
1391 .readv_send
= tstream_smbXcli_np_readv_send
,
1392 .readv_recv
= tstream_smbXcli_np_readv_recv
,
1394 .writev_send
= tstream_smbXcli_np_writev_send
,
1395 .writev_recv
= tstream_smbXcli_np_writev_recv
,
1397 .disconnect_send
= tstream_smbXcli_np_disconnect_send
,
1398 .disconnect_recv
= tstream_smbXcli_np_disconnect_recv
,