smbd: Simplify filename_convert_dirfsp_nosymlink()
[samba4-gss.git] / libcli / smb / tstream_smbXcli_np.c
blobad92ba43b274e9577578435d2271e7b436081cfb
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"
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 | \
38 SEC_FILE_READ_EA | \
39 SEC_FILE_WRITE_EA | \
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;
53 uint16_t pid;
54 unsigned int timeout;
56 const char *npipe;
57 bool is_smb1;
58 uint16_t fnum;
59 uint64_t fid_persistent;
60 uint64_t fid_volatile;
61 uint32_t max_data;
63 struct {
64 bool active;
65 struct tevent_req *read_req;
66 struct tevent_req *write_req;
67 uint16_t setup[2];
68 } trans;
70 struct {
71 off_t ofs;
72 size_t left;
73 uint8_t *buf;
74 } read, write;
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)
83 NTSTATUS status;
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)) {
101 return 0;
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
115 * never be called.
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,
123 cli_nps->timeout,
124 cli_nps->pid,
125 cli_nps->tcon,
126 cli_nps->session,
127 cli_nps->fnum, UINT32_MAX);
128 } else {
129 status = smb2cli_close(cli_nps->conn,
130 cli_nps->timeout,
131 cli_nps->session,
132 cli_nps->tcon,
133 0, /* flags */
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
145 return 0;
148 static int tstream_smbXcli_np_ref_destructor(struct tstream_smbXcli_np_ref *ref)
150 if (ref->cli_nps == NULL) {
151 return 0;
154 if (ref->cli_nps->conn == NULL) {
155 return 0;
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);
166 return 0;
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,
173 int *perrno);
175 struct tstream_smbXcli_np_open_state {
176 struct smbXcli_conn *conn;
177 struct smbXcli_session *session;
178 struct smbXcli_tcon *tcon;
179 uint16_t pid;
180 unsigned int timeout;
182 bool is_smb1;
183 uint16_t fnum;
184 uint64_t fid_persistent;
185 uint64_t fid_volatile;
186 const char *npipe;
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,
196 uint16_t pid,
197 unsigned int timeout,
198 const char *npipe)
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);
206 if (!req) {
207 return NULL;
209 state->conn = conn;
210 state->tcon = tcon;
211 state->session = session;
212 state->pid = pid;
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,
237 state->timeout,
238 state->pid,
239 state->tcon,
240 state->session,
241 smb1_npipe,
242 0, /* CreatFlags */
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 */
252 } else {
253 subreq = smb2cli_create_send(state, ev, state->conn,
254 state->timeout, state->session,
255 state->tcon,
256 npipe,
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,
262 FILE_OPEN,
263 0, /* create_options */
264 NULL); /* blobs */
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);
271 return 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);
280 NTSTATUS status;
282 if (state->is_smb1) {
283 status = smb1cli_ntcreatex_recv(subreq, &state->fnum);
284 } else {
285 status = smb2cli_create_recv(
286 subreq,
287 &state->fid_persistent,
288 &state->fid_volatile,
289 NULL,
290 NULL,
291 NULL,
292 NULL);
294 TALLOC_FREE(subreq);
295 if (!NT_STATUS_IS_OK(status)) {
296 tevent_req_nterror(req, status);
297 return;
300 tevent_req_done(req);
303 NTSTATUS _tstream_smbXcli_np_open_recv(struct tevent_req *req,
304 TALLOC_CTX *mem_ctx,
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;
312 NTSTATUS status;
314 if (tevent_req_is_nterror(req, &status)) {
315 tevent_req_received(req);
316 return status;
319 stream = tstream_context_create(mem_ctx,
320 &tstream_smbXcli_np_ops,
321 &cli_nps,
322 struct tstream_smbXcli_np,
323 location);
324 if (!stream) {
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);
383 *_stream = stream;
384 tevent_req_received(req);
385 return NT_STATUS_OK;
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)) {
394 errno = ENOTCONN;
395 return -1;
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);
407 if (!cli_nps) {
408 return false;
411 return true;
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;
433 return NT_STATUS_OK;
436 void tstream_smbXcli_np_set_max_data(struct tstream_context *stream,
437 uint32_t max_data)
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;
453 return old_timeout;
456 struct tstream_smbXcli_np_writev_state {
457 struct tstream_context *stream;
458 struct tevent_context *ev;
460 struct iovec *vector;
461 size_t count;
463 int ret;
465 struct {
466 int val;
467 const char *location;
468 } error;
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;
479 return 0;
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,
488 size_t count)
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);
497 if (!req) {
498 return NULL;
500 state->stream = stream;
501 state->ev = ev;
502 state->ret = 0;
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);
526 return req;
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 =
535 tevent_req_data(req,
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;
541 ssize_t left;
543 left = iov_buflen(state->vector, state->count);
545 if (left < 0) {
546 tevent_req_error(req, EMSGSIZE);
547 return;
550 if (left == 0) {
551 TALLOC_FREE(cli_nps->write.buf);
552 tevent_req_done(req);
553 return;
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)) {
561 return;
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);
573 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) {
581 state->vector += 1;
582 state->count -= 1;
585 state->ret += len;
588 if (cli_nps->trans.active && state->count == 0) {
589 cli_nps->trans.active = false;
590 cli_nps->trans.write_req = req;
591 return;
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);
597 return;
600 if (cli_nps->is_smb1) {
601 subreq = smb1cli_writex_send(state, state->ev,
602 cli_nps->conn,
603 cli_nps->timeout,
604 cli_nps->pid,
605 cli_nps->tcon,
606 cli_nps->session,
607 cli_nps->fnum,
608 8, /* 8 means message mode. */
609 cli_nps->write.buf,
610 0, /* offset */
611 cli_nps->write.ofs); /* size */
612 } else {
613 subreq = smb2cli_write_send(state, state->ev,
614 cli_nps->conn,
615 cli_nps->timeout,
616 cli_nps->session,
617 cli_nps->tcon,
618 cli_nps->write.ofs, /* length */
619 0, /* offset */
620 cli_nps->fid_persistent,
621 cli_nps->fid_volatile,
622 0, /* remaining_bytes */
623 0, /* flags */
624 cli_nps->write.buf);
626 if (tevent_req_nomem(subreq, req)) {
627 return;
629 tevent_req_set_callback(subreq,
630 tstream_smbXcli_np_writev_write_done,
631 req);
634 static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req *req,
635 int error,
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);
647 uint32_t written;
648 NTSTATUS status;
650 if (cli_nps->is_smb1) {
651 status = smb1cli_writex_recv(subreq, &written, NULL);
652 } else {
653 status = smb2cli_write_recv(subreq, &written);
655 TALLOC_FREE(subreq);
656 if (!NT_STATUS_IS_OK(status)) {
657 tstream_smbXcli_np_writev_disconnect_now(req, EPIPE, __location__);
658 return;
661 if (written != cli_nps->write.ofs) {
662 tstream_smbXcli_np_writev_disconnect_now(req, EIO, __location__);
663 return;
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,
672 int error,
673 const char *location)
675 struct tstream_smbXcli_np_writev_state *state =
676 tevent_req_data(req,
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);
689 return;
692 subreq = tstream_smbXcli_np_disconnect_send(state, state->ev,
693 state->stream);
694 if (subreq == NULL) {
695 /* return the original error */
696 _tevent_req_error(req, state->error.val, state->error.location);
697 return;
699 tevent_req_set_callback(subreq,
700 tstream_smbXcli_np_writev_disconnect_done,
701 req);
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);
710 int error;
712 tstream_smbXcli_np_disconnect_recv(subreq, &error);
713 TALLOC_FREE(subreq);
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,
720 int *perrno)
722 struct tstream_smbXcli_np_writev_state *state =
723 tevent_req_data(req,
724 struct tstream_smbXcli_np_writev_state);
725 int ret;
727 ret = tsocket_simple_int_recv(req, perrno);
728 if (ret == 0) {
729 ret = state->ret;
732 tevent_req_received(req);
733 return ret;
736 struct tstream_smbXcli_np_readv_state {
737 struct tstream_context *stream;
738 struct tevent_context *ev;
740 struct iovec *vector;
741 size_t count;
743 int ret;
745 struct {
746 struct tevent_immediate *im;
747 } trans;
749 struct {
750 int val;
751 const char *location;
752 } error;
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;
763 return 0;
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,
772 size_t count)
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);
781 if (!req) {
782 return NULL;
784 state->stream = stream;
785 state->ev = ev;
786 state->ret = 0;
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);
810 return req;
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 =
818 tevent_req_data(req,
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);
834 base += 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) {
842 state->vector += 1;
843 state->count -= 1;
846 state->ret += len;
849 if (cli_nps->read.left == 0) {
850 TALLOC_FREE(cli_nps->read.buf);
853 if (state->count == 0) {
854 tevent_req_done(req);
855 return;
858 if (cli_nps->trans.active) {
859 cli_nps->trans.active = false;
860 cli_nps->trans.read_req = req;
861 return;
864 if (cli_nps->trans.write_req) {
865 cli_nps->trans.read_req = req;
866 tstream_smbXcli_np_readv_trans_start(req);
867 return;
870 if (cli_nps->is_smb1) {
871 subreq = smb1cli_readx_send(state, state->ev,
872 cli_nps->conn,
873 cli_nps->timeout,
874 cli_nps->pid,
875 cli_nps->tcon,
876 cli_nps->session,
877 cli_nps->fnum,
878 0, /* offset */
879 cli_nps->max_data);
880 } else {
881 subreq = smb2cli_read_send(state, state->ev,
882 cli_nps->conn,
883 cli_nps->timeout,
884 cli_nps->session,
885 cli_nps->tcon,
886 cli_nps->max_data, /* length */
887 0, /* offset */
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)) {
894 return;
896 tevent_req_set_callback(subreq,
897 tstream_smbXcli_np_readv_read_done,
898 req);
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 =
906 tevent_req_data(req,
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)) {
915 return;
918 if (cli_nps->is_smb1) {
919 subreq = smb1cli_trans_send(state, state->ev,
920 cli_nps->conn, SMBtrans,
921 0, 0, /* *_flags */
922 0, 0, /* *_flags2 */
923 cli_nps->timeout,
924 cli_nps->pid,
925 cli_nps->tcon,
926 cli_nps->session,
927 "\\PIPE\\",
928 0, 0, 0,
929 cli_nps->trans.setup, 2,
931 NULL, 0, 0,
932 cli_nps->write.buf,
933 cli_nps->write.ofs,
934 cli_nps->max_data);
935 } else {
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,
940 cli_nps->write.ofs);
942 subreq = smb2cli_ioctl_send(state, state->ev,
943 cli_nps->conn,
944 cli_nps->timeout,
945 cli_nps->session,
946 cli_nps->tcon,
947 cli_nps->fid_persistent,
948 cli_nps->fid_volatile,
949 FSCTL_NAMED_PIPE_READ_WRITE,
950 0, /* in_max_input_length */
951 &in_input_buffer,
952 /* in_max_output_length */
953 cli_nps->max_data,
954 &in_output_buffer,
955 SMB2_IOCTL_FLAG_IS_FSCTL);
957 if (tevent_req_nomem(subreq, req)) {
958 return;
960 tevent_req_set_callback(subreq,
961 tstream_smbXcli_np_readv_trans_done,
962 req);
965 static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req *req,
966 int error,
967 const char *location);
968 static void tstream_smbXcli_np_readv_trans_next(struct tevent_context *ctx,
969 struct tevent_immediate *im,
970 void *private_data);
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);
980 uint8_t *rcvbuf;
981 uint32_t received;
982 NTSTATUS status;
984 if (cli_nps->is_smb1) {
985 status = smb1cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
986 NULL, 0, NULL,
987 &rcvbuf, 0, &received);
988 } else {
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,
993 &out_input_buffer,
994 &out_output_buffer);
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__);
1013 return;
1016 if (received > cli_nps->max_data) {
1017 tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
1018 return;
1021 if (received == 0) {
1022 tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
1023 return;
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);
1032 return;
1034 memcpy(cli_nps->read.buf, rcvbuf, received);
1036 if (cli_nps->trans.write_req == NULL) {
1037 tstream_smbXcli_np_readv_read_next(req);
1038 return;
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,
1049 void *private_data)
1051 struct tevent_req *req =
1052 talloc_get_type_abort(private_data,
1053 struct tevent_req);
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);
1066 uint8_t *rcvbuf;
1067 uint32_t received;
1068 NTSTATUS status;
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);
1077 } else {
1078 status = smb2cli_read_recv(subreq, state, &rcvbuf, &received);
1081 * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
1082 * child of that.
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__);
1097 return;
1100 if (received > cli_nps->max_data) {
1101 TALLOC_FREE(subreq);
1102 tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
1103 return;
1106 if (received == 0) {
1107 TALLOC_FREE(subreq);
1108 tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
1109 return;
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);
1118 return;
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,
1131 int error,
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);
1148 return;
1151 subreq = tstream_smbXcli_np_disconnect_send(state, state->ev,
1152 state->stream);
1153 if (subreq == NULL) {
1154 /* return the original error */
1155 tstream_smbXcli_np_readv_error(req);
1156 return;
1158 tevent_req_set_callback(subreq,
1159 tstream_smbXcli_np_readv_disconnect_done,
1160 req);
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);
1167 int error;
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);
1191 return;
1194 if (state->trans.im == NULL) {
1195 /* return the original error */
1196 _tevent_req_error(req, state->error.val, state->error.location);
1197 return;
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,
1210 void *private_data)
1212 struct tevent_req *req =
1213 talloc_get_type_abort(private_data,
1214 struct tevent_req);
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,
1224 int *perrno)
1226 struct tstream_smbXcli_np_readv_state *state =
1227 tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
1228 int ret;
1230 ret = tsocket_simple_int_recv(req, perrno);
1231 if (ret == 0) {
1232 ret = state->ret;
1235 tevent_req_received(req);
1236 return ret;
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);
1260 if (req == NULL) {
1261 return NULL;
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,
1273 cli_nps->timeout,
1274 cli_nps->pid,
1275 cli_nps->tcon,
1276 cli_nps->session,
1277 cli_nps->fnum, UINT32_MAX);
1278 } else {
1279 subreq = smb2cli_close_send(state, ev, cli_nps->conn,
1280 cli_nps->timeout,
1281 cli_nps->session,
1282 cli_nps->tcon,
1283 0, /* flags */
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;
1300 return req;
1303 static void tstream_smbXcli_np_disconnect_done(struct tevent_req *subreq)
1305 struct tevent_req *req = tevent_req_callback_data(subreq,
1306 struct tevent_req);
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);
1311 NTSTATUS status;
1313 state->subreq = NULL;
1315 if (cli_nps->is_smb1) {
1316 status = smb1cli_close_recv(subreq);
1317 } else {
1318 status = smb2cli_close_recv(subreq);
1320 TALLOC_FREE(subreq);
1321 if (!NT_STATUS_IS_OK(status)) {
1322 tevent_req_error(req, EPIPE);
1323 return;
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) {
1343 return;
1346 cli_nps = tstream_context_data(state->stream, struct tstream_smbXcli_np);
1348 if (cli_nps->tcon == NULL) {
1349 return;
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
1360 * is available.
1362 talloc_steal(cli_nps->tcon, state->subreq);
1363 tevent_req_set_callback(state->subreq,
1364 tstream_smbXcli_np_disconnect_free,
1365 NULL);
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,
1379 int *perrno)
1381 int ret;
1383 ret = tsocket_simple_int_recv(req, perrno);
1385 tevent_req_received(req);
1386 return ret;
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,