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"
29 #include "lib/util/iov_buf.h"
31 static const struct tstream_context_ops tstream_smbXcli_np_ops
;
33 #define TSTREAM_SMBXCLI_NP_DESIRED_ACCESS ( \
34 SEC_STD_READ_CONTROL | \
35 SEC_FILE_READ_DATA | \
36 SEC_FILE_WRITE_DATA | \
37 SEC_FILE_APPEND_DATA | \
40 SEC_FILE_READ_ATTRIBUTE | \
41 SEC_FILE_WRITE_ATTRIBUTE | \
44 struct tstream_smbXcli_np_ref
;
46 struct tstream_smbXcli_np
{
47 struct smbXcli_conn
*conn
;
48 struct tstream_smbXcli_np_ref
*conn_ref
;
49 struct smbXcli_session
*session
;
50 struct tstream_smbXcli_np_ref
*session_ref
;
51 struct smbXcli_tcon
*tcon
;
52 struct tstream_smbXcli_np_ref
*tcon_ref
;
59 uint64_t fid_persistent
;
60 uint64_t fid_volatile
;
65 struct tevent_req
*read_req
;
66 struct tevent_req
*write_req
;
77 struct tstream_smbXcli_np_ref
{
78 struct tstream_smbXcli_np
*cli_nps
;
81 static int tstream_smbXcli_np_destructor(struct tstream_smbXcli_np
*cli_nps
)
85 if (cli_nps
->conn_ref
!= NULL
) {
86 cli_nps
->conn_ref
->cli_nps
= NULL
;
87 TALLOC_FREE(cli_nps
->conn_ref
);
90 if (cli_nps
->session_ref
!= NULL
) {
91 cli_nps
->session_ref
->cli_nps
= NULL
;
92 TALLOC_FREE(cli_nps
->session_ref
);
95 if (cli_nps
->tcon_ref
!= NULL
) {
96 cli_nps
->tcon_ref
->cli_nps
= NULL
;
97 TALLOC_FREE(cli_nps
->tcon_ref
);
100 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
105 * TODO: do not use a sync call with a destructor!!!
107 * This only happens, if a caller does talloc_free(),
108 * while the everything was still ok.
110 * If we get an unexpected failure within a normal
111 * operation, we already do an async cli_close_send()/_recv().
113 * Once we've fixed all callers to call
114 * tstream_disconnect_send()/_recv(), this will
117 * We use a maximum timeout of 1 second == 1000 msec.
119 cli_nps
->timeout
= MIN(cli_nps
->timeout
, 1000);
121 if (cli_nps
->is_smb1
) {
122 status
= smb1cli_close(cli_nps
->conn
,
127 cli_nps
->fnum
, UINT32_MAX
);
129 status
= smb2cli_close(cli_nps
->conn
,
134 cli_nps
->fid_persistent
,
135 cli_nps
->fid_volatile
);
137 if (!NT_STATUS_IS_OK(status
)) {
138 DEBUG(1, ("tstream_smbXcli_np_destructor: cli_close "
139 "failed on pipe %s. Error was %s\n",
140 cli_nps
->npipe
, nt_errstr(status
)));
143 * We can't do much on failure
148 static int tstream_smbXcli_np_ref_destructor(struct tstream_smbXcli_np_ref
*ref
)
150 if (ref
->cli_nps
== NULL
) {
154 if (ref
->cli_nps
->conn
== NULL
) {
158 ref
->cli_nps
->conn
= NULL
;
159 ref
->cli_nps
->session
= NULL
;
160 ref
->cli_nps
->tcon
= NULL
;
162 TALLOC_FREE(ref
->cli_nps
->conn_ref
);
163 TALLOC_FREE(ref
->cli_nps
->session_ref
);
164 TALLOC_FREE(ref
->cli_nps
->tcon_ref
);
169 static struct tevent_req
*tstream_smbXcli_np_disconnect_send(TALLOC_CTX
*mem_ctx
,
170 struct tevent_context
*ev
,
171 struct tstream_context
*stream
);
172 static int tstream_smbXcli_np_disconnect_recv(struct tevent_req
*req
,
175 struct tstream_smbXcli_np_open_state
{
176 struct smbXcli_conn
*conn
;
177 struct smbXcli_session
*session
;
178 struct smbXcli_tcon
*tcon
;
180 unsigned int timeout
;
184 uint64_t fid_persistent
;
185 uint64_t fid_volatile
;
189 static void tstream_smbXcli_np_open_done(struct tevent_req
*subreq
);
191 struct tevent_req
*tstream_smbXcli_np_open_send(TALLOC_CTX
*mem_ctx
,
192 struct tevent_context
*ev
,
193 struct smbXcli_conn
*conn
,
194 struct smbXcli_session
*session
,
195 struct smbXcli_tcon
*tcon
,
197 unsigned int timeout
,
200 struct tevent_req
*req
;
201 struct tstream_smbXcli_np_open_state
*state
;
202 struct tevent_req
*subreq
;
204 req
= tevent_req_create(mem_ctx
, &state
,
205 struct tstream_smbXcli_np_open_state
);
211 state
->session
= session
;
213 state
->timeout
= timeout
;
215 state
->npipe
= talloc_strdup(state
, npipe
);
216 if (tevent_req_nomem(state
->npipe
, req
)) {
217 return tevent_req_post(req
, ev
);
220 if (smbXcli_conn_protocol(conn
) < PROTOCOL_SMB2_02
) {
221 state
->is_smb1
= true;
224 if (state
->is_smb1
) {
225 const char *smb1_npipe
;
228 * Windows and newer Samba versions allow
229 * the pipe name without leading backslash,
230 * but we should better behave like windows clients
232 smb1_npipe
= talloc_asprintf(state
, "\\%s", state
->npipe
);
233 if (tevent_req_nomem(smb1_npipe
, req
)) {
234 return tevent_req_post(req
, ev
);
236 subreq
= smb1cli_ntcreatex_send(state
, ev
, state
->conn
,
243 0, /* RootDirectoryFid */
244 TSTREAM_SMBXCLI_NP_DESIRED_ACCESS
,
245 0, /* AllocationSize */
246 0, /* FileAttributes */
247 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
248 FILE_OPEN
, /* CreateDisposition */
249 0, /* CreateOptions */
250 2, /* NTCREATEX_IMPERSONATION_IMPERSONATION */
251 0); /* SecurityFlags */
253 subreq
= smb2cli_create_send(state
, ev
, state
->conn
,
254 state
->timeout
, state
->session
,
257 SMB2_OPLOCK_LEVEL_NONE
,
258 SMB2_IMPERSONATION_IMPERSONATION
,
259 TSTREAM_SMBXCLI_NP_DESIRED_ACCESS
,
260 0, /* file_attributes */
261 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
263 0, /* create_options */
266 if (tevent_req_nomem(subreq
, req
)) {
267 return tevent_req_post(req
, ev
);
269 tevent_req_set_callback(subreq
, tstream_smbXcli_np_open_done
, req
);
274 static void tstream_smbXcli_np_open_done(struct tevent_req
*subreq
)
276 struct tevent_req
*req
=
277 tevent_req_callback_data(subreq
, struct tevent_req
);
278 struct tstream_smbXcli_np_open_state
*state
=
279 tevent_req_data(req
, struct tstream_smbXcli_np_open_state
);
282 if (state
->is_smb1
) {
283 status
= smb1cli_ntcreatex_recv(subreq
, &state
->fnum
);
285 status
= smb2cli_create_recv(
287 &state
->fid_persistent
,
288 &state
->fid_volatile
,
295 if (!NT_STATUS_IS_OK(status
)) {
296 tevent_req_nterror(req
, status
);
300 tevent_req_done(req
);
303 NTSTATUS
_tstream_smbXcli_np_open_recv(struct tevent_req
*req
,
305 struct tstream_context
**_stream
,
306 const char *location
)
308 struct tstream_smbXcli_np_open_state
*state
=
309 tevent_req_data(req
, struct tstream_smbXcli_np_open_state
);
310 struct tstream_context
*stream
;
311 struct tstream_smbXcli_np
*cli_nps
;
314 if (tevent_req_is_nterror(req
, &status
)) {
315 tevent_req_received(req
);
319 stream
= tstream_context_create(mem_ctx
,
320 &tstream_smbXcli_np_ops
,
322 struct tstream_smbXcli_np
,
325 tevent_req_received(req
);
326 return NT_STATUS_NO_MEMORY
;
328 ZERO_STRUCTP(cli_nps
);
330 cli_nps
->conn_ref
= talloc_zero(state
->conn
,
331 struct tstream_smbXcli_np_ref
);
332 if (cli_nps
->conn_ref
== NULL
) {
333 TALLOC_FREE(cli_nps
);
334 tevent_req_received(req
);
335 return NT_STATUS_NO_MEMORY
;
337 cli_nps
->conn_ref
->cli_nps
= cli_nps
;
339 cli_nps
->session_ref
= talloc_zero(state
->session
,
340 struct tstream_smbXcli_np_ref
);
341 if (cli_nps
->session_ref
== NULL
) {
342 TALLOC_FREE(cli_nps
);
343 tevent_req_received(req
);
344 return NT_STATUS_NO_MEMORY
;
346 cli_nps
->session_ref
->cli_nps
= cli_nps
;
348 cli_nps
->tcon_ref
= talloc_zero(state
->tcon
,
349 struct tstream_smbXcli_np_ref
);
350 if (cli_nps
->tcon_ref
== NULL
) {
351 TALLOC_FREE(cli_nps
);
352 tevent_req_received(req
);
353 return NT_STATUS_NO_MEMORY
;
355 cli_nps
->tcon_ref
->cli_nps
= cli_nps
;
357 cli_nps
->conn
= state
->conn
;
358 cli_nps
->session
= state
->session
;
359 cli_nps
->tcon
= state
->tcon
;
360 cli_nps
->pid
= state
->pid
;
361 cli_nps
->timeout
= state
->timeout
;
362 cli_nps
->npipe
= talloc_move(cli_nps
, &state
->npipe
);
363 cli_nps
->is_smb1
= state
->is_smb1
;
364 cli_nps
->fnum
= state
->fnum
;
365 cli_nps
->fid_persistent
= state
->fid_persistent
;
366 cli_nps
->fid_volatile
= state
->fid_volatile
;
367 cli_nps
->max_data
= TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE
;
369 talloc_set_destructor(cli_nps
, tstream_smbXcli_np_destructor
);
370 talloc_set_destructor(cli_nps
->conn_ref
,
371 tstream_smbXcli_np_ref_destructor
);
372 talloc_set_destructor(cli_nps
->session_ref
,
373 tstream_smbXcli_np_ref_destructor
);
374 talloc_set_destructor(cli_nps
->tcon_ref
,
375 tstream_smbXcli_np_ref_destructor
);
377 cli_nps
->trans
.active
= false;
378 cli_nps
->trans
.read_req
= NULL
;
379 cli_nps
->trans
.write_req
= NULL
;
380 SSVAL(cli_nps
->trans
.setup
+0, 0, TRANSACT_DCERPCCMD
);
381 SSVAL(cli_nps
->trans
.setup
+1, 0, cli_nps
->fnum
);
384 tevent_req_received(req
);
388 static ssize_t
tstream_smbXcli_np_pending_bytes(struct tstream_context
*stream
)
390 struct tstream_smbXcli_np
*cli_nps
= tstream_context_data(stream
,
391 struct tstream_smbXcli_np
);
393 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
398 return cli_nps
->read
.left
;
401 bool tstream_is_smbXcli_np(struct tstream_context
*stream
)
403 struct tstream_smbXcli_np
*cli_nps
=
404 talloc_get_type(_tstream_context_data(stream
),
405 struct tstream_smbXcli_np
);
414 NTSTATUS
tstream_smbXcli_np_use_trans(struct tstream_context
*stream
)
416 struct tstream_smbXcli_np
*cli_nps
= tstream_context_data(stream
,
417 struct tstream_smbXcli_np
);
419 if (cli_nps
->trans
.read_req
) {
420 return NT_STATUS_PIPE_BUSY
;
423 if (cli_nps
->trans
.write_req
) {
424 return NT_STATUS_PIPE_BUSY
;
427 if (cli_nps
->trans
.active
) {
428 return NT_STATUS_PIPE_BUSY
;
431 cli_nps
->trans
.active
= true;
436 void tstream_smbXcli_np_set_max_data(struct tstream_context
*stream
,
439 struct tstream_smbXcli_np
*cli_nps
= tstream_context_data(
440 stream
, struct tstream_smbXcli_np
);
442 cli_nps
->max_data
= max_data
;
445 unsigned int tstream_smbXcli_np_set_timeout(struct tstream_context
*stream
,
446 unsigned int timeout
)
448 struct tstream_smbXcli_np
*cli_nps
= tstream_context_data(stream
,
449 struct tstream_smbXcli_np
);
450 unsigned int old_timeout
= cli_nps
->timeout
;
452 cli_nps
->timeout
= timeout
;
456 struct tstream_smbXcli_np_writev_state
{
457 struct tstream_context
*stream
;
458 struct tevent_context
*ev
;
460 struct iovec
*vector
;
467 const char *location
;
471 static int tstream_smbXcli_np_writev_state_destructor(struct tstream_smbXcli_np_writev_state
*state
)
473 struct tstream_smbXcli_np
*cli_nps
=
474 tstream_context_data(state
->stream
,
475 struct tstream_smbXcli_np
);
477 cli_nps
->trans
.write_req
= NULL
;
482 static void tstream_smbXcli_np_writev_write_next(struct tevent_req
*req
);
484 static struct tevent_req
*tstream_smbXcli_np_writev_send(TALLOC_CTX
*mem_ctx
,
485 struct tevent_context
*ev
,
486 struct tstream_context
*stream
,
487 const struct iovec
*vector
,
490 struct tevent_req
*req
;
491 struct tstream_smbXcli_np_writev_state
*state
;
492 struct tstream_smbXcli_np
*cli_nps
= tstream_context_data(stream
,
493 struct tstream_smbXcli_np
);
495 req
= tevent_req_create(mem_ctx
, &state
,
496 struct tstream_smbXcli_np_writev_state
);
500 state
->stream
= stream
;
504 talloc_set_destructor(state
, tstream_smbXcli_np_writev_state_destructor
);
506 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
507 tevent_req_error(req
, ENOTCONN
);
508 return tevent_req_post(req
, ev
);
512 * we make a copy of the vector so we can change the structure
514 state
->vector
= talloc_array(state
, struct iovec
, count
);
515 if (tevent_req_nomem(state
->vector
, req
)) {
516 return tevent_req_post(req
, ev
);
518 memcpy(state
->vector
, vector
, sizeof(struct iovec
) * count
);
519 state
->count
= count
;
521 tstream_smbXcli_np_writev_write_next(req
);
522 if (!tevent_req_is_in_progress(req
)) {
523 return tevent_req_post(req
, ev
);
529 static void tstream_smbXcli_np_readv_trans_start(struct tevent_req
*req
);
530 static void tstream_smbXcli_np_writev_write_done(struct tevent_req
*subreq
);
532 static void tstream_smbXcli_np_writev_write_next(struct tevent_req
*req
)
534 struct tstream_smbXcli_np_writev_state
*state
=
536 struct tstream_smbXcli_np_writev_state
);
537 struct tstream_smbXcli_np
*cli_nps
=
538 tstream_context_data(state
->stream
,
539 struct tstream_smbXcli_np
);
540 struct tevent_req
*subreq
;
543 left
= iov_buflen(state
->vector
, state
->count
);
546 tevent_req_error(req
, EMSGSIZE
);
551 TALLOC_FREE(cli_nps
->write
.buf
);
552 tevent_req_done(req
);
556 cli_nps
->write
.ofs
= 0;
557 cli_nps
->write
.left
= MIN(left
, cli_nps
->max_data
);
558 cli_nps
->write
.buf
= talloc_realloc(cli_nps
, cli_nps
->write
.buf
,
559 uint8_t, cli_nps
->write
.left
);
560 if (tevent_req_nomem(cli_nps
->write
.buf
, req
)) {
565 * copy the pending buffer first
567 while (cli_nps
->write
.left
> 0 && state
->count
> 0) {
568 uint8_t *base
= (uint8_t *)state
->vector
[0].iov_base
;
569 size_t len
= MIN(cli_nps
->write
.left
, state
->vector
[0].iov_len
);
571 memcpy(cli_nps
->write
.buf
+ cli_nps
->write
.ofs
, base
, len
);
574 state
->vector
[0].iov_base
= base
;
575 state
->vector
[0].iov_len
-= len
;
577 cli_nps
->write
.ofs
+= len
;
578 cli_nps
->write
.left
-= len
;
580 if (state
->vector
[0].iov_len
== 0) {
588 if (cli_nps
->trans
.active
&& state
->count
== 0) {
589 cli_nps
->trans
.active
= false;
590 cli_nps
->trans
.write_req
= req
;
594 if (cli_nps
->trans
.read_req
&& state
->count
== 0) {
595 cli_nps
->trans
.write_req
= req
;
596 tstream_smbXcli_np_readv_trans_start(cli_nps
->trans
.read_req
);
600 if (cli_nps
->is_smb1
) {
601 subreq
= smb1cli_writex_send(state
, state
->ev
,
608 8, /* 8 means message mode. */
611 cli_nps
->write
.ofs
); /* size */
613 subreq
= smb2cli_write_send(state
, state
->ev
,
618 cli_nps
->write
.ofs
, /* length */
620 cli_nps
->fid_persistent
,
621 cli_nps
->fid_volatile
,
622 0, /* remaining_bytes */
626 if (tevent_req_nomem(subreq
, req
)) {
629 tevent_req_set_callback(subreq
,
630 tstream_smbXcli_np_writev_write_done
,
634 static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req
*req
,
636 const char *location
);
638 static void tstream_smbXcli_np_writev_write_done(struct tevent_req
*subreq
)
640 struct tevent_req
*req
=
641 tevent_req_callback_data(subreq
, struct tevent_req
);
642 struct tstream_smbXcli_np_writev_state
*state
=
643 tevent_req_data(req
, struct tstream_smbXcli_np_writev_state
);
644 struct tstream_smbXcli_np
*cli_nps
=
645 tstream_context_data(state
->stream
,
646 struct tstream_smbXcli_np
);
650 if (cli_nps
->is_smb1
) {
651 status
= smb1cli_writex_recv(subreq
, &written
, NULL
);
653 status
= smb2cli_write_recv(subreq
, &written
);
656 if (!NT_STATUS_IS_OK(status
)) {
657 tstream_smbXcli_np_writev_disconnect_now(req
, EPIPE
, __location__
);
661 if (written
!= cli_nps
->write
.ofs
) {
662 tstream_smbXcli_np_writev_disconnect_now(req
, EIO
, __location__
);
666 tstream_smbXcli_np_writev_write_next(req
);
669 static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req
*subreq
);
671 static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req
*req
,
673 const char *location
)
675 struct tstream_smbXcli_np_writev_state
*state
=
677 struct tstream_smbXcli_np_writev_state
);
678 struct tstream_smbXcli_np
*cli_nps
=
679 tstream_context_data(state
->stream
,
680 struct tstream_smbXcli_np
);
681 struct tevent_req
*subreq
;
683 state
->error
.val
= error
;
684 state
->error
.location
= location
;
686 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
687 /* return the original error */
688 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
692 subreq
= tstream_smbXcli_np_disconnect_send(state
, state
->ev
,
694 if (subreq
== NULL
) {
695 /* return the original error */
696 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
699 tevent_req_set_callback(subreq
,
700 tstream_smbXcli_np_writev_disconnect_done
,
704 static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req
*subreq
)
706 struct tevent_req
*req
=
707 tevent_req_callback_data(subreq
, struct tevent_req
);
708 struct tstream_smbXcli_np_writev_state
*state
=
709 tevent_req_data(req
, struct tstream_smbXcli_np_writev_state
);
712 tstream_smbXcli_np_disconnect_recv(subreq
, &error
);
715 /* return the original error */
716 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
719 static int tstream_smbXcli_np_writev_recv(struct tevent_req
*req
,
722 struct tstream_smbXcli_np_writev_state
*state
=
724 struct tstream_smbXcli_np_writev_state
);
727 ret
= tsocket_simple_int_recv(req
, perrno
);
732 tevent_req_received(req
);
736 struct tstream_smbXcli_np_readv_state
{
737 struct tstream_context
*stream
;
738 struct tevent_context
*ev
;
740 struct iovec
*vector
;
746 struct tevent_immediate
*im
;
751 const char *location
;
755 static int tstream_smbXcli_np_readv_state_destructor(struct tstream_smbXcli_np_readv_state
*state
)
757 struct tstream_smbXcli_np
*cli_nps
=
758 tstream_context_data(state
->stream
,
759 struct tstream_smbXcli_np
);
761 cli_nps
->trans
.read_req
= NULL
;
766 static void tstream_smbXcli_np_readv_read_next(struct tevent_req
*req
);
768 static struct tevent_req
*tstream_smbXcli_np_readv_send(TALLOC_CTX
*mem_ctx
,
769 struct tevent_context
*ev
,
770 struct tstream_context
*stream
,
771 struct iovec
*vector
,
774 struct tevent_req
*req
;
775 struct tstream_smbXcli_np_readv_state
*state
;
776 struct tstream_smbXcli_np
*cli_nps
=
777 tstream_context_data(stream
, struct tstream_smbXcli_np
);
779 req
= tevent_req_create(mem_ctx
, &state
,
780 struct tstream_smbXcli_np_readv_state
);
784 state
->stream
= stream
;
788 talloc_set_destructor(state
, tstream_smbXcli_np_readv_state_destructor
);
790 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
791 tevent_req_error(req
, ENOTCONN
);
792 return tevent_req_post(req
, ev
);
796 * we make a copy of the vector so we can change the structure
798 state
->vector
= talloc_array(state
, struct iovec
, count
);
799 if (tevent_req_nomem(state
->vector
, req
)) {
800 return tevent_req_post(req
, ev
);
802 memcpy(state
->vector
, vector
, sizeof(struct iovec
) * count
);
803 state
->count
= count
;
805 tstream_smbXcli_np_readv_read_next(req
);
806 if (!tevent_req_is_in_progress(req
)) {
807 return tevent_req_post(req
, ev
);
813 static void tstream_smbXcli_np_readv_read_done(struct tevent_req
*subreq
);
815 static void tstream_smbXcli_np_readv_read_next(struct tevent_req
*req
)
817 struct tstream_smbXcli_np_readv_state
*state
=
819 struct tstream_smbXcli_np_readv_state
);
820 struct tstream_smbXcli_np
*cli_nps
=
821 tstream_context_data(state
->stream
,
822 struct tstream_smbXcli_np
);
823 struct tevent_req
*subreq
;
826 * copy the pending buffer first
828 while (cli_nps
->read
.left
> 0 && state
->count
> 0) {
829 uint8_t *base
= (uint8_t *)state
->vector
[0].iov_base
;
830 size_t len
= MIN(cli_nps
->read
.left
, state
->vector
[0].iov_len
);
832 memcpy(base
, cli_nps
->read
.buf
+ cli_nps
->read
.ofs
, len
);
835 state
->vector
[0].iov_base
= base
;
836 state
->vector
[0].iov_len
-= len
;
838 cli_nps
->read
.ofs
+= len
;
839 cli_nps
->read
.left
-= len
;
841 if (state
->vector
[0].iov_len
== 0) {
849 if (cli_nps
->read
.left
== 0) {
850 TALLOC_FREE(cli_nps
->read
.buf
);
853 if (state
->count
== 0) {
854 tevent_req_done(req
);
858 if (cli_nps
->trans
.active
) {
859 cli_nps
->trans
.active
= false;
860 cli_nps
->trans
.read_req
= req
;
864 if (cli_nps
->trans
.write_req
) {
865 cli_nps
->trans
.read_req
= req
;
866 tstream_smbXcli_np_readv_trans_start(req
);
870 if (cli_nps
->is_smb1
) {
871 subreq
= smb1cli_readx_send(state
, state
->ev
,
881 subreq
= smb2cli_read_send(state
, state
->ev
,
886 cli_nps
->max_data
, /* length */
888 cli_nps
->fid_persistent
,
889 cli_nps
->fid_volatile
,
890 0, /* minimum_count */
891 0); /* remaining_bytes */
893 if (tevent_req_nomem(subreq
, req
)) {
896 tevent_req_set_callback(subreq
,
897 tstream_smbXcli_np_readv_read_done
,
901 static void tstream_smbXcli_np_readv_trans_done(struct tevent_req
*subreq
);
903 static void tstream_smbXcli_np_readv_trans_start(struct tevent_req
*req
)
905 struct tstream_smbXcli_np_readv_state
*state
=
907 struct tstream_smbXcli_np_readv_state
);
908 struct tstream_smbXcli_np
*cli_nps
=
909 tstream_context_data(state
->stream
,
910 struct tstream_smbXcli_np
);
911 struct tevent_req
*subreq
;
913 state
->trans
.im
= tevent_create_immediate(state
);
914 if (tevent_req_nomem(state
->trans
.im
, req
)) {
918 if (cli_nps
->is_smb1
) {
919 subreq
= smb1cli_trans_send(state
, state
->ev
,
920 cli_nps
->conn
, SMBtrans
,
929 cli_nps
->trans
.setup
, 2,
936 DATA_BLOB in_input_buffer
= data_blob_null
;
937 DATA_BLOB in_output_buffer
= data_blob_null
;
939 in_input_buffer
= data_blob_const(cli_nps
->write
.buf
,
942 subreq
= smb2cli_ioctl_send(state
, state
->ev
,
947 cli_nps
->fid_persistent
,
948 cli_nps
->fid_volatile
,
949 FSCTL_NAMED_PIPE_READ_WRITE
,
950 0, /* in_max_input_length */
952 /* in_max_output_length */
955 SMB2_IOCTL_FLAG_IS_FSCTL
);
957 if (tevent_req_nomem(subreq
, req
)) {
960 tevent_req_set_callback(subreq
,
961 tstream_smbXcli_np_readv_trans_done
,
965 static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req
*req
,
967 const char *location
);
968 static void tstream_smbXcli_np_readv_trans_next(struct tevent_context
*ctx
,
969 struct tevent_immediate
*im
,
972 static void tstream_smbXcli_np_readv_trans_done(struct tevent_req
*subreq
)
974 struct tevent_req
*req
=
975 tevent_req_callback_data(subreq
, struct tevent_req
);
976 struct tstream_smbXcli_np_readv_state
*state
=
977 tevent_req_data(req
, struct tstream_smbXcli_np_readv_state
);
978 struct tstream_smbXcli_np
*cli_nps
=
979 tstream_context_data(state
->stream
, struct tstream_smbXcli_np
);
984 if (cli_nps
->is_smb1
) {
985 status
= smb1cli_trans_recv(subreq
, state
, NULL
, NULL
, 0, NULL
,
987 &rcvbuf
, 0, &received
);
989 DATA_BLOB out_input_buffer
= data_blob_null
;
990 DATA_BLOB out_output_buffer
= data_blob_null
;
992 status
= smb2cli_ioctl_recv(subreq
, state
,
996 /* Note that rcvbuf is not a talloc pointer here */
997 rcvbuf
= out_output_buffer
.data
;
998 received
= out_output_buffer
.length
;
1000 TALLOC_FREE(subreq
);
1001 if (NT_STATUS_EQUAL(status
, STATUS_BUFFER_OVERFLOW
)) {
1003 * STATUS_BUFFER_OVERFLOW means that there's
1004 * more data to read when the named pipe is used
1005 * in message mode (which is the case here).
1007 * But we hide this from the caller.
1009 status
= NT_STATUS_OK
;
1011 if (!NT_STATUS_IS_OK(status
)) {
1012 tstream_smbXcli_np_readv_disconnect_now(req
, EPIPE
, __location__
);
1016 if (received
> cli_nps
->max_data
) {
1017 tstream_smbXcli_np_readv_disconnect_now(req
, EIO
, __location__
);
1021 if (received
== 0) {
1022 tstream_smbXcli_np_readv_disconnect_now(req
, EPIPE
, __location__
);
1026 cli_nps
->read
.ofs
= 0;
1027 cli_nps
->read
.left
= received
;
1028 cli_nps
->read
.buf
= talloc_array(cli_nps
, uint8_t, received
);
1029 if (cli_nps
->read
.buf
== NULL
) {
1030 TALLOC_FREE(subreq
);
1031 tevent_req_oom(req
);
1034 memcpy(cli_nps
->read
.buf
, rcvbuf
, received
);
1036 if (cli_nps
->trans
.write_req
== NULL
) {
1037 tstream_smbXcli_np_readv_read_next(req
);
1041 tevent_schedule_immediate(state
->trans
.im
, state
->ev
,
1042 tstream_smbXcli_np_readv_trans_next
, req
);
1044 tevent_req_done(cli_nps
->trans
.write_req
);
1047 static void tstream_smbXcli_np_readv_trans_next(struct tevent_context
*ctx
,
1048 struct tevent_immediate
*im
,
1051 struct tevent_req
*req
=
1052 talloc_get_type_abort(private_data
,
1055 tstream_smbXcli_np_readv_read_next(req
);
1058 static void tstream_smbXcli_np_readv_read_done(struct tevent_req
*subreq
)
1060 struct tevent_req
*req
=
1061 tevent_req_callback_data(subreq
, struct tevent_req
);
1062 struct tstream_smbXcli_np_readv_state
*state
=
1063 tevent_req_data(req
, struct tstream_smbXcli_np_readv_state
);
1064 struct tstream_smbXcli_np
*cli_nps
=
1065 tstream_context_data(state
->stream
, struct tstream_smbXcli_np
);
1071 * We must free subreq in this function as there is
1072 * a timer event attached to it.
1075 if (cli_nps
->is_smb1
) {
1076 status
= smb1cli_readx_recv(subreq
, &received
, &rcvbuf
);
1078 status
= smb2cli_read_recv(subreq
, state
, &rcvbuf
, &received
);
1081 * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
1084 if (NT_STATUS_EQUAL(status
, STATUS_BUFFER_OVERFLOW
)) {
1086 * STATUS_BUFFER_OVERFLOW means that there's
1087 * more data to read when the named pipe is used
1088 * in message mode (which is the case here).
1090 * But we hide this from the caller.
1092 status
= NT_STATUS_OK
;
1094 if (!NT_STATUS_IS_OK(status
)) {
1095 TALLOC_FREE(subreq
);
1096 tstream_smbXcli_np_readv_disconnect_now(req
, EPIPE
, __location__
);
1100 if (received
> cli_nps
->max_data
) {
1101 TALLOC_FREE(subreq
);
1102 tstream_smbXcli_np_readv_disconnect_now(req
, EIO
, __location__
);
1106 if (received
== 0) {
1107 TALLOC_FREE(subreq
);
1108 tstream_smbXcli_np_readv_disconnect_now(req
, EPIPE
, __location__
);
1112 cli_nps
->read
.ofs
= 0;
1113 cli_nps
->read
.left
= received
;
1114 cli_nps
->read
.buf
= talloc_array(cli_nps
, uint8_t, received
);
1115 if (cli_nps
->read
.buf
== NULL
) {
1116 TALLOC_FREE(subreq
);
1117 tevent_req_oom(req
);
1120 memcpy(cli_nps
->read
.buf
, rcvbuf
, received
);
1121 TALLOC_FREE(subreq
);
1123 tstream_smbXcli_np_readv_read_next(req
);
1126 static void tstream_smbXcli_np_readv_disconnect_done(struct tevent_req
*subreq
);
1128 static void tstream_smbXcli_np_readv_error(struct tevent_req
*req
);
1130 static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req
*req
,
1132 const char *location
)
1134 struct tstream_smbXcli_np_readv_state
*state
=
1135 tevent_req_data(req
,
1136 struct tstream_smbXcli_np_readv_state
);
1137 struct tstream_smbXcli_np
*cli_nps
=
1138 tstream_context_data(state
->stream
,
1139 struct tstream_smbXcli_np
);
1140 struct tevent_req
*subreq
;
1142 state
->error
.val
= error
;
1143 state
->error
.location
= location
;
1145 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
1146 /* return the original error */
1147 tstream_smbXcli_np_readv_error(req
);
1151 subreq
= tstream_smbXcli_np_disconnect_send(state
, state
->ev
,
1153 if (subreq
== NULL
) {
1154 /* return the original error */
1155 tstream_smbXcli_np_readv_error(req
);
1158 tevent_req_set_callback(subreq
,
1159 tstream_smbXcli_np_readv_disconnect_done
,
1163 static void tstream_smbXcli_np_readv_disconnect_done(struct tevent_req
*subreq
)
1165 struct tevent_req
*req
=
1166 tevent_req_callback_data(subreq
, struct tevent_req
);
1169 tstream_smbXcli_np_disconnect_recv(subreq
, &error
);
1170 TALLOC_FREE(subreq
);
1172 tstream_smbXcli_np_readv_error(req
);
1175 static void tstream_smbXcli_np_readv_error_trigger(struct tevent_context
*ctx
,
1176 struct tevent_immediate
*im
,
1177 void *private_data
);
1179 static void tstream_smbXcli_np_readv_error(struct tevent_req
*req
)
1181 struct tstream_smbXcli_np_readv_state
*state
=
1182 tevent_req_data(req
,
1183 struct tstream_smbXcli_np_readv_state
);
1184 struct tstream_smbXcli_np
*cli_nps
=
1185 tstream_context_data(state
->stream
,
1186 struct tstream_smbXcli_np
);
1188 if (cli_nps
->trans
.write_req
== NULL
) {
1189 /* return the original error */
1190 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
1194 if (state
->trans
.im
== NULL
) {
1195 /* return the original error */
1196 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
1200 tevent_schedule_immediate(state
->trans
.im
, state
->ev
,
1201 tstream_smbXcli_np_readv_error_trigger
, req
);
1203 /* return the original error for writev */
1204 _tevent_req_error(cli_nps
->trans
.write_req
,
1205 state
->error
.val
, state
->error
.location
);
1208 static void tstream_smbXcli_np_readv_error_trigger(struct tevent_context
*ctx
,
1209 struct tevent_immediate
*im
,
1212 struct tevent_req
*req
=
1213 talloc_get_type_abort(private_data
,
1215 struct tstream_smbXcli_np_readv_state
*state
=
1216 tevent_req_data(req
,
1217 struct tstream_smbXcli_np_readv_state
);
1219 /* return the original error */
1220 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
1223 static int tstream_smbXcli_np_readv_recv(struct tevent_req
*req
,
1226 struct tstream_smbXcli_np_readv_state
*state
=
1227 tevent_req_data(req
, struct tstream_smbXcli_np_readv_state
);
1230 ret
= tsocket_simple_int_recv(req
, perrno
);
1235 tevent_req_received(req
);
1239 struct tstream_smbXcli_np_disconnect_state
{
1240 struct tstream_context
*stream
;
1241 struct tevent_req
*subreq
;
1244 static void tstream_smbXcli_np_disconnect_done(struct tevent_req
*subreq
);
1245 static void tstream_smbXcli_np_disconnect_cleanup(struct tevent_req
*req
,
1246 enum tevent_req_state req_state
);
1248 static struct tevent_req
*tstream_smbXcli_np_disconnect_send(TALLOC_CTX
*mem_ctx
,
1249 struct tevent_context
*ev
,
1250 struct tstream_context
*stream
)
1252 struct tstream_smbXcli_np
*cli_nps
= tstream_context_data(stream
,
1253 struct tstream_smbXcli_np
);
1254 struct tevent_req
*req
;
1255 struct tstream_smbXcli_np_disconnect_state
*state
;
1256 struct tevent_req
*subreq
;
1258 req
= tevent_req_create(mem_ctx
, &state
,
1259 struct tstream_smbXcli_np_disconnect_state
);
1264 state
->stream
= stream
;
1266 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
1267 tevent_req_error(req
, ENOTCONN
);
1268 return tevent_req_post(req
, ev
);
1271 if (cli_nps
->is_smb1
) {
1272 subreq
= smb1cli_close_send(state
, ev
, cli_nps
->conn
,
1277 cli_nps
->fnum
, UINT32_MAX
);
1279 subreq
= smb2cli_close_send(state
, ev
, cli_nps
->conn
,
1284 cli_nps
->fid_persistent
,
1285 cli_nps
->fid_volatile
);
1287 if (tevent_req_nomem(subreq
, req
)) {
1288 return tevent_req_post(req
, ev
);
1290 tevent_req_set_callback(subreq
, tstream_smbXcli_np_disconnect_done
, req
);
1291 state
->subreq
= subreq
;
1293 tevent_req_set_cleanup_fn(req
, tstream_smbXcli_np_disconnect_cleanup
);
1296 * Make sure we don't send any requests anymore.
1298 cli_nps
->conn
= NULL
;
1303 static void tstream_smbXcli_np_disconnect_done(struct tevent_req
*subreq
)
1305 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
1307 struct tstream_smbXcli_np_disconnect_state
*state
=
1308 tevent_req_data(req
, struct tstream_smbXcli_np_disconnect_state
);
1309 struct tstream_smbXcli_np
*cli_nps
=
1310 tstream_context_data(state
->stream
, struct tstream_smbXcli_np
);
1313 state
->subreq
= NULL
;
1315 if (cli_nps
->is_smb1
) {
1316 status
= smb1cli_close_recv(subreq
);
1318 status
= smb2cli_close_recv(subreq
);
1320 TALLOC_FREE(subreq
);
1321 if (!NT_STATUS_IS_OK(status
)) {
1322 tevent_req_error(req
, EPIPE
);
1326 cli_nps
->conn
= NULL
;
1327 cli_nps
->session
= NULL
;
1328 cli_nps
->tcon
= NULL
;
1330 tevent_req_done(req
);
1333 static void tstream_smbXcli_np_disconnect_free(struct tevent_req
*subreq
);
1335 static void tstream_smbXcli_np_disconnect_cleanup(struct tevent_req
*req
,
1336 enum tevent_req_state req_state
)
1338 struct tstream_smbXcli_np_disconnect_state
*state
=
1339 tevent_req_data(req
, struct tstream_smbXcli_np_disconnect_state
);
1340 struct tstream_smbXcli_np
*cli_nps
= NULL
;
1342 if (state
->subreq
== NULL
) {
1346 cli_nps
= tstream_context_data(state
->stream
, struct tstream_smbXcli_np
);
1348 if (cli_nps
->tcon
== NULL
) {
1353 * We're no longer interested in the result
1354 * any more, but need to make sure that the close
1355 * request arrives at the server if the smb connection,
1356 * session and tcon are still alive.
1358 * We move the low level request to the tcon,
1359 * which means that it stays as long as the tcon
1362 talloc_steal(cli_nps
->tcon
, state
->subreq
);
1363 tevent_req_set_callback(state
->subreq
,
1364 tstream_smbXcli_np_disconnect_free
,
1366 state
->subreq
= NULL
;
1368 cli_nps
->conn
= NULL
;
1369 cli_nps
->session
= NULL
;
1370 cli_nps
->tcon
= NULL
;
1373 static void tstream_smbXcli_np_disconnect_free(struct tevent_req
*subreq
)
1375 TALLOC_FREE(subreq
);
1378 static int tstream_smbXcli_np_disconnect_recv(struct tevent_req
*req
,
1383 ret
= tsocket_simple_int_recv(req
, perrno
);
1385 tevent_req_received(req
);
1389 static const struct tstream_context_ops tstream_smbXcli_np_ops
= {
1390 .name
= "smbXcli_np",
1392 .pending_bytes
= tstream_smbXcli_np_pending_bytes
,
1394 .readv_send
= tstream_smbXcli_np_readv_send
,
1395 .readv_recv
= tstream_smbXcli_np_readv_recv
,
1397 .writev_send
= tstream_smbXcli_np_writev_send
,
1398 .writev_recv
= tstream_smbXcli_np_writev_recv
,
1400 .disconnect_send
= tstream_smbXcli_np_disconnect_send
,
1401 .disconnect_recv
= tstream_smbXcli_np_disconnect_recv
,