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 * We use a maximun timeout of 1 second == 1000 msec.
117 cli_nps
->timeout
= MIN(cli_nps
->timeout
, 1000);
119 if (cli_nps
->is_smb1
) {
120 status
= smb1cli_close(cli_nps
->conn
,
125 cli_nps
->fnum
, UINT32_MAX
);
127 status
= smb2cli_close(cli_nps
->conn
,
132 cli_nps
->fid_persistent
,
133 cli_nps
->fid_volatile
);
135 if (!NT_STATUS_IS_OK(status
)) {
136 DEBUG(1, ("tstream_smbXcli_np_destructor: cli_close "
137 "failed on pipe %s. Error was %s\n",
138 cli_nps
->npipe
, nt_errstr(status
)));
141 * We can't do much on failure
146 static int tstream_smbXcli_np_ref_destructor(struct tstream_smbXcli_np_ref
*ref
)
148 if (ref
->cli_nps
== NULL
) {
152 if (ref
->cli_nps
->conn
== NULL
) {
156 ref
->cli_nps
->conn
= NULL
;
157 ref
->cli_nps
->session
= NULL
;
158 ref
->cli_nps
->tcon
= NULL
;
160 TALLOC_FREE(ref
->cli_nps
->conn_ref
);
161 TALLOC_FREE(ref
->cli_nps
->session_ref
);
162 TALLOC_FREE(ref
->cli_nps
->tcon_ref
);
167 static struct tevent_req
*tstream_smbXcli_np_disconnect_send(TALLOC_CTX
*mem_ctx
,
168 struct tevent_context
*ev
,
169 struct tstream_context
*stream
);
170 static int tstream_smbXcli_np_disconnect_recv(struct tevent_req
*req
,
173 struct tstream_smbXcli_np_open_state
{
174 struct smbXcli_conn
*conn
;
175 struct smbXcli_session
*session
;
176 struct smbXcli_tcon
*tcon
;
178 unsigned int timeout
;
182 uint64_t fid_persistent
;
183 uint64_t fid_volatile
;
187 static void tstream_smbXcli_np_open_done(struct tevent_req
*subreq
);
189 struct tevent_req
*tstream_smbXcli_np_open_send(TALLOC_CTX
*mem_ctx
,
190 struct tevent_context
*ev
,
191 struct smbXcli_conn
*conn
,
192 struct smbXcli_session
*session
,
193 struct smbXcli_tcon
*tcon
,
195 unsigned int timeout
,
198 struct tevent_req
*req
;
199 struct tstream_smbXcli_np_open_state
*state
;
200 struct tevent_req
*subreq
;
202 req
= tevent_req_create(mem_ctx
, &state
,
203 struct tstream_smbXcli_np_open_state
);
209 state
->session
= session
;
211 state
->timeout
= timeout
;
213 state
->npipe
= talloc_strdup(state
, npipe
);
214 if (tevent_req_nomem(state
->npipe
, req
)) {
215 return tevent_req_post(req
, ev
);
218 if (smbXcli_conn_protocol(conn
) < PROTOCOL_SMB2_02
) {
219 state
->is_smb1
= true;
222 if (state
->is_smb1
) {
223 const char *smb1_npipe
;
226 * Windows and newer Samba versions allow
227 * the pipe name without leading backslash,
228 * but we should better behave like windows clients
230 smb1_npipe
= talloc_asprintf(state
, "\\%s", state
->npipe
);
231 if (tevent_req_nomem(smb1_npipe
, req
)) {
232 return tevent_req_post(req
, ev
);
234 subreq
= smb1cli_ntcreatex_send(state
, ev
, state
->conn
,
241 0, /* RootDirectoryFid */
242 TSTREAM_SMBXCLI_NP_DESIRED_ACCESS
,
243 0, /* AllocationSize */
244 0, /* FileAttributes */
245 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
246 FILE_OPEN
, /* CreateDisposition */
247 0, /* CreateOptions */
248 2, /* NTCREATEX_IMPERSONATION_IMPERSONATION */
249 0); /* SecurityFlags */
251 subreq
= smb2cli_create_send(state
, ev
, state
->conn
,
252 state
->timeout
, state
->session
,
255 SMB2_OPLOCK_LEVEL_NONE
,
256 SMB2_IMPERSONATION_IMPERSONATION
,
257 TSTREAM_SMBXCLI_NP_DESIRED_ACCESS
,
258 0, /* file_attributes */
259 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
261 0, /* create_options */
264 if (tevent_req_nomem(subreq
, req
)) {
265 return tevent_req_post(req
, ev
);
267 tevent_req_set_callback(subreq
, tstream_smbXcli_np_open_done
, req
);
272 static void tstream_smbXcli_np_open_done(struct tevent_req
*subreq
)
274 struct tevent_req
*req
=
275 tevent_req_callback_data(subreq
, struct tevent_req
);
276 struct tstream_smbXcli_np_open_state
*state
=
277 tevent_req_data(req
, struct tstream_smbXcli_np_open_state
);
280 if (state
->is_smb1
) {
281 status
= smb1cli_ntcreatex_recv(subreq
, &state
->fnum
);
283 status
= smb2cli_create_recv(subreq
,
284 &state
->fid_persistent
,
285 &state
->fid_volatile
,
289 if (!NT_STATUS_IS_OK(status
)) {
290 tevent_req_nterror(req
, status
);
294 tevent_req_done(req
);
297 NTSTATUS
_tstream_smbXcli_np_open_recv(struct tevent_req
*req
,
299 struct tstream_context
**_stream
,
300 const char *location
)
302 struct tstream_smbXcli_np_open_state
*state
=
303 tevent_req_data(req
, struct tstream_smbXcli_np_open_state
);
304 struct tstream_context
*stream
;
305 struct tstream_smbXcli_np
*cli_nps
;
308 if (tevent_req_is_nterror(req
, &status
)) {
309 tevent_req_received(req
);
313 stream
= tstream_context_create(mem_ctx
,
314 &tstream_smbXcli_np_ops
,
316 struct tstream_smbXcli_np
,
319 tevent_req_received(req
);
320 return NT_STATUS_NO_MEMORY
;
322 ZERO_STRUCTP(cli_nps
);
324 cli_nps
->conn_ref
= talloc_zero(state
->conn
,
325 struct tstream_smbXcli_np_ref
);
326 if (cli_nps
->conn_ref
== NULL
) {
327 TALLOC_FREE(cli_nps
);
328 tevent_req_received(req
);
329 return NT_STATUS_NO_MEMORY
;
331 cli_nps
->conn_ref
->cli_nps
= cli_nps
;
333 cli_nps
->session_ref
= talloc_zero(state
->session
,
334 struct tstream_smbXcli_np_ref
);
335 if (cli_nps
->session_ref
== NULL
) {
336 TALLOC_FREE(cli_nps
);
337 tevent_req_received(req
);
338 return NT_STATUS_NO_MEMORY
;
340 cli_nps
->session_ref
->cli_nps
= cli_nps
;
342 cli_nps
->tcon_ref
= talloc_zero(state
->tcon
,
343 struct tstream_smbXcli_np_ref
);
344 if (cli_nps
->tcon_ref
== NULL
) {
345 TALLOC_FREE(cli_nps
);
346 tevent_req_received(req
);
347 return NT_STATUS_NO_MEMORY
;
349 cli_nps
->tcon_ref
->cli_nps
= cli_nps
;
351 cli_nps
->conn
= state
->conn
;
352 cli_nps
->session
= state
->session
;
353 cli_nps
->tcon
= state
->tcon
;
354 cli_nps
->pid
= state
->pid
;
355 cli_nps
->timeout
= state
->timeout
;
356 cli_nps
->npipe
= talloc_move(cli_nps
, &state
->npipe
);
357 cli_nps
->is_smb1
= state
->is_smb1
;
358 cli_nps
->fnum
= state
->fnum
;
359 cli_nps
->fid_persistent
= state
->fid_persistent
;
360 cli_nps
->fid_volatile
= state
->fid_volatile
;
362 talloc_set_destructor(cli_nps
, tstream_smbXcli_np_destructor
);
363 talloc_set_destructor(cli_nps
->conn_ref
,
364 tstream_smbXcli_np_ref_destructor
);
365 talloc_set_destructor(cli_nps
->session_ref
,
366 tstream_smbXcli_np_ref_destructor
);
367 talloc_set_destructor(cli_nps
->tcon_ref
,
368 tstream_smbXcli_np_ref_destructor
);
370 cli_nps
->trans
.active
= false;
371 cli_nps
->trans
.read_req
= NULL
;
372 cli_nps
->trans
.write_req
= NULL
;
373 SSVAL(cli_nps
->trans
.setup
+0, 0, TRANSACT_DCERPCCMD
);
374 SSVAL(cli_nps
->trans
.setup
+1, 0, cli_nps
->fnum
);
377 tevent_req_received(req
);
381 static ssize_t
tstream_smbXcli_np_pending_bytes(struct tstream_context
*stream
)
383 struct tstream_smbXcli_np
*cli_nps
= tstream_context_data(stream
,
384 struct tstream_smbXcli_np
);
386 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
391 return cli_nps
->read
.left
;
394 bool tstream_is_smbXcli_np(struct tstream_context
*stream
)
396 struct tstream_smbXcli_np
*cli_nps
=
397 talloc_get_type(_tstream_context_data(stream
),
398 struct tstream_smbXcli_np
);
407 NTSTATUS
tstream_smbXcli_np_use_trans(struct tstream_context
*stream
)
409 struct tstream_smbXcli_np
*cli_nps
= tstream_context_data(stream
,
410 struct tstream_smbXcli_np
);
412 if (cli_nps
->trans
.read_req
) {
413 return NT_STATUS_PIPE_BUSY
;
416 if (cli_nps
->trans
.write_req
) {
417 return NT_STATUS_PIPE_BUSY
;
420 if (cli_nps
->trans
.active
) {
421 return NT_STATUS_PIPE_BUSY
;
424 cli_nps
->trans
.active
= true;
429 unsigned int tstream_smbXcli_np_set_timeout(struct tstream_context
*stream
,
430 unsigned int timeout
)
432 struct tstream_smbXcli_np
*cli_nps
= tstream_context_data(stream
,
433 struct tstream_smbXcli_np
);
434 unsigned int old_timeout
= cli_nps
->timeout
;
436 cli_nps
->timeout
= timeout
;
440 struct tstream_smbXcli_np_writev_state
{
441 struct tstream_context
*stream
;
442 struct tevent_context
*ev
;
444 struct iovec
*vector
;
451 const char *location
;
455 static int tstream_smbXcli_np_writev_state_destructor(struct tstream_smbXcli_np_writev_state
*state
)
457 struct tstream_smbXcli_np
*cli_nps
=
458 tstream_context_data(state
->stream
,
459 struct tstream_smbXcli_np
);
461 cli_nps
->trans
.write_req
= NULL
;
466 static void tstream_smbXcli_np_writev_write_next(struct tevent_req
*req
);
468 static struct tevent_req
*tstream_smbXcli_np_writev_send(TALLOC_CTX
*mem_ctx
,
469 struct tevent_context
*ev
,
470 struct tstream_context
*stream
,
471 const struct iovec
*vector
,
474 struct tevent_req
*req
;
475 struct tstream_smbXcli_np_writev_state
*state
;
476 struct tstream_smbXcli_np
*cli_nps
= tstream_context_data(stream
,
477 struct tstream_smbXcli_np
);
479 req
= tevent_req_create(mem_ctx
, &state
,
480 struct tstream_smbXcli_np_writev_state
);
484 state
->stream
= stream
;
488 talloc_set_destructor(state
, tstream_smbXcli_np_writev_state_destructor
);
490 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
491 tevent_req_error(req
, ENOTCONN
);
492 return tevent_req_post(req
, ev
);
496 * we make a copy of the vector so we can change the structure
498 state
->vector
= talloc_array(state
, struct iovec
, count
);
499 if (tevent_req_nomem(state
->vector
, req
)) {
500 return tevent_req_post(req
, ev
);
502 memcpy(state
->vector
, vector
, sizeof(struct iovec
) * count
);
503 state
->count
= count
;
505 tstream_smbXcli_np_writev_write_next(req
);
506 if (!tevent_req_is_in_progress(req
)) {
507 return tevent_req_post(req
, ev
);
513 static void tstream_smbXcli_np_readv_trans_start(struct tevent_req
*req
);
514 static void tstream_smbXcli_np_writev_write_done(struct tevent_req
*subreq
);
516 static void tstream_smbXcli_np_writev_write_next(struct tevent_req
*req
)
518 struct tstream_smbXcli_np_writev_state
*state
=
520 struct tstream_smbXcli_np_writev_state
);
521 struct tstream_smbXcli_np
*cli_nps
=
522 tstream_context_data(state
->stream
,
523 struct tstream_smbXcli_np
);
524 struct tevent_req
*subreq
;
528 for (i
=0; i
< state
->count
; i
++) {
529 left
+= state
->vector
[i
].iov_len
;
533 TALLOC_FREE(cli_nps
->write
.buf
);
534 tevent_req_done(req
);
538 cli_nps
->write
.ofs
= 0;
539 cli_nps
->write
.left
= MIN(left
, TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE
);
540 cli_nps
->write
.buf
= talloc_realloc(cli_nps
, cli_nps
->write
.buf
,
541 uint8_t, cli_nps
->write
.left
);
542 if (tevent_req_nomem(cli_nps
->write
.buf
, req
)) {
547 * copy the pending buffer first
549 while (cli_nps
->write
.left
> 0 && state
->count
> 0) {
550 uint8_t *base
= (uint8_t *)state
->vector
[0].iov_base
;
551 size_t len
= MIN(cli_nps
->write
.left
, state
->vector
[0].iov_len
);
553 memcpy(cli_nps
->write
.buf
+ cli_nps
->write
.ofs
, base
, len
);
556 state
->vector
[0].iov_base
= base
;
557 state
->vector
[0].iov_len
-= len
;
559 cli_nps
->write
.ofs
+= len
;
560 cli_nps
->write
.left
-= len
;
562 if (state
->vector
[0].iov_len
== 0) {
570 if (cli_nps
->trans
.active
&& state
->count
== 0) {
571 cli_nps
->trans
.active
= false;
572 cli_nps
->trans
.write_req
= req
;
576 if (cli_nps
->trans
.read_req
&& state
->count
== 0) {
577 cli_nps
->trans
.write_req
= req
;
578 tstream_smbXcli_np_readv_trans_start(cli_nps
->trans
.read_req
);
582 if (cli_nps
->is_smb1
) {
583 subreq
= smb1cli_writex_send(state
, state
->ev
,
590 8, /* 8 means message mode. */
593 cli_nps
->write
.ofs
); /* size */
595 subreq
= smb2cli_write_send(state
, state
->ev
,
600 cli_nps
->write
.ofs
, /* length */
602 cli_nps
->fid_persistent
,
603 cli_nps
->fid_volatile
,
604 0, /* remaining_bytes */
608 if (tevent_req_nomem(subreq
, req
)) {
611 tevent_req_set_callback(subreq
,
612 tstream_smbXcli_np_writev_write_done
,
616 static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req
*req
,
618 const char *location
);
620 static void tstream_smbXcli_np_writev_write_done(struct tevent_req
*subreq
)
622 struct tevent_req
*req
=
623 tevent_req_callback_data(subreq
, struct tevent_req
);
624 struct tstream_smbXcli_np_writev_state
*state
=
625 tevent_req_data(req
, struct tstream_smbXcli_np_writev_state
);
626 struct tstream_smbXcli_np
*cli_nps
=
627 tstream_context_data(state
->stream
,
628 struct tstream_smbXcli_np
);
632 if (cli_nps
->is_smb1
) {
633 status
= smb1cli_writex_recv(subreq
, &written
, NULL
);
635 status
= smb2cli_write_recv(subreq
, &written
);
638 if (!NT_STATUS_IS_OK(status
)) {
639 tstream_smbXcli_np_writev_disconnect_now(req
, EPIPE
, __location__
);
643 if (written
!= cli_nps
->write
.ofs
) {
644 tstream_smbXcli_np_writev_disconnect_now(req
, EIO
, __location__
);
648 tstream_smbXcli_np_writev_write_next(req
);
651 static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req
*subreq
);
653 static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req
*req
,
655 const char *location
)
657 struct tstream_smbXcli_np_writev_state
*state
=
659 struct tstream_smbXcli_np_writev_state
);
660 struct tstream_smbXcli_np
*cli_nps
=
661 tstream_context_data(state
->stream
,
662 struct tstream_smbXcli_np
);
663 struct tevent_req
*subreq
;
665 state
->error
.val
= error
;
666 state
->error
.location
= location
;
668 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
669 /* return the original error */
670 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
674 subreq
= tstream_smbXcli_np_disconnect_send(state
, state
->ev
,
676 if (subreq
== NULL
) {
677 /* return the original error */
678 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
681 tevent_req_set_callback(subreq
,
682 tstream_smbXcli_np_writev_disconnect_done
,
686 static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req
*subreq
)
688 struct tevent_req
*req
=
689 tevent_req_callback_data(subreq
, struct tevent_req
);
690 struct tstream_smbXcli_np_writev_state
*state
=
691 tevent_req_data(req
, struct tstream_smbXcli_np_writev_state
);
694 tstream_smbXcli_np_disconnect_recv(subreq
, &error
);
697 /* return the original error */
698 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
701 static int tstream_smbXcli_np_writev_recv(struct tevent_req
*req
,
704 struct tstream_smbXcli_np_writev_state
*state
=
706 struct tstream_smbXcli_np_writev_state
);
709 ret
= tsocket_simple_int_recv(req
, perrno
);
714 tevent_req_received(req
);
718 struct tstream_smbXcli_np_readv_state
{
719 struct tstream_context
*stream
;
720 struct tevent_context
*ev
;
722 struct iovec
*vector
;
728 struct tevent_immediate
*im
;
733 const char *location
;
737 static int tstream_smbXcli_np_readv_state_destructor(struct tstream_smbXcli_np_readv_state
*state
)
739 struct tstream_smbXcli_np
*cli_nps
=
740 tstream_context_data(state
->stream
,
741 struct tstream_smbXcli_np
);
743 cli_nps
->trans
.read_req
= NULL
;
748 static void tstream_smbXcli_np_readv_read_next(struct tevent_req
*req
);
750 static struct tevent_req
*tstream_smbXcli_np_readv_send(TALLOC_CTX
*mem_ctx
,
751 struct tevent_context
*ev
,
752 struct tstream_context
*stream
,
753 struct iovec
*vector
,
756 struct tevent_req
*req
;
757 struct tstream_smbXcli_np_readv_state
*state
;
758 struct tstream_smbXcli_np
*cli_nps
=
759 tstream_context_data(stream
, struct tstream_smbXcli_np
);
761 req
= tevent_req_create(mem_ctx
, &state
,
762 struct tstream_smbXcli_np_readv_state
);
766 state
->stream
= stream
;
770 talloc_set_destructor(state
, tstream_smbXcli_np_readv_state_destructor
);
772 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
773 tevent_req_error(req
, ENOTCONN
);
774 return tevent_req_post(req
, ev
);
778 * we make a copy of the vector so we can change the structure
780 state
->vector
= talloc_array(state
, struct iovec
, count
);
781 if (tevent_req_nomem(state
->vector
, req
)) {
782 return tevent_req_post(req
, ev
);
784 memcpy(state
->vector
, vector
, sizeof(struct iovec
) * count
);
785 state
->count
= count
;
787 tstream_smbXcli_np_readv_read_next(req
);
788 if (!tevent_req_is_in_progress(req
)) {
789 return tevent_req_post(req
, ev
);
795 static void tstream_smbXcli_np_readv_read_done(struct tevent_req
*subreq
);
797 static void tstream_smbXcli_np_readv_read_next(struct tevent_req
*req
)
799 struct tstream_smbXcli_np_readv_state
*state
=
801 struct tstream_smbXcli_np_readv_state
);
802 struct tstream_smbXcli_np
*cli_nps
=
803 tstream_context_data(state
->stream
,
804 struct tstream_smbXcli_np
);
805 struct tevent_req
*subreq
;
808 * copy the pending buffer first
810 while (cli_nps
->read
.left
> 0 && state
->count
> 0) {
811 uint8_t *base
= (uint8_t *)state
->vector
[0].iov_base
;
812 size_t len
= MIN(cli_nps
->read
.left
, state
->vector
[0].iov_len
);
814 memcpy(base
, cli_nps
->read
.buf
+ cli_nps
->read
.ofs
, len
);
817 state
->vector
[0].iov_base
= base
;
818 state
->vector
[0].iov_len
-= len
;
820 cli_nps
->read
.ofs
+= len
;
821 cli_nps
->read
.left
-= len
;
823 if (state
->vector
[0].iov_len
== 0) {
831 if (cli_nps
->read
.left
== 0) {
832 TALLOC_FREE(cli_nps
->read
.buf
);
835 if (state
->count
== 0) {
836 tevent_req_done(req
);
840 if (cli_nps
->trans
.active
) {
841 cli_nps
->trans
.active
= false;
842 cli_nps
->trans
.read_req
= req
;
846 if (cli_nps
->trans
.write_req
) {
847 cli_nps
->trans
.read_req
= req
;
848 tstream_smbXcli_np_readv_trans_start(req
);
852 if (cli_nps
->is_smb1
) {
853 subreq
= smb1cli_readx_send(state
, state
->ev
,
861 TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE
);
863 subreq
= smb2cli_read_send(state
, state
->ev
,
868 TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE
, /* length */
870 cli_nps
->fid_persistent
,
871 cli_nps
->fid_volatile
,
872 0, /* minimum_count */
873 0); /* remaining_bytes */
875 if (tevent_req_nomem(subreq
, req
)) {
878 tevent_req_set_callback(subreq
,
879 tstream_smbXcli_np_readv_read_done
,
883 static void tstream_smbXcli_np_readv_trans_done(struct tevent_req
*subreq
);
885 static void tstream_smbXcli_np_readv_trans_start(struct tevent_req
*req
)
887 struct tstream_smbXcli_np_readv_state
*state
=
889 struct tstream_smbXcli_np_readv_state
);
890 struct tstream_smbXcli_np
*cli_nps
=
891 tstream_context_data(state
->stream
,
892 struct tstream_smbXcli_np
);
893 struct tevent_req
*subreq
;
895 state
->trans
.im
= tevent_create_immediate(state
);
896 if (tevent_req_nomem(state
->trans
.im
, req
)) {
900 if (cli_nps
->is_smb1
) {
901 subreq
= smb1cli_trans_send(state
, state
->ev
,
902 cli_nps
->conn
, SMBtrans
,
911 cli_nps
->trans
.setup
, 2,
916 TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE
);
918 DATA_BLOB in_input_buffer
= data_blob_null
;
919 DATA_BLOB in_output_buffer
= data_blob_null
;
921 in_input_buffer
= data_blob_const(cli_nps
->write
.buf
,
924 subreq
= smb2cli_ioctl_send(state
, state
->ev
,
929 cli_nps
->fid_persistent
,
930 cli_nps
->fid_volatile
,
931 FSCTL_NAMED_PIPE_READ_WRITE
,
932 0, /* in_max_input_length */
934 /* in_max_output_length */
935 TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE
,
937 SMB2_IOCTL_FLAG_IS_FSCTL
);
939 if (tevent_req_nomem(subreq
, req
)) {
942 tevent_req_set_callback(subreq
,
943 tstream_smbXcli_np_readv_trans_done
,
947 static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req
*req
,
949 const char *location
);
950 static void tstream_smbXcli_np_readv_trans_next(struct tevent_context
*ctx
,
951 struct tevent_immediate
*im
,
954 static void tstream_smbXcli_np_readv_trans_done(struct tevent_req
*subreq
)
956 struct tevent_req
*req
=
957 tevent_req_callback_data(subreq
, struct tevent_req
);
958 struct tstream_smbXcli_np_readv_state
*state
=
959 tevent_req_data(req
, struct tstream_smbXcli_np_readv_state
);
960 struct tstream_smbXcli_np
*cli_nps
=
961 tstream_context_data(state
->stream
, struct tstream_smbXcli_np
);
966 if (cli_nps
->is_smb1
) {
967 status
= smb1cli_trans_recv(subreq
, state
, NULL
, NULL
, 0, NULL
,
969 &rcvbuf
, 0, &received
);
971 DATA_BLOB out_input_buffer
= data_blob_null
;
972 DATA_BLOB out_output_buffer
= data_blob_null
;
974 status
= smb2cli_ioctl_recv(subreq
, state
,
978 /* Note that rcvbuf is not a talloc pointer here */
979 rcvbuf
= out_output_buffer
.data
;
980 received
= out_output_buffer
.length
;
983 if (NT_STATUS_EQUAL(status
, STATUS_BUFFER_OVERFLOW
)) {
985 * STATUS_BUFFER_OVERFLOW means that there's
986 * more data to read when the named pipe is used
987 * in message mode (which is the case here).
989 * But we hide this from the caller.
991 status
= NT_STATUS_OK
;
993 if (!NT_STATUS_IS_OK(status
)) {
994 tstream_smbXcli_np_readv_disconnect_now(req
, EPIPE
, __location__
);
998 if (received
> TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE
) {
999 tstream_smbXcli_np_readv_disconnect_now(req
, EIO
, __location__
);
1003 if (received
== 0) {
1004 tstream_smbXcli_np_readv_disconnect_now(req
, EPIPE
, __location__
);
1008 cli_nps
->read
.ofs
= 0;
1009 cli_nps
->read
.left
= received
;
1010 cli_nps
->read
.buf
= talloc_array(cli_nps
, uint8_t, received
);
1011 if (cli_nps
->read
.buf
== NULL
) {
1012 TALLOC_FREE(subreq
);
1013 tevent_req_oom(req
);
1016 memcpy(cli_nps
->read
.buf
, rcvbuf
, received
);
1018 if (cli_nps
->trans
.write_req
== NULL
) {
1019 tstream_smbXcli_np_readv_read_next(req
);
1023 tevent_schedule_immediate(state
->trans
.im
, state
->ev
,
1024 tstream_smbXcli_np_readv_trans_next
, req
);
1026 tevent_req_done(cli_nps
->trans
.write_req
);
1029 static void tstream_smbXcli_np_readv_trans_next(struct tevent_context
*ctx
,
1030 struct tevent_immediate
*im
,
1033 struct tevent_req
*req
=
1034 talloc_get_type_abort(private_data
,
1037 tstream_smbXcli_np_readv_read_next(req
);
1040 static void tstream_smbXcli_np_readv_read_done(struct tevent_req
*subreq
)
1042 struct tevent_req
*req
=
1043 tevent_req_callback_data(subreq
, struct tevent_req
);
1044 struct tstream_smbXcli_np_readv_state
*state
=
1045 tevent_req_data(req
, struct tstream_smbXcli_np_readv_state
);
1046 struct tstream_smbXcli_np
*cli_nps
=
1047 tstream_context_data(state
->stream
, struct tstream_smbXcli_np
);
1053 * We must free subreq in this function as there is
1054 * a timer event attached to it.
1057 if (cli_nps
->is_smb1
) {
1058 status
= smb1cli_readx_recv(subreq
, &received
, &rcvbuf
);
1060 status
= smb2cli_read_recv(subreq
, state
, &rcvbuf
, &received
);
1063 * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
1066 if (NT_STATUS_EQUAL(status
, STATUS_BUFFER_OVERFLOW
)) {
1068 * STATUS_BUFFER_OVERFLOW means that there's
1069 * more data to read when the named pipe is used
1070 * in message mode (which is the case here).
1072 * But we hide this from the caller.
1074 status
= NT_STATUS_OK
;
1076 if (!NT_STATUS_IS_OK(status
)) {
1077 TALLOC_FREE(subreq
);
1078 tstream_smbXcli_np_readv_disconnect_now(req
, EPIPE
, __location__
);
1082 if (received
> TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE
) {
1083 TALLOC_FREE(subreq
);
1084 tstream_smbXcli_np_readv_disconnect_now(req
, EIO
, __location__
);
1088 if (received
== 0) {
1089 TALLOC_FREE(subreq
);
1090 tstream_smbXcli_np_readv_disconnect_now(req
, EPIPE
, __location__
);
1094 cli_nps
->read
.ofs
= 0;
1095 cli_nps
->read
.left
= received
;
1096 cli_nps
->read
.buf
= talloc_array(cli_nps
, uint8_t, received
);
1097 if (cli_nps
->read
.buf
== NULL
) {
1098 TALLOC_FREE(subreq
);
1099 tevent_req_oom(req
);
1102 memcpy(cli_nps
->read
.buf
, rcvbuf
, received
);
1103 TALLOC_FREE(subreq
);
1105 tstream_smbXcli_np_readv_read_next(req
);
1108 static void tstream_smbXcli_np_readv_disconnect_done(struct tevent_req
*subreq
);
1110 static void tstream_smbXcli_np_readv_error(struct tevent_req
*req
);
1112 static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req
*req
,
1114 const char *location
)
1116 struct tstream_smbXcli_np_readv_state
*state
=
1117 tevent_req_data(req
,
1118 struct tstream_smbXcli_np_readv_state
);
1119 struct tstream_smbXcli_np
*cli_nps
=
1120 tstream_context_data(state
->stream
,
1121 struct tstream_smbXcli_np
);
1122 struct tevent_req
*subreq
;
1124 state
->error
.val
= error
;
1125 state
->error
.location
= location
;
1127 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
1128 /* return the original error */
1129 tstream_smbXcli_np_readv_error(req
);
1133 subreq
= tstream_smbXcli_np_disconnect_send(state
, state
->ev
,
1135 if (subreq
== NULL
) {
1136 /* return the original error */
1137 tstream_smbXcli_np_readv_error(req
);
1140 tevent_req_set_callback(subreq
,
1141 tstream_smbXcli_np_readv_disconnect_done
,
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
);
1151 tstream_smbXcli_np_disconnect_recv(subreq
, &error
);
1152 TALLOC_FREE(subreq
);
1154 tstream_smbXcli_np_readv_error(req
);
1157 static void tstream_smbXcli_np_readv_error_trigger(struct tevent_context
*ctx
,
1158 struct tevent_immediate
*im
,
1159 void *private_data
);
1161 static void tstream_smbXcli_np_readv_error(struct tevent_req
*req
)
1163 struct tstream_smbXcli_np_readv_state
*state
=
1164 tevent_req_data(req
,
1165 struct tstream_smbXcli_np_readv_state
);
1166 struct tstream_smbXcli_np
*cli_nps
=
1167 tstream_context_data(state
->stream
,
1168 struct tstream_smbXcli_np
);
1170 if (cli_nps
->trans
.write_req
== NULL
) {
1171 /* return the original error */
1172 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
1176 if (state
->trans
.im
== NULL
) {
1177 /* return the original error */
1178 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
1182 tevent_schedule_immediate(state
->trans
.im
, state
->ev
,
1183 tstream_smbXcli_np_readv_error_trigger
, req
);
1185 /* return the original error for writev */
1186 _tevent_req_error(cli_nps
->trans
.write_req
,
1187 state
->error
.val
, state
->error
.location
);
1190 static void tstream_smbXcli_np_readv_error_trigger(struct tevent_context
*ctx
,
1191 struct tevent_immediate
*im
,
1194 struct tevent_req
*req
=
1195 talloc_get_type_abort(private_data
,
1197 struct tstream_smbXcli_np_readv_state
*state
=
1198 tevent_req_data(req
,
1199 struct tstream_smbXcli_np_readv_state
);
1201 /* return the original error */
1202 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
1205 static int tstream_smbXcli_np_readv_recv(struct tevent_req
*req
,
1208 struct tstream_smbXcli_np_readv_state
*state
=
1209 tevent_req_data(req
, struct tstream_smbXcli_np_readv_state
);
1212 ret
= tsocket_simple_int_recv(req
, perrno
);
1217 tevent_req_received(req
);
1221 struct tstream_smbXcli_np_disconnect_state
{
1222 struct tstream_context
*stream
;
1223 struct tevent_req
*subreq
;
1226 static void tstream_smbXcli_np_disconnect_done(struct tevent_req
*subreq
);
1227 static void tstream_smbXcli_np_disconnect_cleanup(struct tevent_req
*req
,
1228 enum tevent_req_state req_state
);
1230 static struct tevent_req
*tstream_smbXcli_np_disconnect_send(TALLOC_CTX
*mem_ctx
,
1231 struct tevent_context
*ev
,
1232 struct tstream_context
*stream
)
1234 struct tstream_smbXcli_np
*cli_nps
= tstream_context_data(stream
,
1235 struct tstream_smbXcli_np
);
1236 struct tevent_req
*req
;
1237 struct tstream_smbXcli_np_disconnect_state
*state
;
1238 struct tevent_req
*subreq
;
1240 req
= tevent_req_create(mem_ctx
, &state
,
1241 struct tstream_smbXcli_np_disconnect_state
);
1246 state
->stream
= stream
;
1248 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
1249 tevent_req_error(req
, ENOTCONN
);
1250 return tevent_req_post(req
, ev
);
1253 if (cli_nps
->is_smb1
) {
1254 subreq
= smb1cli_close_send(state
, ev
, cli_nps
->conn
,
1259 cli_nps
->fnum
, UINT32_MAX
);
1261 subreq
= smb2cli_close_send(state
, ev
, cli_nps
->conn
,
1266 cli_nps
->fid_persistent
,
1267 cli_nps
->fid_volatile
);
1269 if (tevent_req_nomem(subreq
, req
)) {
1270 return tevent_req_post(req
, ev
);
1272 tevent_req_set_callback(subreq
, tstream_smbXcli_np_disconnect_done
, req
);
1273 state
->subreq
= subreq
;
1275 tevent_req_set_cleanup_fn(req
, tstream_smbXcli_np_disconnect_cleanup
);
1278 * Make sure we don't send any requests anymore.
1280 cli_nps
->conn
= NULL
;
1285 static void tstream_smbXcli_np_disconnect_done(struct tevent_req
*subreq
)
1287 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
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
);
1295 state
->subreq
= NULL
;
1297 if (cli_nps
->is_smb1
) {
1298 status
= smb1cli_close_recv(subreq
);
1300 status
= smb2cli_close_recv(subreq
);
1302 TALLOC_FREE(subreq
);
1303 if (!NT_STATUS_IS_OK(status
)) {
1304 tevent_req_error(req
, EPIPE
);
1308 cli_nps
->conn
= NULL
;
1309 cli_nps
->session
= NULL
;
1310 cli_nps
->tcon
= NULL
;
1312 tevent_req_done(req
);
1315 static void tstream_smbXcli_np_disconnect_free(struct tevent_req
*subreq
);
1317 static void tstream_smbXcli_np_disconnect_cleanup(struct tevent_req
*req
,
1318 enum tevent_req_state req_state
)
1320 struct tstream_smbXcli_np_disconnect_state
*state
=
1321 tevent_req_data(req
, struct tstream_smbXcli_np_disconnect_state
);
1322 struct tstream_smbXcli_np
*cli_nps
= NULL
;
1324 if (state
->subreq
== NULL
) {
1328 cli_nps
= tstream_context_data(state
->stream
, struct tstream_smbXcli_np
);
1330 if (cli_nps
->tcon
== NULL
) {
1335 * We're no longer interested in the result
1336 * any more, but need to make sure that the close
1337 * request arrives at the server if the smb connection,
1338 * session and tcon are still alive.
1340 * We move the low level request to the tcon,
1341 * which means that it stays as long as the tcon
1344 talloc_steal(cli_nps
->tcon
, state
->subreq
);
1345 tevent_req_set_callback(state
->subreq
,
1346 tstream_smbXcli_np_disconnect_free
,
1348 state
->subreq
= NULL
;
1350 cli_nps
->conn
= NULL
;
1351 cli_nps
->session
= NULL
;
1352 cli_nps
->tcon
= NULL
;
1355 static void tstream_smbXcli_np_disconnect_free(struct tevent_req
*subreq
)
1357 TALLOC_FREE(subreq
);
1360 static int tstream_smbXcli_np_disconnect_recv(struct tevent_req
*req
,
1365 ret
= tsocket_simple_int_recv(req
, perrno
);
1367 tevent_req_received(req
);
1371 static const struct tstream_context_ops tstream_smbXcli_np_ops
= {
1372 .name
= "smbXcli_np",
1374 .pending_bytes
= tstream_smbXcli_np_pending_bytes
,
1376 .readv_send
= tstream_smbXcli_np_readv_send
,
1377 .readv_recv
= tstream_smbXcli_np_readv_recv
,
1379 .writev_send
= tstream_smbXcli_np_writev_send
,
1380 .writev_recv
= tstream_smbXcli_np_writev_recv
,
1382 .disconnect_send
= tstream_smbXcli_np_disconnect_send
,
1383 .disconnect_recv
= tstream_smbXcli_np_disconnect_recv
,