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
;
33 * Windows uses 4280 (the max xmit/recv size negotiated on DCERPC).
34 * This is fits into the max_xmit negotiated at the SMB layer.
36 * On the sending side they may use SMBtranss if the request does not
37 * fit into a single SMBtrans call.
39 * Windows uses 1024 as max data size of a SMBtrans request and then
40 * possibly reads the rest of the DCERPC fragment (up to 3256 bytes)
43 * For now we just ask for the full 4280 bytes (max data size) in the SMBtrans
44 * request to get the whole fragment at once (like samba 3.5.x and below did.
46 * It is important that we use do SMBwriteX with the size of a full fragment,
47 * otherwise we may get NT_STATUS_PIPE_BUSY on the SMBtrans request
48 * from NT4 servers. (See bug #8195)
50 #define TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE 4280
52 #define TSTREAM_SMBXCLI_NP_DESIRED_ACCESS ( \
53 SEC_STD_READ_CONTROL | \
54 SEC_FILE_READ_DATA | \
55 SEC_FILE_WRITE_DATA | \
56 SEC_FILE_APPEND_DATA | \
59 SEC_FILE_READ_ATTRIBUTE | \
60 SEC_FILE_WRITE_ATTRIBUTE | \
63 struct tstream_smbXcli_np_ref
;
65 struct tstream_smbXcli_np
{
66 struct tstream_smbXcli_np_ref
*ref
;
67 struct smbXcli_conn
*conn
;
68 struct smbXcli_session
*session
;
69 struct smbXcli_tcon
*tcon
;
76 uint64_t fid_persistent
;
77 uint64_t fid_volatile
;
81 struct tevent_req
*read_req
;
82 struct tevent_req
*write_req
;
93 struct tstream_smbXcli_np_ref
{
94 struct tstream_smbXcli_np
*cli_nps
;
97 static int tstream_smbXcli_np_destructor(struct tstream_smbXcli_np
*cli_nps
)
101 if (cli_nps
->ref
!= NULL
) {
102 cli_nps
->ref
->cli_nps
= NULL
;
103 TALLOC_FREE(cli_nps
->ref
);
106 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
111 * TODO: do not use a sync call with a destructor!!!
113 * This only happens, if a caller does talloc_free(),
114 * while the everything was still ok.
116 * If we get an unexpected failure within a normal
117 * operation, we already do an async cli_close_send()/_recv().
119 * Once we've fixed all callers to call
120 * tstream_disconnect_send()/_recv(), this will
123 if (cli_nps
->is_smb1
) {
124 status
= smb1cli_close(cli_nps
->conn
,
129 cli_nps
->fnum
, UINT32_MAX
);
131 status
= smb2cli_close(cli_nps
->conn
,
136 cli_nps
->fid_persistent
,
137 cli_nps
->fid_volatile
);
139 if (!NT_STATUS_IS_OK(status
)) {
140 DEBUG(1, ("tstream_smbXcli_np_destructor: cli_close "
141 "failed on pipe %s. Error was %s\n",
142 cli_nps
->npipe
, nt_errstr(status
)));
145 * We can't do much on failure
150 static int tstream_smbXcli_np_ref_destructor(struct tstream_smbXcli_np_ref
*ref
)
152 if (ref
->cli_nps
== NULL
) {
156 ref
->cli_nps
->conn
= NULL
;
157 ref
->cli_nps
->session
= NULL
;
158 ref
->cli_nps
->tcon
= NULL
;
159 ref
->cli_nps
->ref
= NULL
;
164 struct tstream_smbXcli_np_open_state
{
165 struct smbXcli_conn
*conn
;
166 struct smbXcli_session
*session
;
167 struct smbXcli_tcon
*tcon
;
169 unsigned int timeout
;
173 uint64_t fid_persistent
;
174 uint64_t fid_volatile
;
178 static void tstream_smbXcli_np_open_done(struct tevent_req
*subreq
);
180 struct tevent_req
*tstream_smbXcli_np_open_send(TALLOC_CTX
*mem_ctx
,
181 struct tevent_context
*ev
,
182 struct smbXcli_conn
*conn
,
183 struct smbXcli_session
*session
,
184 struct smbXcli_tcon
*tcon
,
186 unsigned int timeout
,
189 struct tevent_req
*req
;
190 struct tstream_smbXcli_np_open_state
*state
;
191 struct tevent_req
*subreq
;
193 req
= tevent_req_create(mem_ctx
, &state
,
194 struct tstream_smbXcli_np_open_state
);
200 state
->session
= session
;
202 state
->timeout
= timeout
;
204 state
->npipe
= talloc_strdup(state
, npipe
);
205 if (tevent_req_nomem(state
->npipe
, req
)) {
206 return tevent_req_post(req
, ev
);
209 if (smbXcli_conn_protocol(conn
) < PROTOCOL_SMB2_02
) {
210 state
->is_smb1
= true;
213 if (state
->is_smb1
) {
214 const char *smb1_npipe
;
217 * Windows and newer Samba versions allow
218 * the pipe name without leading backslash,
219 * but we should better behave like windows clients
221 smb1_npipe
= talloc_asprintf(state
, "\\%s", state
->npipe
);
222 if (tevent_req_nomem(smb1_npipe
, req
)) {
223 return tevent_req_post(req
, ev
);
225 subreq
= smb1cli_ntcreatex_send(state
, ev
, state
->conn
,
232 0, /* RootDirectoryFid */
233 TSTREAM_SMBXCLI_NP_DESIRED_ACCESS
,
234 0, /* AllocationSize */
235 0, /* FileAttributes */
236 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
237 FILE_OPEN
, /* CreateDisposition */
238 0, /* CreateOptions */
239 2, /* NTCREATEX_IMPERSONATION_IMPERSONATION */
240 0); /* SecurityFlags */
242 subreq
= smb2cli_create_send(state
, ev
, state
->conn
,
243 state
->timeout
, state
->session
,
246 SMB2_OPLOCK_LEVEL_NONE
,
247 SMB2_IMPERSONATION_IMPERSONATION
,
248 TSTREAM_SMBXCLI_NP_DESIRED_ACCESS
,
249 0, /* file_attributes */
250 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
252 0, /* create_options */
255 if (tevent_req_nomem(subreq
, req
)) {
256 return tevent_req_post(req
, ev
);
258 tevent_req_set_callback(subreq
, tstream_smbXcli_np_open_done
, req
);
263 static void tstream_smbXcli_np_open_done(struct tevent_req
*subreq
)
265 struct tevent_req
*req
=
266 tevent_req_callback_data(subreq
, struct tevent_req
);
267 struct tstream_smbXcli_np_open_state
*state
=
268 tevent_req_data(req
, struct tstream_smbXcli_np_open_state
);
271 if (state
->is_smb1
) {
272 status
= smb1cli_ntcreatex_recv(subreq
, &state
->fnum
);
274 status
= smb2cli_create_recv(subreq
,
275 &state
->fid_persistent
,
276 &state
->fid_volatile
,
280 if (!NT_STATUS_IS_OK(status
)) {
281 tevent_req_nterror(req
, status
);
285 tevent_req_done(req
);
288 NTSTATUS
_tstream_smbXcli_np_open_recv(struct tevent_req
*req
,
290 struct tstream_context
**_stream
,
291 const char *location
)
293 struct tstream_smbXcli_np_open_state
*state
=
294 tevent_req_data(req
, struct tstream_smbXcli_np_open_state
);
295 struct tstream_context
*stream
;
296 struct tstream_smbXcli_np
*cli_nps
;
299 if (tevent_req_is_nterror(req
, &status
)) {
300 tevent_req_received(req
);
304 stream
= tstream_context_create(mem_ctx
,
305 &tstream_smbXcli_np_ops
,
307 struct tstream_smbXcli_np
,
310 tevent_req_received(req
);
311 return NT_STATUS_NO_MEMORY
;
313 ZERO_STRUCTP(cli_nps
);
315 cli_nps
->ref
= talloc_zero(state
->conn
, struct tstream_smbXcli_np_ref
);
316 if (cli_nps
->ref
== NULL
) {
317 TALLOC_FREE(cli_nps
);
318 tevent_req_received(req
);
319 return NT_STATUS_NO_MEMORY
;
321 cli_nps
->ref
->cli_nps
= cli_nps
;
322 cli_nps
->conn
= state
->conn
;
323 cli_nps
->session
= state
->session
;
324 cli_nps
->tcon
= state
->tcon
;
325 cli_nps
->pid
= state
->pid
;
326 cli_nps
->timeout
= state
->timeout
;
327 cli_nps
->npipe
= talloc_move(cli_nps
, &state
->npipe
);
328 cli_nps
->is_smb1
= state
->is_smb1
;
329 cli_nps
->fnum
= state
->fnum
;
330 cli_nps
->fid_persistent
= state
->fid_persistent
;
331 cli_nps
->fid_volatile
= state
->fid_volatile
;
333 talloc_set_destructor(cli_nps
, tstream_smbXcli_np_destructor
);
334 talloc_set_destructor(cli_nps
->ref
, tstream_smbXcli_np_ref_destructor
);
336 cli_nps
->trans
.active
= false;
337 cli_nps
->trans
.read_req
= NULL
;
338 cli_nps
->trans
.write_req
= NULL
;
339 SSVAL(cli_nps
->trans
.setup
+0, 0, TRANSACT_DCERPCCMD
);
340 SSVAL(cli_nps
->trans
.setup
+1, 0, cli_nps
->fnum
);
343 tevent_req_received(req
);
347 static ssize_t
tstream_smbXcli_np_pending_bytes(struct tstream_context
*stream
)
349 struct tstream_smbXcli_np
*cli_nps
= tstream_context_data(stream
,
350 struct tstream_smbXcli_np
);
352 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
357 return cli_nps
->read
.left
;
360 bool tstream_is_smbXcli_np(struct tstream_context
*stream
)
362 struct tstream_smbXcli_np
*cli_nps
=
363 talloc_get_type(_tstream_context_data(stream
),
364 struct tstream_smbXcli_np
);
373 NTSTATUS
tstream_smbXcli_np_use_trans(struct tstream_context
*stream
)
375 struct tstream_smbXcli_np
*cli_nps
= tstream_context_data(stream
,
376 struct tstream_smbXcli_np
);
378 if (cli_nps
->trans
.read_req
) {
379 return NT_STATUS_PIPE_BUSY
;
382 if (cli_nps
->trans
.write_req
) {
383 return NT_STATUS_PIPE_BUSY
;
386 if (cli_nps
->trans
.active
) {
387 return NT_STATUS_PIPE_BUSY
;
390 cli_nps
->trans
.active
= true;
395 unsigned int tstream_smbXcli_np_set_timeout(struct tstream_context
*stream
,
396 unsigned int timeout
)
398 struct tstream_smbXcli_np
*cli_nps
= tstream_context_data(stream
,
399 struct tstream_smbXcli_np
);
400 unsigned int old_timeout
= cli_nps
->timeout
;
402 cli_nps
->timeout
= timeout
;
406 struct tstream_smbXcli_np_writev_state
{
407 struct tstream_context
*stream
;
408 struct tevent_context
*ev
;
410 struct iovec
*vector
;
417 const char *location
;
421 static int tstream_smbXcli_np_writev_state_destructor(struct tstream_smbXcli_np_writev_state
*state
)
423 struct tstream_smbXcli_np
*cli_nps
=
424 tstream_context_data(state
->stream
,
425 struct tstream_smbXcli_np
);
427 cli_nps
->trans
.write_req
= NULL
;
432 static void tstream_smbXcli_np_writev_write_next(struct tevent_req
*req
);
434 static struct tevent_req
*tstream_smbXcli_np_writev_send(TALLOC_CTX
*mem_ctx
,
435 struct tevent_context
*ev
,
436 struct tstream_context
*stream
,
437 const struct iovec
*vector
,
440 struct tevent_req
*req
;
441 struct tstream_smbXcli_np_writev_state
*state
;
442 struct tstream_smbXcli_np
*cli_nps
= tstream_context_data(stream
,
443 struct tstream_smbXcli_np
);
445 req
= tevent_req_create(mem_ctx
, &state
,
446 struct tstream_smbXcli_np_writev_state
);
450 state
->stream
= stream
;
454 talloc_set_destructor(state
, tstream_smbXcli_np_writev_state_destructor
);
456 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
457 tevent_req_error(req
, ENOTCONN
);
458 return tevent_req_post(req
, ev
);
462 * we make a copy of the vector so we can change the structure
464 state
->vector
= talloc_array(state
, struct iovec
, count
);
465 if (tevent_req_nomem(state
->vector
, req
)) {
466 return tevent_req_post(req
, ev
);
468 memcpy(state
->vector
, vector
, sizeof(struct iovec
) * count
);
469 state
->count
= count
;
471 tstream_smbXcli_np_writev_write_next(req
);
472 if (!tevent_req_is_in_progress(req
)) {
473 return tevent_req_post(req
, ev
);
479 static void tstream_smbXcli_np_readv_trans_start(struct tevent_req
*req
);
480 static void tstream_smbXcli_np_writev_write_done(struct tevent_req
*subreq
);
482 static void tstream_smbXcli_np_writev_write_next(struct tevent_req
*req
)
484 struct tstream_smbXcli_np_writev_state
*state
=
486 struct tstream_smbXcli_np_writev_state
);
487 struct tstream_smbXcli_np
*cli_nps
=
488 tstream_context_data(state
->stream
,
489 struct tstream_smbXcli_np
);
490 struct tevent_req
*subreq
;
494 for (i
=0; i
< state
->count
; i
++) {
495 left
+= state
->vector
[i
].iov_len
;
499 TALLOC_FREE(cli_nps
->write
.buf
);
500 tevent_req_done(req
);
504 cli_nps
->write
.ofs
= 0;
505 cli_nps
->write
.left
= MIN(left
, TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE
);
506 cli_nps
->write
.buf
= talloc_realloc(cli_nps
, cli_nps
->write
.buf
,
507 uint8_t, cli_nps
->write
.left
);
508 if (tevent_req_nomem(cli_nps
->write
.buf
, req
)) {
513 * copy the pending buffer first
515 while (cli_nps
->write
.left
> 0 && state
->count
> 0) {
516 uint8_t *base
= (uint8_t *)state
->vector
[0].iov_base
;
517 size_t len
= MIN(cli_nps
->write
.left
, state
->vector
[0].iov_len
);
519 memcpy(cli_nps
->write
.buf
+ cli_nps
->write
.ofs
, base
, len
);
522 state
->vector
[0].iov_base
= base
;
523 state
->vector
[0].iov_len
-= len
;
525 cli_nps
->write
.ofs
+= len
;
526 cli_nps
->write
.left
-= len
;
528 if (state
->vector
[0].iov_len
== 0) {
536 if (cli_nps
->trans
.active
&& state
->count
== 0) {
537 cli_nps
->trans
.active
= false;
538 cli_nps
->trans
.write_req
= req
;
542 if (cli_nps
->trans
.read_req
&& state
->count
== 0) {
543 cli_nps
->trans
.write_req
= req
;
544 tstream_smbXcli_np_readv_trans_start(cli_nps
->trans
.read_req
);
548 if (cli_nps
->is_smb1
) {
549 subreq
= smb1cli_writex_send(state
, state
->ev
,
556 8, /* 8 means message mode. */
559 cli_nps
->write
.ofs
); /* size */
561 subreq
= smb2cli_write_send(state
, state
->ev
,
566 cli_nps
->write
.ofs
, /* length */
568 cli_nps
->fid_persistent
,
569 cli_nps
->fid_volatile
,
570 0, /* remaining_bytes */
574 if (tevent_req_nomem(subreq
, req
)) {
577 tevent_req_set_callback(subreq
,
578 tstream_smbXcli_np_writev_write_done
,
582 static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req
*req
,
584 const char *location
);
586 static void tstream_smbXcli_np_writev_write_done(struct tevent_req
*subreq
)
588 struct tevent_req
*req
=
589 tevent_req_callback_data(subreq
, struct tevent_req
);
590 struct tstream_smbXcli_np_writev_state
*state
=
591 tevent_req_data(req
, struct tstream_smbXcli_np_writev_state
);
592 struct tstream_smbXcli_np
*cli_nps
=
593 tstream_context_data(state
->stream
,
594 struct tstream_smbXcli_np
);
598 if (cli_nps
->is_smb1
) {
599 status
= smb1cli_writex_recv(subreq
, &written
, NULL
);
601 status
= smb2cli_write_recv(subreq
, &written
);
604 if (!NT_STATUS_IS_OK(status
)) {
605 tstream_smbXcli_np_writev_disconnect_now(req
, EIO
, __location__
);
609 if (written
!= cli_nps
->write
.ofs
) {
610 tstream_smbXcli_np_writev_disconnect_now(req
, EIO
, __location__
);
614 tstream_smbXcli_np_writev_write_next(req
);
617 static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req
*subreq
);
619 static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req
*req
,
621 const char *location
)
623 struct tstream_smbXcli_np_writev_state
*state
=
625 struct tstream_smbXcli_np_writev_state
);
626 struct tstream_smbXcli_np
*cli_nps
=
627 tstream_context_data(state
->stream
,
628 struct tstream_smbXcli_np
);
629 struct tevent_req
*subreq
;
631 state
->error
.val
= error
;
632 state
->error
.location
= location
;
634 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
635 /* return the original error */
636 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
640 if (cli_nps
->is_smb1
) {
641 subreq
= smb1cli_close_send(state
, state
->ev
,
647 cli_nps
->fnum
, UINT32_MAX
);
649 subreq
= smb2cli_close_send(state
, state
->ev
,
655 cli_nps
->fid_persistent
,
656 cli_nps
->fid_volatile
);
658 if (subreq
== NULL
) {
659 /* return the original error */
660 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
663 tevent_req_set_callback(subreq
,
664 tstream_smbXcli_np_writev_disconnect_done
,
668 static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req
*subreq
)
670 struct tevent_req
*req
=
671 tevent_req_callback_data(subreq
, struct tevent_req
);
672 struct tstream_smbXcli_np_writev_state
*state
=
673 tevent_req_data(req
, struct tstream_smbXcli_np_writev_state
);
674 struct tstream_smbXcli_np
*cli_nps
=
675 tstream_context_data(state
->stream
, struct tstream_smbXcli_np
);
677 if (cli_nps
->is_smb1
) {
678 smb1cli_close_recv(subreq
);
680 smb2cli_close_recv(subreq
);
684 cli_nps
->conn
= NULL
;
685 cli_nps
->tcon
= NULL
;
686 cli_nps
->session
= NULL
;
688 /* return the original error */
689 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
692 static int tstream_smbXcli_np_writev_recv(struct tevent_req
*req
,
695 struct tstream_smbXcli_np_writev_state
*state
=
697 struct tstream_smbXcli_np_writev_state
);
700 ret
= tsocket_simple_int_recv(req
, perrno
);
705 tevent_req_received(req
);
709 struct tstream_smbXcli_np_readv_state
{
710 struct tstream_context
*stream
;
711 struct tevent_context
*ev
;
713 struct iovec
*vector
;
719 struct tevent_immediate
*im
;
724 const char *location
;
728 static int tstream_smbXcli_np_readv_state_destructor(struct tstream_smbXcli_np_readv_state
*state
)
730 struct tstream_smbXcli_np
*cli_nps
=
731 tstream_context_data(state
->stream
,
732 struct tstream_smbXcli_np
);
734 cli_nps
->trans
.read_req
= NULL
;
739 static void tstream_smbXcli_np_readv_read_next(struct tevent_req
*req
);
741 static struct tevent_req
*tstream_smbXcli_np_readv_send(TALLOC_CTX
*mem_ctx
,
742 struct tevent_context
*ev
,
743 struct tstream_context
*stream
,
744 struct iovec
*vector
,
747 struct tevent_req
*req
;
748 struct tstream_smbXcli_np_readv_state
*state
;
749 struct tstream_smbXcli_np
*cli_nps
=
750 tstream_context_data(stream
, struct tstream_smbXcli_np
);
752 req
= tevent_req_create(mem_ctx
, &state
,
753 struct tstream_smbXcli_np_readv_state
);
757 state
->stream
= stream
;
761 talloc_set_destructor(state
, tstream_smbXcli_np_readv_state_destructor
);
763 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
764 tevent_req_error(req
, ENOTCONN
);
765 return tevent_req_post(req
, ev
);
769 * we make a copy of the vector so we can change the structure
771 state
->vector
= talloc_array(state
, struct iovec
, count
);
772 if (tevent_req_nomem(state
->vector
, req
)) {
773 return tevent_req_post(req
, ev
);
775 memcpy(state
->vector
, vector
, sizeof(struct iovec
) * count
);
776 state
->count
= count
;
778 tstream_smbXcli_np_readv_read_next(req
);
779 if (!tevent_req_is_in_progress(req
)) {
780 return tevent_req_post(req
, ev
);
786 static void tstream_smbXcli_np_readv_read_done(struct tevent_req
*subreq
);
788 static void tstream_smbXcli_np_readv_read_next(struct tevent_req
*req
)
790 struct tstream_smbXcli_np_readv_state
*state
=
792 struct tstream_smbXcli_np_readv_state
);
793 struct tstream_smbXcli_np
*cli_nps
=
794 tstream_context_data(state
->stream
,
795 struct tstream_smbXcli_np
);
796 struct tevent_req
*subreq
;
799 * copy the pending buffer first
801 while (cli_nps
->read
.left
> 0 && state
->count
> 0) {
802 uint8_t *base
= (uint8_t *)state
->vector
[0].iov_base
;
803 size_t len
= MIN(cli_nps
->read
.left
, state
->vector
[0].iov_len
);
805 memcpy(base
, cli_nps
->read
.buf
+ cli_nps
->read
.ofs
, len
);
808 state
->vector
[0].iov_base
= base
;
809 state
->vector
[0].iov_len
-= len
;
811 cli_nps
->read
.ofs
+= len
;
812 cli_nps
->read
.left
-= len
;
814 if (state
->vector
[0].iov_len
== 0) {
822 if (cli_nps
->read
.left
== 0) {
823 TALLOC_FREE(cli_nps
->read
.buf
);
826 if (state
->count
== 0) {
827 tevent_req_done(req
);
831 if (cli_nps
->trans
.active
) {
832 cli_nps
->trans
.active
= false;
833 cli_nps
->trans
.read_req
= req
;
837 if (cli_nps
->trans
.write_req
) {
838 cli_nps
->trans
.read_req
= req
;
839 tstream_smbXcli_np_readv_trans_start(req
);
843 if (cli_nps
->is_smb1
) {
844 subreq
= smb1cli_readx_send(state
, state
->ev
,
852 TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE
);
854 subreq
= smb2cli_read_send(state
, state
->ev
,
859 TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE
, /* length */
861 cli_nps
->fid_persistent
,
862 cli_nps
->fid_volatile
,
863 0, /* minimum_count */
864 0); /* remaining_bytes */
866 if (tevent_req_nomem(subreq
, req
)) {
869 tevent_req_set_callback(subreq
,
870 tstream_smbXcli_np_readv_read_done
,
874 static void tstream_smbXcli_np_readv_trans_done(struct tevent_req
*subreq
);
876 static void tstream_smbXcli_np_readv_trans_start(struct tevent_req
*req
)
878 struct tstream_smbXcli_np_readv_state
*state
=
880 struct tstream_smbXcli_np_readv_state
);
881 struct tstream_smbXcli_np
*cli_nps
=
882 tstream_context_data(state
->stream
,
883 struct tstream_smbXcli_np
);
884 struct tevent_req
*subreq
;
886 state
->trans
.im
= tevent_create_immediate(state
);
887 if (tevent_req_nomem(state
->trans
.im
, req
)) {
891 if (cli_nps
->is_smb1
) {
892 subreq
= smb1cli_trans_send(state
, state
->ev
,
893 cli_nps
->conn
, SMBtrans
,
902 cli_nps
->trans
.setup
, 2,
907 TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE
);
909 DATA_BLOB in_input_buffer
= data_blob_null
;
910 DATA_BLOB in_output_buffer
= data_blob_null
;
912 in_input_buffer
= data_blob_const(cli_nps
->write
.buf
,
915 subreq
= smb2cli_ioctl_send(state
, state
->ev
,
920 cli_nps
->fid_persistent
,
921 cli_nps
->fid_volatile
,
922 FSCTL_NAMED_PIPE_READ_WRITE
,
923 0, /* in_max_input_length */
925 /* in_max_output_length */
926 TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE
,
928 SMB2_IOCTL_FLAG_IS_FSCTL
);
930 if (tevent_req_nomem(subreq
, req
)) {
933 tevent_req_set_callback(subreq
,
934 tstream_smbXcli_np_readv_trans_done
,
938 static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req
*req
,
940 const char *location
);
941 static void tstream_smbXcli_np_readv_trans_next(struct tevent_context
*ctx
,
942 struct tevent_immediate
*im
,
945 static void tstream_smbXcli_np_readv_trans_done(struct tevent_req
*subreq
)
947 struct tevent_req
*req
=
948 tevent_req_callback_data(subreq
, struct tevent_req
);
949 struct tstream_smbXcli_np_readv_state
*state
=
950 tevent_req_data(req
, struct tstream_smbXcli_np_readv_state
);
951 struct tstream_smbXcli_np
*cli_nps
=
952 tstream_context_data(state
->stream
, struct tstream_smbXcli_np
);
957 if (cli_nps
->is_smb1
) {
958 status
= smb1cli_trans_recv(subreq
, state
, NULL
, NULL
, 0, NULL
,
960 &rcvbuf
, 0, &received
);
962 DATA_BLOB out_input_buffer
= data_blob_null
;
963 DATA_BLOB out_output_buffer
= data_blob_null
;
965 status
= smb2cli_ioctl_recv(subreq
, state
,
969 /* Note that rcvbuf is not a talloc pointer here */
970 rcvbuf
= out_output_buffer
.data
;
971 received
= out_output_buffer
.length
;
974 if (NT_STATUS_EQUAL(status
, NT_STATUS_BUFFER_TOO_SMALL
)) {
975 status
= NT_STATUS_OK
;
977 if (!NT_STATUS_IS_OK(status
)) {
978 tstream_smbXcli_np_readv_disconnect_now(req
, EIO
, __location__
);
982 if (received
> TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE
) {
983 tstream_smbXcli_np_readv_disconnect_now(req
, EIO
, __location__
);
988 tstream_smbXcli_np_readv_disconnect_now(req
, EPIPE
, __location__
);
992 cli_nps
->read
.ofs
= 0;
993 cli_nps
->read
.left
= received
;
994 cli_nps
->read
.buf
= talloc_array(cli_nps
, uint8_t, received
);
995 if (cli_nps
->read
.buf
== NULL
) {
997 tevent_req_nomem(cli_nps
->read
.buf
, req
);
1000 memcpy(cli_nps
->read
.buf
, rcvbuf
, received
);
1002 if (cli_nps
->trans
.write_req
== NULL
) {
1003 tstream_smbXcli_np_readv_read_next(req
);
1007 tevent_schedule_immediate(state
->trans
.im
, state
->ev
,
1008 tstream_smbXcli_np_readv_trans_next
, req
);
1010 tevent_req_done(cli_nps
->trans
.write_req
);
1013 static void tstream_smbXcli_np_readv_trans_next(struct tevent_context
*ctx
,
1014 struct tevent_immediate
*im
,
1017 struct tevent_req
*req
=
1018 talloc_get_type_abort(private_data
,
1021 tstream_smbXcli_np_readv_read_next(req
);
1024 static void tstream_smbXcli_np_readv_read_done(struct tevent_req
*subreq
)
1026 struct tevent_req
*req
=
1027 tevent_req_callback_data(subreq
, struct tevent_req
);
1028 struct tstream_smbXcli_np_readv_state
*state
=
1029 tevent_req_data(req
, struct tstream_smbXcli_np_readv_state
);
1030 struct tstream_smbXcli_np
*cli_nps
=
1031 tstream_context_data(state
->stream
, struct tstream_smbXcli_np
);
1037 * We must free subreq in this function as there is
1038 * a timer event attached to it.
1041 if (cli_nps
->is_smb1
) {
1042 status
= smb1cli_readx_recv(subreq
, &received
, &rcvbuf
);
1044 status
= smb2cli_read_recv(subreq
, state
, &rcvbuf
, &received
);
1047 * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
1050 if (NT_STATUS_EQUAL(status
, NT_STATUS_BUFFER_TOO_SMALL
)) {
1052 * NT_STATUS_BUFFER_TOO_SMALL means that there's
1053 * more data to read when the named pipe is used
1054 * in message mode (which is the case here).
1056 * But we hide this from the caller.
1058 status
= NT_STATUS_OK
;
1060 if (!NT_STATUS_IS_OK(status
)) {
1061 TALLOC_FREE(subreq
);
1062 tstream_smbXcli_np_readv_disconnect_now(req
, EIO
, __location__
);
1066 if (received
> TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE
) {
1067 TALLOC_FREE(subreq
);
1068 tstream_smbXcli_np_readv_disconnect_now(req
, EIO
, __location__
);
1072 if (received
== 0) {
1073 TALLOC_FREE(subreq
);
1074 tstream_smbXcli_np_readv_disconnect_now(req
, EPIPE
, __location__
);
1078 cli_nps
->read
.ofs
= 0;
1079 cli_nps
->read
.left
= received
;
1080 cli_nps
->read
.buf
= talloc_array(cli_nps
, uint8_t, received
);
1081 if (cli_nps
->read
.buf
== NULL
) {
1082 TALLOC_FREE(subreq
);
1083 tevent_req_nomem(cli_nps
->read
.buf
, req
);
1086 memcpy(cli_nps
->read
.buf
, rcvbuf
, received
);
1087 TALLOC_FREE(subreq
);
1089 tstream_smbXcli_np_readv_read_next(req
);
1092 static void tstream_smbXcli_np_readv_disconnect_done(struct tevent_req
*subreq
);
1094 static void tstream_smbXcli_np_readv_error(struct tevent_req
*req
);
1096 static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req
*req
,
1098 const char *location
)
1100 struct tstream_smbXcli_np_readv_state
*state
=
1101 tevent_req_data(req
,
1102 struct tstream_smbXcli_np_readv_state
);
1103 struct tstream_smbXcli_np
*cli_nps
=
1104 tstream_context_data(state
->stream
,
1105 struct tstream_smbXcli_np
);
1106 struct tevent_req
*subreq
;
1108 state
->error
.val
= error
;
1109 state
->error
.location
= location
;
1111 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
1112 /* return the original error */
1113 tstream_smbXcli_np_readv_error(req
);
1117 if (cli_nps
->is_smb1
) {
1118 subreq
= smb1cli_close_send(state
, state
->ev
,
1124 cli_nps
->fnum
, UINT32_MAX
);
1126 subreq
= smb2cli_close_send(state
, state
->ev
,
1132 cli_nps
->fid_persistent
,
1133 cli_nps
->fid_volatile
);
1135 if (subreq
== NULL
) {
1136 /* return the original error */
1137 tstream_smbXcli_np_readv_error(req
);
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
);
1149 struct tstream_smbXcli_np_readv_state
*state
=
1150 tevent_req_data(req
, struct tstream_smbXcli_np_readv_state
);
1151 struct tstream_smbXcli_np
*cli_nps
=
1152 tstream_context_data(state
->stream
, struct tstream_smbXcli_np
);
1154 if (cli_nps
->is_smb1
) {
1155 smb1cli_close_recv(subreq
);
1157 smb2cli_close_recv(subreq
);
1159 TALLOC_FREE(subreq
);
1161 cli_nps
->conn
= NULL
;
1162 cli_nps
->session
= NULL
;
1163 cli_nps
->tcon
= NULL
;
1165 tstream_smbXcli_np_readv_error(req
);
1168 static void tstream_smbXcli_np_readv_error_trigger(struct tevent_context
*ctx
,
1169 struct tevent_immediate
*im
,
1170 void *private_data
);
1172 static void tstream_smbXcli_np_readv_error(struct tevent_req
*req
)
1174 struct tstream_smbXcli_np_readv_state
*state
=
1175 tevent_req_data(req
,
1176 struct tstream_smbXcli_np_readv_state
);
1177 struct tstream_smbXcli_np
*cli_nps
=
1178 tstream_context_data(state
->stream
,
1179 struct tstream_smbXcli_np
);
1181 if (cli_nps
->trans
.write_req
== NULL
) {
1182 /* return the original error */
1183 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
1187 if (state
->trans
.im
== NULL
) {
1188 /* return the original error */
1189 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
1193 tevent_schedule_immediate(state
->trans
.im
, state
->ev
,
1194 tstream_smbXcli_np_readv_error_trigger
, req
);
1196 /* return the original error for writev */
1197 _tevent_req_error(cli_nps
->trans
.write_req
,
1198 state
->error
.val
, state
->error
.location
);
1201 static void tstream_smbXcli_np_readv_error_trigger(struct tevent_context
*ctx
,
1202 struct tevent_immediate
*im
,
1205 struct tevent_req
*req
=
1206 talloc_get_type_abort(private_data
,
1208 struct tstream_smbXcli_np_readv_state
*state
=
1209 tevent_req_data(req
,
1210 struct tstream_smbXcli_np_readv_state
);
1212 /* return the original error */
1213 _tevent_req_error(req
, state
->error
.val
, state
->error
.location
);
1216 static int tstream_smbXcli_np_readv_recv(struct tevent_req
*req
,
1219 struct tstream_smbXcli_np_readv_state
*state
=
1220 tevent_req_data(req
, struct tstream_smbXcli_np_readv_state
);
1223 ret
= tsocket_simple_int_recv(req
, perrno
);
1228 tevent_req_received(req
);
1232 struct tstream_smbXcli_np_disconnect_state
{
1233 struct tstream_context
*stream
;
1236 static void tstream_smbXcli_np_disconnect_done(struct tevent_req
*subreq
);
1238 static struct tevent_req
*tstream_smbXcli_np_disconnect_send(TALLOC_CTX
*mem_ctx
,
1239 struct tevent_context
*ev
,
1240 struct tstream_context
*stream
)
1242 struct tstream_smbXcli_np
*cli_nps
= tstream_context_data(stream
,
1243 struct tstream_smbXcli_np
);
1244 struct tevent_req
*req
;
1245 struct tstream_smbXcli_np_disconnect_state
*state
;
1246 struct tevent_req
*subreq
;
1248 req
= tevent_req_create(mem_ctx
, &state
,
1249 struct tstream_smbXcli_np_disconnect_state
);
1254 state
->stream
= stream
;
1256 if (!smbXcli_conn_is_connected(cli_nps
->conn
)) {
1257 tevent_req_error(req
, ENOTCONN
);
1258 return tevent_req_post(req
, ev
);
1261 if (cli_nps
->is_smb1
) {
1262 subreq
= smb1cli_close_send(state
, ev
, cli_nps
->conn
,
1267 cli_nps
->fnum
, UINT32_MAX
);
1269 subreq
= smb2cli_close_send(state
, ev
, cli_nps
->conn
,
1274 cli_nps
->fid_persistent
,
1275 cli_nps
->fid_volatile
);
1277 if (tevent_req_nomem(subreq
, req
)) {
1278 return tevent_req_post(req
, ev
);
1280 tevent_req_set_callback(subreq
, tstream_smbXcli_np_disconnect_done
, req
);
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 if (cli_nps
->is_smb1
) {
1296 status
= smb1cli_close_recv(subreq
);
1298 status
= smb2cli_close_recv(subreq
);
1300 TALLOC_FREE(subreq
);
1301 if (!NT_STATUS_IS_OK(status
)) {
1302 tevent_req_error(req
, EIO
);
1306 cli_nps
->conn
= NULL
;
1307 cli_nps
->session
= NULL
;
1308 cli_nps
->tcon
= NULL
;
1310 tevent_req_done(req
);
1313 static int tstream_smbXcli_np_disconnect_recv(struct tevent_req
*req
,
1318 ret
= tsocket_simple_int_recv(req
, perrno
);
1320 tevent_req_received(req
);
1324 static const struct tstream_context_ops tstream_smbXcli_np_ops
= {
1325 .name
= "smbXcli_np",
1327 .pending_bytes
= tstream_smbXcli_np_pending_bytes
,
1329 .readv_send
= tstream_smbXcli_np_readv_send
,
1330 .readv_recv
= tstream_smbXcli_np_readv_recv
,
1332 .writev_send
= tstream_smbXcli_np_writev_send
,
1333 .writev_recv
= tstream_smbXcli_np_writev_recv
,
1335 .disconnect_send
= tstream_smbXcli_np_disconnect_send
,
1336 .disconnect_recv
= tstream_smbXcli_np_disconnect_recv
,