selftest: also run test base.createx_access against ad_dc
[Samba.git] / libcli / smb / tstream_smbXcli_np.c
bloba59db13321b193fe235aa89f39d3e3d0aa5821c7
1 /*
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/>.
20 #include "includes.h"
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 | \
37 SEC_FILE_READ_EA | \
38 SEC_FILE_WRITE_EA | \
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;
52 uint16_t pid;
53 unsigned int timeout;
55 const char *npipe;
56 bool is_smb1;
57 uint16_t fnum;
58 uint64_t fid_persistent;
59 uint64_t fid_volatile;
61 struct {
62 bool active;
63 struct tevent_req *read_req;
64 struct tevent_req *write_req;
65 uint16_t setup[2];
66 } trans;
68 struct {
69 off_t ofs;
70 size_t left;
71 uint8_t *buf;
72 } read, write;
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)
81 NTSTATUS status;
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)) {
99 return 0;
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
113 * never be called.
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,
121 cli_nps->timeout,
122 cli_nps->pid,
123 cli_nps->tcon,
124 cli_nps->session,
125 cli_nps->fnum, UINT32_MAX);
126 } else {
127 status = smb2cli_close(cli_nps->conn,
128 cli_nps->timeout,
129 cli_nps->session,
130 cli_nps->tcon,
131 0, /* flags */
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
143 return 0;
146 static int tstream_smbXcli_np_ref_destructor(struct tstream_smbXcli_np_ref *ref)
148 if (ref->cli_nps == NULL) {
149 return 0;
152 if (ref->cli_nps->conn == NULL) {
153 return 0;
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);
164 return 0;
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,
171 int *perrno);
173 struct tstream_smbXcli_np_open_state {
174 struct smbXcli_conn *conn;
175 struct smbXcli_session *session;
176 struct smbXcli_tcon *tcon;
177 uint16_t pid;
178 unsigned int timeout;
180 bool is_smb1;
181 uint16_t fnum;
182 uint64_t fid_persistent;
183 uint64_t fid_volatile;
184 const char *npipe;
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,
194 uint16_t pid,
195 unsigned int timeout,
196 const char *npipe)
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);
204 if (!req) {
205 return NULL;
207 state->conn = conn;
208 state->tcon = tcon;
209 state->session = session;
210 state->pid = pid;
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,
235 state->timeout,
236 state->pid,
237 state->tcon,
238 state->session,
239 smb1_npipe,
240 0, /* CreatFlags */
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 */
250 } else {
251 subreq = smb2cli_create_send(state, ev, state->conn,
252 state->timeout, state->session,
253 state->tcon,
254 npipe,
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,
260 FILE_OPEN,
261 0, /* create_options */
262 NULL); /* blobs */
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);
269 return 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);
278 NTSTATUS status;
280 if (state->is_smb1) {
281 status = smb1cli_ntcreatex_recv(subreq, &state->fnum);
282 } else {
283 status = smb2cli_create_recv(subreq,
284 &state->fid_persistent,
285 &state->fid_volatile,
286 NULL, NULL, NULL);
288 TALLOC_FREE(subreq);
289 if (!NT_STATUS_IS_OK(status)) {
290 tevent_req_nterror(req, status);
291 return;
294 tevent_req_done(req);
297 NTSTATUS _tstream_smbXcli_np_open_recv(struct tevent_req *req,
298 TALLOC_CTX *mem_ctx,
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;
306 NTSTATUS status;
308 if (tevent_req_is_nterror(req, &status)) {
309 tevent_req_received(req);
310 return status;
313 stream = tstream_context_create(mem_ctx,
314 &tstream_smbXcli_np_ops,
315 &cli_nps,
316 struct tstream_smbXcli_np,
317 location);
318 if (!stream) {
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);
376 *_stream = stream;
377 tevent_req_received(req);
378 return NT_STATUS_OK;
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)) {
387 errno = ENOTCONN;
388 return -1;
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);
400 if (!cli_nps) {
401 return false;
404 return true;
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;
426 return NT_STATUS_OK;
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;
437 return old_timeout;
440 struct tstream_smbXcli_np_writev_state {
441 struct tstream_context *stream;
442 struct tevent_context *ev;
444 struct iovec *vector;
445 size_t count;
447 int ret;
449 struct {
450 int val;
451 const char *location;
452 } error;
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;
463 return 0;
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,
472 size_t count)
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);
481 if (!req) {
482 return NULL;
484 state->stream = stream;
485 state->ev = ev;
486 state->ret = 0;
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);
510 return req;
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 =
519 tevent_req_data(req,
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;
525 size_t i;
526 size_t left = 0;
528 for (i=0; i < state->count; i++) {
529 left += state->vector[i].iov_len;
532 if (left == 0) {
533 TALLOC_FREE(cli_nps->write.buf);
534 tevent_req_done(req);
535 return;
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)) {
543 return;
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);
555 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) {
563 state->vector += 1;
564 state->count -= 1;
567 state->ret += len;
570 if (cli_nps->trans.active && state->count == 0) {
571 cli_nps->trans.active = false;
572 cli_nps->trans.write_req = req;
573 return;
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);
579 return;
582 if (cli_nps->is_smb1) {
583 subreq = smb1cli_writex_send(state, state->ev,
584 cli_nps->conn,
585 cli_nps->timeout,
586 cli_nps->pid,
587 cli_nps->tcon,
588 cli_nps->session,
589 cli_nps->fnum,
590 8, /* 8 means message mode. */
591 cli_nps->write.buf,
592 0, /* offset */
593 cli_nps->write.ofs); /* size */
594 } else {
595 subreq = smb2cli_write_send(state, state->ev,
596 cli_nps->conn,
597 cli_nps->timeout,
598 cli_nps->session,
599 cli_nps->tcon,
600 cli_nps->write.ofs, /* length */
601 0, /* offset */
602 cli_nps->fid_persistent,
603 cli_nps->fid_volatile,
604 0, /* remaining_bytes */
605 0, /* flags */
606 cli_nps->write.buf);
608 if (tevent_req_nomem(subreq, req)) {
609 return;
611 tevent_req_set_callback(subreq,
612 tstream_smbXcli_np_writev_write_done,
613 req);
616 static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req *req,
617 int error,
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);
629 uint32_t written;
630 NTSTATUS status;
632 if (cli_nps->is_smb1) {
633 status = smb1cli_writex_recv(subreq, &written, NULL);
634 } else {
635 status = smb2cli_write_recv(subreq, &written);
637 TALLOC_FREE(subreq);
638 if (!NT_STATUS_IS_OK(status)) {
639 tstream_smbXcli_np_writev_disconnect_now(req, EPIPE, __location__);
640 return;
643 if (written != cli_nps->write.ofs) {
644 tstream_smbXcli_np_writev_disconnect_now(req, EIO, __location__);
645 return;
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,
654 int error,
655 const char *location)
657 struct tstream_smbXcli_np_writev_state *state =
658 tevent_req_data(req,
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);
671 return;
674 subreq = tstream_smbXcli_np_disconnect_send(state, state->ev,
675 state->stream);
676 if (subreq == NULL) {
677 /* return the original error */
678 _tevent_req_error(req, state->error.val, state->error.location);
679 return;
681 tevent_req_set_callback(subreq,
682 tstream_smbXcli_np_writev_disconnect_done,
683 req);
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);
692 int error;
694 tstream_smbXcli_np_disconnect_recv(subreq, &error);
695 TALLOC_FREE(subreq);
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,
702 int *perrno)
704 struct tstream_smbXcli_np_writev_state *state =
705 tevent_req_data(req,
706 struct tstream_smbXcli_np_writev_state);
707 int ret;
709 ret = tsocket_simple_int_recv(req, perrno);
710 if (ret == 0) {
711 ret = state->ret;
714 tevent_req_received(req);
715 return ret;
718 struct tstream_smbXcli_np_readv_state {
719 struct tstream_context *stream;
720 struct tevent_context *ev;
722 struct iovec *vector;
723 size_t count;
725 int ret;
727 struct {
728 struct tevent_immediate *im;
729 } trans;
731 struct {
732 int val;
733 const char *location;
734 } error;
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;
745 return 0;
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,
754 size_t count)
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);
763 if (!req) {
764 return NULL;
766 state->stream = stream;
767 state->ev = ev;
768 state->ret = 0;
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);
792 return req;
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 =
800 tevent_req_data(req,
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);
816 base += 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) {
824 state->vector += 1;
825 state->count -= 1;
828 state->ret += len;
831 if (cli_nps->read.left == 0) {
832 TALLOC_FREE(cli_nps->read.buf);
835 if (state->count == 0) {
836 tevent_req_done(req);
837 return;
840 if (cli_nps->trans.active) {
841 cli_nps->trans.active = false;
842 cli_nps->trans.read_req = req;
843 return;
846 if (cli_nps->trans.write_req) {
847 cli_nps->trans.read_req = req;
848 tstream_smbXcli_np_readv_trans_start(req);
849 return;
852 if (cli_nps->is_smb1) {
853 subreq = smb1cli_readx_send(state, state->ev,
854 cli_nps->conn,
855 cli_nps->timeout,
856 cli_nps->pid,
857 cli_nps->tcon,
858 cli_nps->session,
859 cli_nps->fnum,
860 0, /* offset */
861 TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE);
862 } else {
863 subreq = smb2cli_read_send(state, state->ev,
864 cli_nps->conn,
865 cli_nps->timeout,
866 cli_nps->session,
867 cli_nps->tcon,
868 TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE, /* length */
869 0, /* offset */
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)) {
876 return;
878 tevent_req_set_callback(subreq,
879 tstream_smbXcli_np_readv_read_done,
880 req);
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 =
888 tevent_req_data(req,
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)) {
897 return;
900 if (cli_nps->is_smb1) {
901 subreq = smb1cli_trans_send(state, state->ev,
902 cli_nps->conn, SMBtrans,
903 0, 0, /* *_flags */
904 0, 0, /* *_flags2 */
905 cli_nps->timeout,
906 cli_nps->pid,
907 cli_nps->tcon,
908 cli_nps->session,
909 "\\PIPE\\",
910 0, 0, 0,
911 cli_nps->trans.setup, 2,
913 NULL, 0, 0,
914 cli_nps->write.buf,
915 cli_nps->write.ofs,
916 TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE);
917 } else {
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,
922 cli_nps->write.ofs);
924 subreq = smb2cli_ioctl_send(state, state->ev,
925 cli_nps->conn,
926 cli_nps->timeout,
927 cli_nps->session,
928 cli_nps->tcon,
929 cli_nps->fid_persistent,
930 cli_nps->fid_volatile,
931 FSCTL_NAMED_PIPE_READ_WRITE,
932 0, /* in_max_input_length */
933 &in_input_buffer,
934 /* in_max_output_length */
935 TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE,
936 &in_output_buffer,
937 SMB2_IOCTL_FLAG_IS_FSCTL);
939 if (tevent_req_nomem(subreq, req)) {
940 return;
942 tevent_req_set_callback(subreq,
943 tstream_smbXcli_np_readv_trans_done,
944 req);
947 static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req *req,
948 int error,
949 const char *location);
950 static void tstream_smbXcli_np_readv_trans_next(struct tevent_context *ctx,
951 struct tevent_immediate *im,
952 void *private_data);
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);
962 uint8_t *rcvbuf;
963 uint32_t received;
964 NTSTATUS status;
966 if (cli_nps->is_smb1) {
967 status = smb1cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
968 NULL, 0, NULL,
969 &rcvbuf, 0, &received);
970 } else {
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,
975 &out_input_buffer,
976 &out_output_buffer);
978 /* Note that rcvbuf is not a talloc pointer here */
979 rcvbuf = out_output_buffer.data;
980 received = out_output_buffer.length;
982 TALLOC_FREE(subreq);
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__);
995 return;
998 if (received > TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE) {
999 tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
1000 return;
1003 if (received == 0) {
1004 tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
1005 return;
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_nomem(cli_nps->read.buf, req);
1014 return;
1016 memcpy(cli_nps->read.buf, rcvbuf, received);
1018 if (cli_nps->trans.write_req == NULL) {
1019 tstream_smbXcli_np_readv_read_next(req);
1020 return;
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,
1031 void *private_data)
1033 struct tevent_req *req =
1034 talloc_get_type_abort(private_data,
1035 struct tevent_req);
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);
1048 uint8_t *rcvbuf;
1049 uint32_t received;
1050 NTSTATUS status;
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);
1059 } else {
1060 status = smb2cli_read_recv(subreq, state, &rcvbuf, &received);
1063 * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
1064 * child of that.
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__);
1079 return;
1082 if (received > TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE) {
1083 TALLOC_FREE(subreq);
1084 tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
1085 return;
1088 if (received == 0) {
1089 TALLOC_FREE(subreq);
1090 tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
1091 return;
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_nomem(cli_nps->read.buf, req);
1100 return;
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,
1113 int error,
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);
1130 return;
1133 subreq = tstream_smbXcli_np_disconnect_send(state, state->ev,
1134 state->stream);
1135 if (subreq == NULL) {
1136 /* return the original error */
1137 tstream_smbXcli_np_readv_error(req);
1138 return;
1140 tevent_req_set_callback(subreq,
1141 tstream_smbXcli_np_readv_disconnect_done,
1142 req);
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 int error;
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);
1173 return;
1176 if (state->trans.im == NULL) {
1177 /* return the original error */
1178 _tevent_req_error(req, state->error.val, state->error.location);
1179 return;
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,
1192 void *private_data)
1194 struct tevent_req *req =
1195 talloc_get_type_abort(private_data,
1196 struct tevent_req);
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,
1206 int *perrno)
1208 struct tstream_smbXcli_np_readv_state *state =
1209 tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
1210 int ret;
1212 ret = tsocket_simple_int_recv(req, perrno);
1213 if (ret == 0) {
1214 ret = state->ret;
1217 tevent_req_received(req);
1218 return ret;
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);
1242 if (req == NULL) {
1243 return NULL;
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,
1255 cli_nps->timeout,
1256 cli_nps->pid,
1257 cli_nps->tcon,
1258 cli_nps->session,
1259 cli_nps->fnum, UINT32_MAX);
1260 } else {
1261 subreq = smb2cli_close_send(state, ev, cli_nps->conn,
1262 cli_nps->timeout,
1263 cli_nps->session,
1264 cli_nps->tcon,
1265 0, /* flags */
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;
1282 return req;
1285 static void tstream_smbXcli_np_disconnect_done(struct tevent_req *subreq)
1287 struct tevent_req *req = tevent_req_callback_data(subreq,
1288 struct tevent_req);
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);
1293 NTSTATUS status;
1295 state->subreq = NULL;
1297 if (cli_nps->is_smb1) {
1298 status = smb1cli_close_recv(subreq);
1299 } else {
1300 status = smb2cli_close_recv(subreq);
1302 TALLOC_FREE(subreq);
1303 if (!NT_STATUS_IS_OK(status)) {
1304 tevent_req_error(req, EPIPE);
1305 return;
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) {
1325 return;
1328 cli_nps = tstream_context_data(state->stream, struct tstream_smbXcli_np);
1330 if (cli_nps->tcon == NULL) {
1331 return;
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
1342 * is available.
1344 talloc_steal(cli_nps->tcon, state->subreq);
1345 tevent_req_set_callback(state->subreq,
1346 tstream_smbXcli_np_disconnect_free,
1347 NULL);
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,
1361 int *perrno)
1363 int ret;
1365 ret = tsocket_simple_int_recv(req, perrno);
1367 tevent_req_received(req);
1368 return ret;
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,