smbd: Fix cached dos attributes
[Samba.git] / libcli / smb / tstream_smbXcli_np.c
blob024830040801d1f05c5a27241df51aa0a11c3feb
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;
60 uint32_t max_data;
62 struct {
63 bool active;
64 struct tevent_req *read_req;
65 struct tevent_req *write_req;
66 uint16_t setup[2];
67 } trans;
69 struct {
70 off_t ofs;
71 size_t left;
72 uint8_t *buf;
73 } read, write;
76 struct tstream_smbXcli_np_ref {
77 struct tstream_smbXcli_np *cli_nps;
80 static int tstream_smbXcli_np_destructor(struct tstream_smbXcli_np *cli_nps)
82 NTSTATUS status;
84 if (cli_nps->conn_ref != NULL) {
85 cli_nps->conn_ref->cli_nps = NULL;
86 TALLOC_FREE(cli_nps->conn_ref);
89 if (cli_nps->session_ref != NULL) {
90 cli_nps->session_ref->cli_nps = NULL;
91 TALLOC_FREE(cli_nps->session_ref);
94 if (cli_nps->tcon_ref != NULL) {
95 cli_nps->tcon_ref->cli_nps = NULL;
96 TALLOC_FREE(cli_nps->tcon_ref);
99 if (!smbXcli_conn_is_connected(cli_nps->conn)) {
100 return 0;
104 * TODO: do not use a sync call with a destructor!!!
106 * This only happens, if a caller does talloc_free(),
107 * while the everything was still ok.
109 * If we get an unexpected failure within a normal
110 * operation, we already do an async cli_close_send()/_recv().
112 * Once we've fixed all callers to call
113 * tstream_disconnect_send()/_recv(), this will
114 * never be called.
116 * We use a maximum timeout of 1 second == 1000 msec.
118 cli_nps->timeout = MIN(cli_nps->timeout, 1000);
120 if (cli_nps->is_smb1) {
121 status = smb1cli_close(cli_nps->conn,
122 cli_nps->timeout,
123 cli_nps->pid,
124 cli_nps->tcon,
125 cli_nps->session,
126 cli_nps->fnum, UINT32_MAX);
127 } else {
128 status = smb2cli_close(cli_nps->conn,
129 cli_nps->timeout,
130 cli_nps->session,
131 cli_nps->tcon,
132 0, /* flags */
133 cli_nps->fid_persistent,
134 cli_nps->fid_volatile);
136 if (!NT_STATUS_IS_OK(status)) {
137 DEBUG(1, ("tstream_smbXcli_np_destructor: cli_close "
138 "failed on pipe %s. Error was %s\n",
139 cli_nps->npipe, nt_errstr(status)));
142 * We can't do much on failure
144 return 0;
147 static int tstream_smbXcli_np_ref_destructor(struct tstream_smbXcli_np_ref *ref)
149 if (ref->cli_nps == NULL) {
150 return 0;
153 if (ref->cli_nps->conn == NULL) {
154 return 0;
157 ref->cli_nps->conn = NULL;
158 ref->cli_nps->session = NULL;
159 ref->cli_nps->tcon = NULL;
161 TALLOC_FREE(ref->cli_nps->conn_ref);
162 TALLOC_FREE(ref->cli_nps->session_ref);
163 TALLOC_FREE(ref->cli_nps->tcon_ref);
165 return 0;
168 static struct tevent_req *tstream_smbXcli_np_disconnect_send(TALLOC_CTX *mem_ctx,
169 struct tevent_context *ev,
170 struct tstream_context *stream);
171 static int tstream_smbXcli_np_disconnect_recv(struct tevent_req *req,
172 int *perrno);
174 struct tstream_smbXcli_np_open_state {
175 struct smbXcli_conn *conn;
176 struct smbXcli_session *session;
177 struct smbXcli_tcon *tcon;
178 uint16_t pid;
179 unsigned int timeout;
181 bool is_smb1;
182 uint16_t fnum;
183 uint64_t fid_persistent;
184 uint64_t fid_volatile;
185 const char *npipe;
188 static void tstream_smbXcli_np_open_done(struct tevent_req *subreq);
190 struct tevent_req *tstream_smbXcli_np_open_send(TALLOC_CTX *mem_ctx,
191 struct tevent_context *ev,
192 struct smbXcli_conn *conn,
193 struct smbXcli_session *session,
194 struct smbXcli_tcon *tcon,
195 uint16_t pid,
196 unsigned int timeout,
197 const char *npipe)
199 struct tevent_req *req;
200 struct tstream_smbXcli_np_open_state *state;
201 struct tevent_req *subreq;
203 req = tevent_req_create(mem_ctx, &state,
204 struct tstream_smbXcli_np_open_state);
205 if (!req) {
206 return NULL;
208 state->conn = conn;
209 state->tcon = tcon;
210 state->session = session;
211 state->pid = pid;
212 state->timeout = timeout;
214 state->npipe = talloc_strdup(state, npipe);
215 if (tevent_req_nomem(state->npipe, req)) {
216 return tevent_req_post(req, ev);
219 if (smbXcli_conn_protocol(conn) < PROTOCOL_SMB2_02) {
220 state->is_smb1 = true;
223 if (state->is_smb1) {
224 const char *smb1_npipe;
227 * Windows and newer Samba versions allow
228 * the pipe name without leading backslash,
229 * but we should better behave like windows clients
231 smb1_npipe = talloc_asprintf(state, "\\%s", state->npipe);
232 if (tevent_req_nomem(smb1_npipe, req)) {
233 return tevent_req_post(req, ev);
235 subreq = smb1cli_ntcreatex_send(state, ev, state->conn,
236 state->timeout,
237 state->pid,
238 state->tcon,
239 state->session,
240 smb1_npipe,
241 0, /* CreatFlags */
242 0, /* RootDirectoryFid */
243 TSTREAM_SMBXCLI_NP_DESIRED_ACCESS,
244 0, /* AllocationSize */
245 0, /* FileAttributes */
246 FILE_SHARE_READ|FILE_SHARE_WRITE,
247 FILE_OPEN, /* CreateDisposition */
248 0, /* CreateOptions */
249 2, /* NTCREATEX_IMPERSONATION_IMPERSONATION */
250 0); /* SecurityFlags */
251 } else {
252 subreq = smb2cli_create_send(state, ev, state->conn,
253 state->timeout, state->session,
254 state->tcon,
255 npipe,
256 SMB2_OPLOCK_LEVEL_NONE,
257 SMB2_IMPERSONATION_IMPERSONATION,
258 TSTREAM_SMBXCLI_NP_DESIRED_ACCESS,
259 0, /* file_attributes */
260 FILE_SHARE_READ|FILE_SHARE_WRITE,
261 FILE_OPEN,
262 0, /* create_options */
263 NULL); /* blobs */
265 if (tevent_req_nomem(subreq, req)) {
266 return tevent_req_post(req, ev);
268 tevent_req_set_callback(subreq, tstream_smbXcli_np_open_done, req);
270 return req;
273 static void tstream_smbXcli_np_open_done(struct tevent_req *subreq)
275 struct tevent_req *req =
276 tevent_req_callback_data(subreq, struct tevent_req);
277 struct tstream_smbXcli_np_open_state *state =
278 tevent_req_data(req, struct tstream_smbXcli_np_open_state);
279 NTSTATUS status;
281 if (state->is_smb1) {
282 status = smb1cli_ntcreatex_recv(subreq, &state->fnum);
283 } else {
284 status = smb2cli_create_recv(
285 subreq,
286 &state->fid_persistent,
287 &state->fid_volatile,
288 NULL,
289 NULL,
290 NULL,
291 NULL);
293 TALLOC_FREE(subreq);
294 if (!NT_STATUS_IS_OK(status)) {
295 tevent_req_nterror(req, status);
296 return;
299 tevent_req_done(req);
302 NTSTATUS _tstream_smbXcli_np_open_recv(struct tevent_req *req,
303 TALLOC_CTX *mem_ctx,
304 struct tstream_context **_stream,
305 const char *location)
307 struct tstream_smbXcli_np_open_state *state =
308 tevent_req_data(req, struct tstream_smbXcli_np_open_state);
309 struct tstream_context *stream;
310 struct tstream_smbXcli_np *cli_nps;
311 NTSTATUS status;
313 if (tevent_req_is_nterror(req, &status)) {
314 tevent_req_received(req);
315 return status;
318 stream = tstream_context_create(mem_ctx,
319 &tstream_smbXcli_np_ops,
320 &cli_nps,
321 struct tstream_smbXcli_np,
322 location);
323 if (!stream) {
324 tevent_req_received(req);
325 return NT_STATUS_NO_MEMORY;
327 ZERO_STRUCTP(cli_nps);
329 cli_nps->conn_ref = talloc_zero(state->conn,
330 struct tstream_smbXcli_np_ref);
331 if (cli_nps->conn_ref == NULL) {
332 TALLOC_FREE(cli_nps);
333 tevent_req_received(req);
334 return NT_STATUS_NO_MEMORY;
336 cli_nps->conn_ref->cli_nps = cli_nps;
338 cli_nps->session_ref = talloc_zero(state->session,
339 struct tstream_smbXcli_np_ref);
340 if (cli_nps->session_ref == NULL) {
341 TALLOC_FREE(cli_nps);
342 tevent_req_received(req);
343 return NT_STATUS_NO_MEMORY;
345 cli_nps->session_ref->cli_nps = cli_nps;
347 cli_nps->tcon_ref = talloc_zero(state->tcon,
348 struct tstream_smbXcli_np_ref);
349 if (cli_nps->tcon_ref == NULL) {
350 TALLOC_FREE(cli_nps);
351 tevent_req_received(req);
352 return NT_STATUS_NO_MEMORY;
354 cli_nps->tcon_ref->cli_nps = cli_nps;
356 cli_nps->conn = state->conn;
357 cli_nps->session = state->session;
358 cli_nps->tcon = state->tcon;
359 cli_nps->pid = state->pid;
360 cli_nps->timeout = state->timeout;
361 cli_nps->npipe = talloc_move(cli_nps, &state->npipe);
362 cli_nps->is_smb1 = state->is_smb1;
363 cli_nps->fnum = state->fnum;
364 cli_nps->fid_persistent = state->fid_persistent;
365 cli_nps->fid_volatile = state->fid_volatile;
366 cli_nps->max_data = TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE;
368 talloc_set_destructor(cli_nps, tstream_smbXcli_np_destructor);
369 talloc_set_destructor(cli_nps->conn_ref,
370 tstream_smbXcli_np_ref_destructor);
371 talloc_set_destructor(cli_nps->session_ref,
372 tstream_smbXcli_np_ref_destructor);
373 talloc_set_destructor(cli_nps->tcon_ref,
374 tstream_smbXcli_np_ref_destructor);
376 cli_nps->trans.active = false;
377 cli_nps->trans.read_req = NULL;
378 cli_nps->trans.write_req = NULL;
379 SSVAL(cli_nps->trans.setup+0, 0, TRANSACT_DCERPCCMD);
380 SSVAL(cli_nps->trans.setup+1, 0, cli_nps->fnum);
382 *_stream = stream;
383 tevent_req_received(req);
384 return NT_STATUS_OK;
387 static ssize_t tstream_smbXcli_np_pending_bytes(struct tstream_context *stream)
389 struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
390 struct tstream_smbXcli_np);
392 if (!smbXcli_conn_is_connected(cli_nps->conn)) {
393 errno = ENOTCONN;
394 return -1;
397 return cli_nps->read.left;
400 bool tstream_is_smbXcli_np(struct tstream_context *stream)
402 struct tstream_smbXcli_np *cli_nps =
403 talloc_get_type(_tstream_context_data(stream),
404 struct tstream_smbXcli_np);
406 if (!cli_nps) {
407 return false;
410 return true;
413 NTSTATUS tstream_smbXcli_np_use_trans(struct tstream_context *stream)
415 struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
416 struct tstream_smbXcli_np);
418 if (cli_nps->trans.read_req) {
419 return NT_STATUS_PIPE_BUSY;
422 if (cli_nps->trans.write_req) {
423 return NT_STATUS_PIPE_BUSY;
426 if (cli_nps->trans.active) {
427 return NT_STATUS_PIPE_BUSY;
430 cli_nps->trans.active = true;
432 return NT_STATUS_OK;
435 void tstream_smbXcli_np_set_max_data(struct tstream_context *stream,
436 uint32_t max_data)
438 struct tstream_smbXcli_np *cli_nps = tstream_context_data(
439 stream, struct tstream_smbXcli_np);
441 cli_nps->max_data = max_data;
444 unsigned int tstream_smbXcli_np_set_timeout(struct tstream_context *stream,
445 unsigned int timeout)
447 struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
448 struct tstream_smbXcli_np);
449 unsigned int old_timeout = cli_nps->timeout;
451 cli_nps->timeout = timeout;
452 return old_timeout;
455 struct tstream_smbXcli_np_writev_state {
456 struct tstream_context *stream;
457 struct tevent_context *ev;
459 struct iovec *vector;
460 size_t count;
462 int ret;
464 struct {
465 int val;
466 const char *location;
467 } error;
470 static int tstream_smbXcli_np_writev_state_destructor(struct tstream_smbXcli_np_writev_state *state)
472 struct tstream_smbXcli_np *cli_nps =
473 tstream_context_data(state->stream,
474 struct tstream_smbXcli_np);
476 cli_nps->trans.write_req = NULL;
478 return 0;
481 static void tstream_smbXcli_np_writev_write_next(struct tevent_req *req);
483 static struct tevent_req *tstream_smbXcli_np_writev_send(TALLOC_CTX *mem_ctx,
484 struct tevent_context *ev,
485 struct tstream_context *stream,
486 const struct iovec *vector,
487 size_t count)
489 struct tevent_req *req;
490 struct tstream_smbXcli_np_writev_state *state;
491 struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
492 struct tstream_smbXcli_np);
494 req = tevent_req_create(mem_ctx, &state,
495 struct tstream_smbXcli_np_writev_state);
496 if (!req) {
497 return NULL;
499 state->stream = stream;
500 state->ev = ev;
501 state->ret = 0;
503 talloc_set_destructor(state, tstream_smbXcli_np_writev_state_destructor);
505 if (!smbXcli_conn_is_connected(cli_nps->conn)) {
506 tevent_req_error(req, ENOTCONN);
507 return tevent_req_post(req, ev);
511 * we make a copy of the vector so we can change the structure
513 state->vector = talloc_array(state, struct iovec, count);
514 if (tevent_req_nomem(state->vector, req)) {
515 return tevent_req_post(req, ev);
517 memcpy(state->vector, vector, sizeof(struct iovec) * count);
518 state->count = count;
520 tstream_smbXcli_np_writev_write_next(req);
521 if (!tevent_req_is_in_progress(req)) {
522 return tevent_req_post(req, ev);
525 return req;
528 static void tstream_smbXcli_np_readv_trans_start(struct tevent_req *req);
529 static void tstream_smbXcli_np_writev_write_done(struct tevent_req *subreq);
531 static void tstream_smbXcli_np_writev_write_next(struct tevent_req *req)
533 struct tstream_smbXcli_np_writev_state *state =
534 tevent_req_data(req,
535 struct tstream_smbXcli_np_writev_state);
536 struct tstream_smbXcli_np *cli_nps =
537 tstream_context_data(state->stream,
538 struct tstream_smbXcli_np);
539 struct tevent_req *subreq;
540 size_t i;
541 size_t left = 0;
543 for (i=0; i < state->count; i++) {
544 left += state->vector[i].iov_len;
547 if (left == 0) {
548 TALLOC_FREE(cli_nps->write.buf);
549 tevent_req_done(req);
550 return;
553 cli_nps->write.ofs = 0;
554 cli_nps->write.left = MIN(left, cli_nps->max_data);
555 cli_nps->write.buf = talloc_realloc(cli_nps, cli_nps->write.buf,
556 uint8_t, cli_nps->write.left);
557 if (tevent_req_nomem(cli_nps->write.buf, req)) {
558 return;
562 * copy the pending buffer first
564 while (cli_nps->write.left > 0 && state->count > 0) {
565 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
566 size_t len = MIN(cli_nps->write.left, state->vector[0].iov_len);
568 memcpy(cli_nps->write.buf + cli_nps->write.ofs, base, len);
570 base += len;
571 state->vector[0].iov_base = base;
572 state->vector[0].iov_len -= len;
574 cli_nps->write.ofs += len;
575 cli_nps->write.left -= len;
577 if (state->vector[0].iov_len == 0) {
578 state->vector += 1;
579 state->count -= 1;
582 state->ret += len;
585 if (cli_nps->trans.active && state->count == 0) {
586 cli_nps->trans.active = false;
587 cli_nps->trans.write_req = req;
588 return;
591 if (cli_nps->trans.read_req && state->count == 0) {
592 cli_nps->trans.write_req = req;
593 tstream_smbXcli_np_readv_trans_start(cli_nps->trans.read_req);
594 return;
597 if (cli_nps->is_smb1) {
598 subreq = smb1cli_writex_send(state, state->ev,
599 cli_nps->conn,
600 cli_nps->timeout,
601 cli_nps->pid,
602 cli_nps->tcon,
603 cli_nps->session,
604 cli_nps->fnum,
605 8, /* 8 means message mode. */
606 cli_nps->write.buf,
607 0, /* offset */
608 cli_nps->write.ofs); /* size */
609 } else {
610 subreq = smb2cli_write_send(state, state->ev,
611 cli_nps->conn,
612 cli_nps->timeout,
613 cli_nps->session,
614 cli_nps->tcon,
615 cli_nps->write.ofs, /* length */
616 0, /* offset */
617 cli_nps->fid_persistent,
618 cli_nps->fid_volatile,
619 0, /* remaining_bytes */
620 0, /* flags */
621 cli_nps->write.buf);
623 if (tevent_req_nomem(subreq, req)) {
624 return;
626 tevent_req_set_callback(subreq,
627 tstream_smbXcli_np_writev_write_done,
628 req);
631 static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req *req,
632 int error,
633 const char *location);
635 static void tstream_smbXcli_np_writev_write_done(struct tevent_req *subreq)
637 struct tevent_req *req =
638 tevent_req_callback_data(subreq, struct tevent_req);
639 struct tstream_smbXcli_np_writev_state *state =
640 tevent_req_data(req, struct tstream_smbXcli_np_writev_state);
641 struct tstream_smbXcli_np *cli_nps =
642 tstream_context_data(state->stream,
643 struct tstream_smbXcli_np);
644 uint32_t written;
645 NTSTATUS status;
647 if (cli_nps->is_smb1) {
648 status = smb1cli_writex_recv(subreq, &written, NULL);
649 } else {
650 status = smb2cli_write_recv(subreq, &written);
652 TALLOC_FREE(subreq);
653 if (!NT_STATUS_IS_OK(status)) {
654 tstream_smbXcli_np_writev_disconnect_now(req, EPIPE, __location__);
655 return;
658 if (written != cli_nps->write.ofs) {
659 tstream_smbXcli_np_writev_disconnect_now(req, EIO, __location__);
660 return;
663 tstream_smbXcli_np_writev_write_next(req);
666 static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req *subreq);
668 static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req *req,
669 int error,
670 const char *location)
672 struct tstream_smbXcli_np_writev_state *state =
673 tevent_req_data(req,
674 struct tstream_smbXcli_np_writev_state);
675 struct tstream_smbXcli_np *cli_nps =
676 tstream_context_data(state->stream,
677 struct tstream_smbXcli_np);
678 struct tevent_req *subreq;
680 state->error.val = error;
681 state->error.location = location;
683 if (!smbXcli_conn_is_connected(cli_nps->conn)) {
684 /* return the original error */
685 _tevent_req_error(req, state->error.val, state->error.location);
686 return;
689 subreq = tstream_smbXcli_np_disconnect_send(state, state->ev,
690 state->stream);
691 if (subreq == NULL) {
692 /* return the original error */
693 _tevent_req_error(req, state->error.val, state->error.location);
694 return;
696 tevent_req_set_callback(subreq,
697 tstream_smbXcli_np_writev_disconnect_done,
698 req);
701 static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req *subreq)
703 struct tevent_req *req =
704 tevent_req_callback_data(subreq, struct tevent_req);
705 struct tstream_smbXcli_np_writev_state *state =
706 tevent_req_data(req, struct tstream_smbXcli_np_writev_state);
707 int error;
709 tstream_smbXcli_np_disconnect_recv(subreq, &error);
710 TALLOC_FREE(subreq);
712 /* return the original error */
713 _tevent_req_error(req, state->error.val, state->error.location);
716 static int tstream_smbXcli_np_writev_recv(struct tevent_req *req,
717 int *perrno)
719 struct tstream_smbXcli_np_writev_state *state =
720 tevent_req_data(req,
721 struct tstream_smbXcli_np_writev_state);
722 int ret;
724 ret = tsocket_simple_int_recv(req, perrno);
725 if (ret == 0) {
726 ret = state->ret;
729 tevent_req_received(req);
730 return ret;
733 struct tstream_smbXcli_np_readv_state {
734 struct tstream_context *stream;
735 struct tevent_context *ev;
737 struct iovec *vector;
738 size_t count;
740 int ret;
742 struct {
743 struct tevent_immediate *im;
744 } trans;
746 struct {
747 int val;
748 const char *location;
749 } error;
752 static int tstream_smbXcli_np_readv_state_destructor(struct tstream_smbXcli_np_readv_state *state)
754 struct tstream_smbXcli_np *cli_nps =
755 tstream_context_data(state->stream,
756 struct tstream_smbXcli_np);
758 cli_nps->trans.read_req = NULL;
760 return 0;
763 static void tstream_smbXcli_np_readv_read_next(struct tevent_req *req);
765 static struct tevent_req *tstream_smbXcli_np_readv_send(TALLOC_CTX *mem_ctx,
766 struct tevent_context *ev,
767 struct tstream_context *stream,
768 struct iovec *vector,
769 size_t count)
771 struct tevent_req *req;
772 struct tstream_smbXcli_np_readv_state *state;
773 struct tstream_smbXcli_np *cli_nps =
774 tstream_context_data(stream, struct tstream_smbXcli_np);
776 req = tevent_req_create(mem_ctx, &state,
777 struct tstream_smbXcli_np_readv_state);
778 if (!req) {
779 return NULL;
781 state->stream = stream;
782 state->ev = ev;
783 state->ret = 0;
785 talloc_set_destructor(state, tstream_smbXcli_np_readv_state_destructor);
787 if (!smbXcli_conn_is_connected(cli_nps->conn)) {
788 tevent_req_error(req, ENOTCONN);
789 return tevent_req_post(req, ev);
793 * we make a copy of the vector so we can change the structure
795 state->vector = talloc_array(state, struct iovec, count);
796 if (tevent_req_nomem(state->vector, req)) {
797 return tevent_req_post(req, ev);
799 memcpy(state->vector, vector, sizeof(struct iovec) * count);
800 state->count = count;
802 tstream_smbXcli_np_readv_read_next(req);
803 if (!tevent_req_is_in_progress(req)) {
804 return tevent_req_post(req, ev);
807 return req;
810 static void tstream_smbXcli_np_readv_read_done(struct tevent_req *subreq);
812 static void tstream_smbXcli_np_readv_read_next(struct tevent_req *req)
814 struct tstream_smbXcli_np_readv_state *state =
815 tevent_req_data(req,
816 struct tstream_smbXcli_np_readv_state);
817 struct tstream_smbXcli_np *cli_nps =
818 tstream_context_data(state->stream,
819 struct tstream_smbXcli_np);
820 struct tevent_req *subreq;
823 * copy the pending buffer first
825 while (cli_nps->read.left > 0 && state->count > 0) {
826 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
827 size_t len = MIN(cli_nps->read.left, state->vector[0].iov_len);
829 memcpy(base, cli_nps->read.buf + cli_nps->read.ofs, len);
831 base += len;
832 state->vector[0].iov_base = base;
833 state->vector[0].iov_len -= len;
835 cli_nps->read.ofs += len;
836 cli_nps->read.left -= len;
838 if (state->vector[0].iov_len == 0) {
839 state->vector += 1;
840 state->count -= 1;
843 state->ret += len;
846 if (cli_nps->read.left == 0) {
847 TALLOC_FREE(cli_nps->read.buf);
850 if (state->count == 0) {
851 tevent_req_done(req);
852 return;
855 if (cli_nps->trans.active) {
856 cli_nps->trans.active = false;
857 cli_nps->trans.read_req = req;
858 return;
861 if (cli_nps->trans.write_req) {
862 cli_nps->trans.read_req = req;
863 tstream_smbXcli_np_readv_trans_start(req);
864 return;
867 if (cli_nps->is_smb1) {
868 subreq = smb1cli_readx_send(state, state->ev,
869 cli_nps->conn,
870 cli_nps->timeout,
871 cli_nps->pid,
872 cli_nps->tcon,
873 cli_nps->session,
874 cli_nps->fnum,
875 0, /* offset */
876 cli_nps->max_data);
877 } else {
878 subreq = smb2cli_read_send(state, state->ev,
879 cli_nps->conn,
880 cli_nps->timeout,
881 cli_nps->session,
882 cli_nps->tcon,
883 cli_nps->max_data, /* length */
884 0, /* offset */
885 cli_nps->fid_persistent,
886 cli_nps->fid_volatile,
887 0, /* minimum_count */
888 0); /* remaining_bytes */
890 if (tevent_req_nomem(subreq, req)) {
891 return;
893 tevent_req_set_callback(subreq,
894 tstream_smbXcli_np_readv_read_done,
895 req);
898 static void tstream_smbXcli_np_readv_trans_done(struct tevent_req *subreq);
900 static void tstream_smbXcli_np_readv_trans_start(struct tevent_req *req)
902 struct tstream_smbXcli_np_readv_state *state =
903 tevent_req_data(req,
904 struct tstream_smbXcli_np_readv_state);
905 struct tstream_smbXcli_np *cli_nps =
906 tstream_context_data(state->stream,
907 struct tstream_smbXcli_np);
908 struct tevent_req *subreq;
910 state->trans.im = tevent_create_immediate(state);
911 if (tevent_req_nomem(state->trans.im, req)) {
912 return;
915 if (cli_nps->is_smb1) {
916 subreq = smb1cli_trans_send(state, state->ev,
917 cli_nps->conn, SMBtrans,
918 0, 0, /* *_flags */
919 0, 0, /* *_flags2 */
920 cli_nps->timeout,
921 cli_nps->pid,
922 cli_nps->tcon,
923 cli_nps->session,
924 "\\PIPE\\",
925 0, 0, 0,
926 cli_nps->trans.setup, 2,
928 NULL, 0, 0,
929 cli_nps->write.buf,
930 cli_nps->write.ofs,
931 cli_nps->max_data);
932 } else {
933 DATA_BLOB in_input_buffer = data_blob_null;
934 DATA_BLOB in_output_buffer = data_blob_null;
936 in_input_buffer = data_blob_const(cli_nps->write.buf,
937 cli_nps->write.ofs);
939 subreq = smb2cli_ioctl_send(state, state->ev,
940 cli_nps->conn,
941 cli_nps->timeout,
942 cli_nps->session,
943 cli_nps->tcon,
944 cli_nps->fid_persistent,
945 cli_nps->fid_volatile,
946 FSCTL_NAMED_PIPE_READ_WRITE,
947 0, /* in_max_input_length */
948 &in_input_buffer,
949 /* in_max_output_length */
950 cli_nps->max_data,
951 &in_output_buffer,
952 SMB2_IOCTL_FLAG_IS_FSCTL);
954 if (tevent_req_nomem(subreq, req)) {
955 return;
957 tevent_req_set_callback(subreq,
958 tstream_smbXcli_np_readv_trans_done,
959 req);
962 static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req *req,
963 int error,
964 const char *location);
965 static void tstream_smbXcli_np_readv_trans_next(struct tevent_context *ctx,
966 struct tevent_immediate *im,
967 void *private_data);
969 static void tstream_smbXcli_np_readv_trans_done(struct tevent_req *subreq)
971 struct tevent_req *req =
972 tevent_req_callback_data(subreq, struct tevent_req);
973 struct tstream_smbXcli_np_readv_state *state =
974 tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
975 struct tstream_smbXcli_np *cli_nps =
976 tstream_context_data(state->stream, struct tstream_smbXcli_np);
977 uint8_t *rcvbuf;
978 uint32_t received;
979 NTSTATUS status;
981 if (cli_nps->is_smb1) {
982 status = smb1cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
983 NULL, 0, NULL,
984 &rcvbuf, 0, &received);
985 } else {
986 DATA_BLOB out_input_buffer = data_blob_null;
987 DATA_BLOB out_output_buffer = data_blob_null;
989 status = smb2cli_ioctl_recv(subreq, state,
990 &out_input_buffer,
991 &out_output_buffer);
993 /* Note that rcvbuf is not a talloc pointer here */
994 rcvbuf = out_output_buffer.data;
995 received = out_output_buffer.length;
997 TALLOC_FREE(subreq);
998 if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
1000 * STATUS_BUFFER_OVERFLOW means that there's
1001 * more data to read when the named pipe is used
1002 * in message mode (which is the case here).
1004 * But we hide this from the caller.
1006 status = NT_STATUS_OK;
1008 if (!NT_STATUS_IS_OK(status)) {
1009 tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
1010 return;
1013 if (received > cli_nps->max_data) {
1014 tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
1015 return;
1018 if (received == 0) {
1019 tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
1020 return;
1023 cli_nps->read.ofs = 0;
1024 cli_nps->read.left = received;
1025 cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received);
1026 if (cli_nps->read.buf == NULL) {
1027 TALLOC_FREE(subreq);
1028 tevent_req_oom(req);
1029 return;
1031 memcpy(cli_nps->read.buf, rcvbuf, received);
1033 if (cli_nps->trans.write_req == NULL) {
1034 tstream_smbXcli_np_readv_read_next(req);
1035 return;
1038 tevent_schedule_immediate(state->trans.im, state->ev,
1039 tstream_smbXcli_np_readv_trans_next, req);
1041 tevent_req_done(cli_nps->trans.write_req);
1044 static void tstream_smbXcli_np_readv_trans_next(struct tevent_context *ctx,
1045 struct tevent_immediate *im,
1046 void *private_data)
1048 struct tevent_req *req =
1049 talloc_get_type_abort(private_data,
1050 struct tevent_req);
1052 tstream_smbXcli_np_readv_read_next(req);
1055 static void tstream_smbXcli_np_readv_read_done(struct tevent_req *subreq)
1057 struct tevent_req *req =
1058 tevent_req_callback_data(subreq, struct tevent_req);
1059 struct tstream_smbXcli_np_readv_state *state =
1060 tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
1061 struct tstream_smbXcli_np *cli_nps =
1062 tstream_context_data(state->stream, struct tstream_smbXcli_np);
1063 uint8_t *rcvbuf;
1064 uint32_t received;
1065 NTSTATUS status;
1068 * We must free subreq in this function as there is
1069 * a timer event attached to it.
1072 if (cli_nps->is_smb1) {
1073 status = smb1cli_readx_recv(subreq, &received, &rcvbuf);
1074 } else {
1075 status = smb2cli_read_recv(subreq, state, &rcvbuf, &received);
1078 * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
1079 * child of that.
1081 if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
1083 * STATUS_BUFFER_OVERFLOW means that there's
1084 * more data to read when the named pipe is used
1085 * in message mode (which is the case here).
1087 * But we hide this from the caller.
1089 status = NT_STATUS_OK;
1091 if (!NT_STATUS_IS_OK(status)) {
1092 TALLOC_FREE(subreq);
1093 tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
1094 return;
1097 if (received > cli_nps->max_data) {
1098 TALLOC_FREE(subreq);
1099 tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
1100 return;
1103 if (received == 0) {
1104 TALLOC_FREE(subreq);
1105 tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
1106 return;
1109 cli_nps->read.ofs = 0;
1110 cli_nps->read.left = received;
1111 cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received);
1112 if (cli_nps->read.buf == NULL) {
1113 TALLOC_FREE(subreq);
1114 tevent_req_oom(req);
1115 return;
1117 memcpy(cli_nps->read.buf, rcvbuf, received);
1118 TALLOC_FREE(subreq);
1120 tstream_smbXcli_np_readv_read_next(req);
1123 static void tstream_smbXcli_np_readv_disconnect_done(struct tevent_req *subreq);
1125 static void tstream_smbXcli_np_readv_error(struct tevent_req *req);
1127 static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req *req,
1128 int error,
1129 const char *location)
1131 struct tstream_smbXcli_np_readv_state *state =
1132 tevent_req_data(req,
1133 struct tstream_smbXcli_np_readv_state);
1134 struct tstream_smbXcli_np *cli_nps =
1135 tstream_context_data(state->stream,
1136 struct tstream_smbXcli_np);
1137 struct tevent_req *subreq;
1139 state->error.val = error;
1140 state->error.location = location;
1142 if (!smbXcli_conn_is_connected(cli_nps->conn)) {
1143 /* return the original error */
1144 tstream_smbXcli_np_readv_error(req);
1145 return;
1148 subreq = tstream_smbXcli_np_disconnect_send(state, state->ev,
1149 state->stream);
1150 if (subreq == NULL) {
1151 /* return the original error */
1152 tstream_smbXcli_np_readv_error(req);
1153 return;
1155 tevent_req_set_callback(subreq,
1156 tstream_smbXcli_np_readv_disconnect_done,
1157 req);
1160 static void tstream_smbXcli_np_readv_disconnect_done(struct tevent_req *subreq)
1162 struct tevent_req *req =
1163 tevent_req_callback_data(subreq, struct tevent_req);
1164 int error;
1166 tstream_smbXcli_np_disconnect_recv(subreq, &error);
1167 TALLOC_FREE(subreq);
1169 tstream_smbXcli_np_readv_error(req);
1172 static void tstream_smbXcli_np_readv_error_trigger(struct tevent_context *ctx,
1173 struct tevent_immediate *im,
1174 void *private_data);
1176 static void tstream_smbXcli_np_readv_error(struct tevent_req *req)
1178 struct tstream_smbXcli_np_readv_state *state =
1179 tevent_req_data(req,
1180 struct tstream_smbXcli_np_readv_state);
1181 struct tstream_smbXcli_np *cli_nps =
1182 tstream_context_data(state->stream,
1183 struct tstream_smbXcli_np);
1185 if (cli_nps->trans.write_req == NULL) {
1186 /* return the original error */
1187 _tevent_req_error(req, state->error.val, state->error.location);
1188 return;
1191 if (state->trans.im == NULL) {
1192 /* return the original error */
1193 _tevent_req_error(req, state->error.val, state->error.location);
1194 return;
1197 tevent_schedule_immediate(state->trans.im, state->ev,
1198 tstream_smbXcli_np_readv_error_trigger, req);
1200 /* return the original error for writev */
1201 _tevent_req_error(cli_nps->trans.write_req,
1202 state->error.val, state->error.location);
1205 static void tstream_smbXcli_np_readv_error_trigger(struct tevent_context *ctx,
1206 struct tevent_immediate *im,
1207 void *private_data)
1209 struct tevent_req *req =
1210 talloc_get_type_abort(private_data,
1211 struct tevent_req);
1212 struct tstream_smbXcli_np_readv_state *state =
1213 tevent_req_data(req,
1214 struct tstream_smbXcli_np_readv_state);
1216 /* return the original error */
1217 _tevent_req_error(req, state->error.val, state->error.location);
1220 static int tstream_smbXcli_np_readv_recv(struct tevent_req *req,
1221 int *perrno)
1223 struct tstream_smbXcli_np_readv_state *state =
1224 tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
1225 int ret;
1227 ret = tsocket_simple_int_recv(req, perrno);
1228 if (ret == 0) {
1229 ret = state->ret;
1232 tevent_req_received(req);
1233 return ret;
1236 struct tstream_smbXcli_np_disconnect_state {
1237 struct tstream_context *stream;
1238 struct tevent_req *subreq;
1241 static void tstream_smbXcli_np_disconnect_done(struct tevent_req *subreq);
1242 static void tstream_smbXcli_np_disconnect_cleanup(struct tevent_req *req,
1243 enum tevent_req_state req_state);
1245 static struct tevent_req *tstream_smbXcli_np_disconnect_send(TALLOC_CTX *mem_ctx,
1246 struct tevent_context *ev,
1247 struct tstream_context *stream)
1249 struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
1250 struct tstream_smbXcli_np);
1251 struct tevent_req *req;
1252 struct tstream_smbXcli_np_disconnect_state *state;
1253 struct tevent_req *subreq;
1255 req = tevent_req_create(mem_ctx, &state,
1256 struct tstream_smbXcli_np_disconnect_state);
1257 if (req == NULL) {
1258 return NULL;
1261 state->stream = stream;
1263 if (!smbXcli_conn_is_connected(cli_nps->conn)) {
1264 tevent_req_error(req, ENOTCONN);
1265 return tevent_req_post(req, ev);
1268 if (cli_nps->is_smb1) {
1269 subreq = smb1cli_close_send(state, ev, cli_nps->conn,
1270 cli_nps->timeout,
1271 cli_nps->pid,
1272 cli_nps->tcon,
1273 cli_nps->session,
1274 cli_nps->fnum, UINT32_MAX);
1275 } else {
1276 subreq = smb2cli_close_send(state, ev, cli_nps->conn,
1277 cli_nps->timeout,
1278 cli_nps->session,
1279 cli_nps->tcon,
1280 0, /* flags */
1281 cli_nps->fid_persistent,
1282 cli_nps->fid_volatile);
1284 if (tevent_req_nomem(subreq, req)) {
1285 return tevent_req_post(req, ev);
1287 tevent_req_set_callback(subreq, tstream_smbXcli_np_disconnect_done, req);
1288 state->subreq = subreq;
1290 tevent_req_set_cleanup_fn(req, tstream_smbXcli_np_disconnect_cleanup);
1293 * Make sure we don't send any requests anymore.
1295 cli_nps->conn = NULL;
1297 return req;
1300 static void tstream_smbXcli_np_disconnect_done(struct tevent_req *subreq)
1302 struct tevent_req *req = tevent_req_callback_data(subreq,
1303 struct tevent_req);
1304 struct tstream_smbXcli_np_disconnect_state *state =
1305 tevent_req_data(req, struct tstream_smbXcli_np_disconnect_state);
1306 struct tstream_smbXcli_np *cli_nps =
1307 tstream_context_data(state->stream, struct tstream_smbXcli_np);
1308 NTSTATUS status;
1310 state->subreq = NULL;
1312 if (cli_nps->is_smb1) {
1313 status = smb1cli_close_recv(subreq);
1314 } else {
1315 status = smb2cli_close_recv(subreq);
1317 TALLOC_FREE(subreq);
1318 if (!NT_STATUS_IS_OK(status)) {
1319 tevent_req_error(req, EPIPE);
1320 return;
1323 cli_nps->conn = NULL;
1324 cli_nps->session = NULL;
1325 cli_nps->tcon = NULL;
1327 tevent_req_done(req);
1330 static void tstream_smbXcli_np_disconnect_free(struct tevent_req *subreq);
1332 static void tstream_smbXcli_np_disconnect_cleanup(struct tevent_req *req,
1333 enum tevent_req_state req_state)
1335 struct tstream_smbXcli_np_disconnect_state *state =
1336 tevent_req_data(req, struct tstream_smbXcli_np_disconnect_state);
1337 struct tstream_smbXcli_np *cli_nps = NULL;
1339 if (state->subreq == NULL) {
1340 return;
1343 cli_nps = tstream_context_data(state->stream, struct tstream_smbXcli_np);
1345 if (cli_nps->tcon == NULL) {
1346 return;
1350 * We're no longer interested in the result
1351 * any more, but need to make sure that the close
1352 * request arrives at the server if the smb connection,
1353 * session and tcon are still alive.
1355 * We move the low level request to the tcon,
1356 * which means that it stays as long as the tcon
1357 * is available.
1359 talloc_steal(cli_nps->tcon, state->subreq);
1360 tevent_req_set_callback(state->subreq,
1361 tstream_smbXcli_np_disconnect_free,
1362 NULL);
1363 state->subreq = NULL;
1365 cli_nps->conn = NULL;
1366 cli_nps->session = NULL;
1367 cli_nps->tcon = NULL;
1370 static void tstream_smbXcli_np_disconnect_free(struct tevent_req *subreq)
1372 TALLOC_FREE(subreq);
1375 static int tstream_smbXcli_np_disconnect_recv(struct tevent_req *req,
1376 int *perrno)
1378 int ret;
1380 ret = tsocket_simple_int_recv(req, perrno);
1382 tevent_req_received(req);
1383 return ret;
1386 static const struct tstream_context_ops tstream_smbXcli_np_ops = {
1387 .name = "smbXcli_np",
1389 .pending_bytes = tstream_smbXcli_np_pending_bytes,
1391 .readv_send = tstream_smbXcli_np_readv_send,
1392 .readv_recv = tstream_smbXcli_np_readv_recv,
1394 .writev_send = tstream_smbXcli_np_writev_send,
1395 .writev_recv = tstream_smbXcli_np_writev_recv,
1397 .disconnect_send = tstream_smbXcli_np_disconnect_send,
1398 .disconnect_recv = tstream_smbXcli_np_disconnect_recv,