s4-auth: Support password history correctly, including allowing NTLM logins using...
[Samba/wip.git] / libcli / smb / tstream_smbXcli_np.c
blobc32fd6fb14411d0dc8d7e38cd3d4136c21434ddd
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 if (cli_nps->is_smb1) {
116 status = smb1cli_close(cli_nps->conn,
117 cli_nps->timeout,
118 cli_nps->pid,
119 cli_nps->tcon,
120 cli_nps->session,
121 cli_nps->fnum, UINT32_MAX);
122 } else {
123 status = smb2cli_close(cli_nps->conn,
124 cli_nps->timeout,
125 cli_nps->session,
126 cli_nps->tcon,
127 0, /* flags */
128 cli_nps->fid_persistent,
129 cli_nps->fid_volatile);
131 if (!NT_STATUS_IS_OK(status)) {
132 DEBUG(1, ("tstream_smbXcli_np_destructor: cli_close "
133 "failed on pipe %s. Error was %s\n",
134 cli_nps->npipe, nt_errstr(status)));
137 * We can't do much on failure
139 return 0;
142 static int tstream_smbXcli_np_ref_destructor(struct tstream_smbXcli_np_ref *ref)
144 if (ref->cli_nps == NULL) {
145 return 0;
148 if (ref->cli_nps->conn == NULL) {
149 return 0;
152 ref->cli_nps->conn = NULL;
153 ref->cli_nps->session = NULL;
154 ref->cli_nps->tcon = NULL;
156 TALLOC_FREE(ref->cli_nps->conn_ref);
157 TALLOC_FREE(ref->cli_nps->session_ref);
158 TALLOC_FREE(ref->cli_nps->tcon_ref);
160 return 0;
163 static struct tevent_req *tstream_smbXcli_np_disconnect_send(TALLOC_CTX *mem_ctx,
164 struct tevent_context *ev,
165 struct tstream_context *stream);
166 static int tstream_smbXcli_np_disconnect_recv(struct tevent_req *req,
167 int *perrno);
169 struct tstream_smbXcli_np_open_state {
170 struct smbXcli_conn *conn;
171 struct smbXcli_session *session;
172 struct smbXcli_tcon *tcon;
173 uint16_t pid;
174 unsigned int timeout;
176 bool is_smb1;
177 uint16_t fnum;
178 uint64_t fid_persistent;
179 uint64_t fid_volatile;
180 const char *npipe;
183 static void tstream_smbXcli_np_open_done(struct tevent_req *subreq);
185 struct tevent_req *tstream_smbXcli_np_open_send(TALLOC_CTX *mem_ctx,
186 struct tevent_context *ev,
187 struct smbXcli_conn *conn,
188 struct smbXcli_session *session,
189 struct smbXcli_tcon *tcon,
190 uint16_t pid,
191 unsigned int timeout,
192 const char *npipe)
194 struct tevent_req *req;
195 struct tstream_smbXcli_np_open_state *state;
196 struct tevent_req *subreq;
198 req = tevent_req_create(mem_ctx, &state,
199 struct tstream_smbXcli_np_open_state);
200 if (!req) {
201 return NULL;
203 state->conn = conn;
204 state->tcon = tcon;
205 state->session = session;
206 state->pid = pid;
207 state->timeout = timeout;
209 state->npipe = talloc_strdup(state, npipe);
210 if (tevent_req_nomem(state->npipe, req)) {
211 return tevent_req_post(req, ev);
214 if (smbXcli_conn_protocol(conn) < PROTOCOL_SMB2_02) {
215 state->is_smb1 = true;
218 if (state->is_smb1) {
219 const char *smb1_npipe;
222 * Windows and newer Samba versions allow
223 * the pipe name without leading backslash,
224 * but we should better behave like windows clients
226 smb1_npipe = talloc_asprintf(state, "\\%s", state->npipe);
227 if (tevent_req_nomem(smb1_npipe, req)) {
228 return tevent_req_post(req, ev);
230 subreq = smb1cli_ntcreatex_send(state, ev, state->conn,
231 state->timeout,
232 state->pid,
233 state->tcon,
234 state->session,
235 smb1_npipe,
236 0, /* CreatFlags */
237 0, /* RootDirectoryFid */
238 TSTREAM_SMBXCLI_NP_DESIRED_ACCESS,
239 0, /* AllocationSize */
240 0, /* FileAttributes */
241 FILE_SHARE_READ|FILE_SHARE_WRITE,
242 FILE_OPEN, /* CreateDisposition */
243 0, /* CreateOptions */
244 2, /* NTCREATEX_IMPERSONATION_IMPERSONATION */
245 0); /* SecurityFlags */
246 } else {
247 subreq = smb2cli_create_send(state, ev, state->conn,
248 state->timeout, state->session,
249 state->tcon,
250 npipe,
251 SMB2_OPLOCK_LEVEL_NONE,
252 SMB2_IMPERSONATION_IMPERSONATION,
253 TSTREAM_SMBXCLI_NP_DESIRED_ACCESS,
254 0, /* file_attributes */
255 FILE_SHARE_READ|FILE_SHARE_WRITE,
256 FILE_OPEN,
257 0, /* create_options */
258 NULL); /* blobs */
260 if (tevent_req_nomem(subreq, req)) {
261 return tevent_req_post(req, ev);
263 tevent_req_set_callback(subreq, tstream_smbXcli_np_open_done, req);
265 return req;
268 static void tstream_smbXcli_np_open_done(struct tevent_req *subreq)
270 struct tevent_req *req =
271 tevent_req_callback_data(subreq, struct tevent_req);
272 struct tstream_smbXcli_np_open_state *state =
273 tevent_req_data(req, struct tstream_smbXcli_np_open_state);
274 NTSTATUS status;
276 if (state->is_smb1) {
277 status = smb1cli_ntcreatex_recv(subreq, &state->fnum);
278 } else {
279 status = smb2cli_create_recv(subreq,
280 &state->fid_persistent,
281 &state->fid_volatile,
282 NULL);
284 TALLOC_FREE(subreq);
285 if (!NT_STATUS_IS_OK(status)) {
286 tevent_req_nterror(req, status);
287 return;
290 tevent_req_done(req);
293 NTSTATUS _tstream_smbXcli_np_open_recv(struct tevent_req *req,
294 TALLOC_CTX *mem_ctx,
295 struct tstream_context **_stream,
296 const char *location)
298 struct tstream_smbXcli_np_open_state *state =
299 tevent_req_data(req, struct tstream_smbXcli_np_open_state);
300 struct tstream_context *stream;
301 struct tstream_smbXcli_np *cli_nps;
302 NTSTATUS status;
304 if (tevent_req_is_nterror(req, &status)) {
305 tevent_req_received(req);
306 return status;
309 stream = tstream_context_create(mem_ctx,
310 &tstream_smbXcli_np_ops,
311 &cli_nps,
312 struct tstream_smbXcli_np,
313 location);
314 if (!stream) {
315 tevent_req_received(req);
316 return NT_STATUS_NO_MEMORY;
318 ZERO_STRUCTP(cli_nps);
320 cli_nps->conn_ref = talloc_zero(state->conn,
321 struct tstream_smbXcli_np_ref);
322 if (cli_nps->conn_ref == NULL) {
323 TALLOC_FREE(cli_nps);
324 tevent_req_received(req);
325 return NT_STATUS_NO_MEMORY;
327 cli_nps->conn_ref->cli_nps = cli_nps;
329 cli_nps->session_ref = talloc_zero(state->session,
330 struct tstream_smbXcli_np_ref);
331 if (cli_nps->session_ref == NULL) {
332 TALLOC_FREE(cli_nps);
333 tevent_req_received(req);
334 return NT_STATUS_NO_MEMORY;
336 cli_nps->session_ref->cli_nps = cli_nps;
338 cli_nps->tcon_ref = talloc_zero(state->tcon,
339 struct tstream_smbXcli_np_ref);
340 if (cli_nps->tcon_ref == NULL) {
341 TALLOC_FREE(cli_nps);
342 tevent_req_received(req);
343 return NT_STATUS_NO_MEMORY;
345 cli_nps->tcon_ref->cli_nps = cli_nps;
347 cli_nps->conn = state->conn;
348 cli_nps->session = state->session;
349 cli_nps->tcon = state->tcon;
350 cli_nps->pid = state->pid;
351 cli_nps->timeout = state->timeout;
352 cli_nps->npipe = talloc_move(cli_nps, &state->npipe);
353 cli_nps->is_smb1 = state->is_smb1;
354 cli_nps->fnum = state->fnum;
355 cli_nps->fid_persistent = state->fid_persistent;
356 cli_nps->fid_volatile = state->fid_volatile;
358 talloc_set_destructor(cli_nps, tstream_smbXcli_np_destructor);
359 talloc_set_destructor(cli_nps->conn_ref,
360 tstream_smbXcli_np_ref_destructor);
361 talloc_set_destructor(cli_nps->session_ref,
362 tstream_smbXcli_np_ref_destructor);
363 talloc_set_destructor(cli_nps->tcon_ref,
364 tstream_smbXcli_np_ref_destructor);
366 cli_nps->trans.active = false;
367 cli_nps->trans.read_req = NULL;
368 cli_nps->trans.write_req = NULL;
369 SSVAL(cli_nps->trans.setup+0, 0, TRANSACT_DCERPCCMD);
370 SSVAL(cli_nps->trans.setup+1, 0, cli_nps->fnum);
372 *_stream = stream;
373 tevent_req_received(req);
374 return NT_STATUS_OK;
377 static ssize_t tstream_smbXcli_np_pending_bytes(struct tstream_context *stream)
379 struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
380 struct tstream_smbXcli_np);
382 if (!smbXcli_conn_is_connected(cli_nps->conn)) {
383 errno = ENOTCONN;
384 return -1;
387 return cli_nps->read.left;
390 bool tstream_is_smbXcli_np(struct tstream_context *stream)
392 struct tstream_smbXcli_np *cli_nps =
393 talloc_get_type(_tstream_context_data(stream),
394 struct tstream_smbXcli_np);
396 if (!cli_nps) {
397 return false;
400 return true;
403 NTSTATUS tstream_smbXcli_np_use_trans(struct tstream_context *stream)
405 struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
406 struct tstream_smbXcli_np);
408 if (cli_nps->trans.read_req) {
409 return NT_STATUS_PIPE_BUSY;
412 if (cli_nps->trans.write_req) {
413 return NT_STATUS_PIPE_BUSY;
416 if (cli_nps->trans.active) {
417 return NT_STATUS_PIPE_BUSY;
420 cli_nps->trans.active = true;
422 return NT_STATUS_OK;
425 unsigned int tstream_smbXcli_np_set_timeout(struct tstream_context *stream,
426 unsigned int timeout)
428 struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
429 struct tstream_smbXcli_np);
430 unsigned int old_timeout = cli_nps->timeout;
432 cli_nps->timeout = timeout;
433 return old_timeout;
436 struct tstream_smbXcli_np_writev_state {
437 struct tstream_context *stream;
438 struct tevent_context *ev;
440 struct iovec *vector;
441 size_t count;
443 int ret;
445 struct {
446 int val;
447 const char *location;
448 } error;
451 static int tstream_smbXcli_np_writev_state_destructor(struct tstream_smbXcli_np_writev_state *state)
453 struct tstream_smbXcli_np *cli_nps =
454 tstream_context_data(state->stream,
455 struct tstream_smbXcli_np);
457 cli_nps->trans.write_req = NULL;
459 return 0;
462 static void tstream_smbXcli_np_writev_write_next(struct tevent_req *req);
464 static struct tevent_req *tstream_smbXcli_np_writev_send(TALLOC_CTX *mem_ctx,
465 struct tevent_context *ev,
466 struct tstream_context *stream,
467 const struct iovec *vector,
468 size_t count)
470 struct tevent_req *req;
471 struct tstream_smbXcli_np_writev_state *state;
472 struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
473 struct tstream_smbXcli_np);
475 req = tevent_req_create(mem_ctx, &state,
476 struct tstream_smbXcli_np_writev_state);
477 if (!req) {
478 return NULL;
480 state->stream = stream;
481 state->ev = ev;
482 state->ret = 0;
484 talloc_set_destructor(state, tstream_smbXcli_np_writev_state_destructor);
486 if (!smbXcli_conn_is_connected(cli_nps->conn)) {
487 tevent_req_error(req, ENOTCONN);
488 return tevent_req_post(req, ev);
492 * we make a copy of the vector so we can change the structure
494 state->vector = talloc_array(state, struct iovec, count);
495 if (tevent_req_nomem(state->vector, req)) {
496 return tevent_req_post(req, ev);
498 memcpy(state->vector, vector, sizeof(struct iovec) * count);
499 state->count = count;
501 tstream_smbXcli_np_writev_write_next(req);
502 if (!tevent_req_is_in_progress(req)) {
503 return tevent_req_post(req, ev);
506 return req;
509 static void tstream_smbXcli_np_readv_trans_start(struct tevent_req *req);
510 static void tstream_smbXcli_np_writev_write_done(struct tevent_req *subreq);
512 static void tstream_smbXcli_np_writev_write_next(struct tevent_req *req)
514 struct tstream_smbXcli_np_writev_state *state =
515 tevent_req_data(req,
516 struct tstream_smbXcli_np_writev_state);
517 struct tstream_smbXcli_np *cli_nps =
518 tstream_context_data(state->stream,
519 struct tstream_smbXcli_np);
520 struct tevent_req *subreq;
521 size_t i;
522 size_t left = 0;
524 for (i=0; i < state->count; i++) {
525 left += state->vector[i].iov_len;
528 if (left == 0) {
529 TALLOC_FREE(cli_nps->write.buf);
530 tevent_req_done(req);
531 return;
534 cli_nps->write.ofs = 0;
535 cli_nps->write.left = MIN(left, TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE);
536 cli_nps->write.buf = talloc_realloc(cli_nps, cli_nps->write.buf,
537 uint8_t, cli_nps->write.left);
538 if (tevent_req_nomem(cli_nps->write.buf, req)) {
539 return;
543 * copy the pending buffer first
545 while (cli_nps->write.left > 0 && state->count > 0) {
546 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
547 size_t len = MIN(cli_nps->write.left, state->vector[0].iov_len);
549 memcpy(cli_nps->write.buf + cli_nps->write.ofs, base, len);
551 base += len;
552 state->vector[0].iov_base = base;
553 state->vector[0].iov_len -= len;
555 cli_nps->write.ofs += len;
556 cli_nps->write.left -= len;
558 if (state->vector[0].iov_len == 0) {
559 state->vector += 1;
560 state->count -= 1;
563 state->ret += len;
566 if (cli_nps->trans.active && state->count == 0) {
567 cli_nps->trans.active = false;
568 cli_nps->trans.write_req = req;
569 return;
572 if (cli_nps->trans.read_req && state->count == 0) {
573 cli_nps->trans.write_req = req;
574 tstream_smbXcli_np_readv_trans_start(cli_nps->trans.read_req);
575 return;
578 if (cli_nps->is_smb1) {
579 subreq = smb1cli_writex_send(state, state->ev,
580 cli_nps->conn,
581 cli_nps->timeout,
582 cli_nps->pid,
583 cli_nps->tcon,
584 cli_nps->session,
585 cli_nps->fnum,
586 8, /* 8 means message mode. */
587 cli_nps->write.buf,
588 0, /* offset */
589 cli_nps->write.ofs); /* size */
590 } else {
591 subreq = smb2cli_write_send(state, state->ev,
592 cli_nps->conn,
593 cli_nps->timeout,
594 cli_nps->session,
595 cli_nps->tcon,
596 cli_nps->write.ofs, /* length */
597 0, /* offset */
598 cli_nps->fid_persistent,
599 cli_nps->fid_volatile,
600 0, /* remaining_bytes */
601 0, /* flags */
602 cli_nps->write.buf);
604 if (tevent_req_nomem(subreq, req)) {
605 return;
607 tevent_req_set_callback(subreq,
608 tstream_smbXcli_np_writev_write_done,
609 req);
612 static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req *req,
613 int error,
614 const char *location);
616 static void tstream_smbXcli_np_writev_write_done(struct tevent_req *subreq)
618 struct tevent_req *req =
619 tevent_req_callback_data(subreq, struct tevent_req);
620 struct tstream_smbXcli_np_writev_state *state =
621 tevent_req_data(req, struct tstream_smbXcli_np_writev_state);
622 struct tstream_smbXcli_np *cli_nps =
623 tstream_context_data(state->stream,
624 struct tstream_smbXcli_np);
625 uint32_t written;
626 NTSTATUS status;
628 if (cli_nps->is_smb1) {
629 status = smb1cli_writex_recv(subreq, &written, NULL);
630 } else {
631 status = smb2cli_write_recv(subreq, &written);
633 TALLOC_FREE(subreq);
634 if (!NT_STATUS_IS_OK(status)) {
635 tstream_smbXcli_np_writev_disconnect_now(req, EIO, __location__);
636 return;
639 if (written != cli_nps->write.ofs) {
640 tstream_smbXcli_np_writev_disconnect_now(req, EIO, __location__);
641 return;
644 tstream_smbXcli_np_writev_write_next(req);
647 static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req *subreq);
649 static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req *req,
650 int error,
651 const char *location)
653 struct tstream_smbXcli_np_writev_state *state =
654 tevent_req_data(req,
655 struct tstream_smbXcli_np_writev_state);
656 struct tstream_smbXcli_np *cli_nps =
657 tstream_context_data(state->stream,
658 struct tstream_smbXcli_np);
659 struct tevent_req *subreq;
661 state->error.val = error;
662 state->error.location = location;
664 if (!smbXcli_conn_is_connected(cli_nps->conn)) {
665 /* return the original error */
666 _tevent_req_error(req, state->error.val, state->error.location);
667 return;
670 subreq = tstream_smbXcli_np_disconnect_send(state, state->ev,
671 state->stream);
672 if (subreq == NULL) {
673 /* return the original error */
674 _tevent_req_error(req, state->error.val, state->error.location);
675 return;
677 tevent_req_set_callback(subreq,
678 tstream_smbXcli_np_writev_disconnect_done,
679 req);
682 static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req *subreq)
684 struct tevent_req *req =
685 tevent_req_callback_data(subreq, struct tevent_req);
686 struct tstream_smbXcli_np_writev_state *state =
687 tevent_req_data(req, struct tstream_smbXcli_np_writev_state);
688 int error;
690 tstream_smbXcli_np_disconnect_recv(subreq, &error);
691 TALLOC_FREE(subreq);
693 /* return the original error */
694 _tevent_req_error(req, state->error.val, state->error.location);
697 static int tstream_smbXcli_np_writev_recv(struct tevent_req *req,
698 int *perrno)
700 struct tstream_smbXcli_np_writev_state *state =
701 tevent_req_data(req,
702 struct tstream_smbXcli_np_writev_state);
703 int ret;
705 ret = tsocket_simple_int_recv(req, perrno);
706 if (ret == 0) {
707 ret = state->ret;
710 tevent_req_received(req);
711 return ret;
714 struct tstream_smbXcli_np_readv_state {
715 struct tstream_context *stream;
716 struct tevent_context *ev;
718 struct iovec *vector;
719 size_t count;
721 int ret;
723 struct {
724 struct tevent_immediate *im;
725 } trans;
727 struct {
728 int val;
729 const char *location;
730 } error;
733 static int tstream_smbXcli_np_readv_state_destructor(struct tstream_smbXcli_np_readv_state *state)
735 struct tstream_smbXcli_np *cli_nps =
736 tstream_context_data(state->stream,
737 struct tstream_smbXcli_np);
739 cli_nps->trans.read_req = NULL;
741 return 0;
744 static void tstream_smbXcli_np_readv_read_next(struct tevent_req *req);
746 static struct tevent_req *tstream_smbXcli_np_readv_send(TALLOC_CTX *mem_ctx,
747 struct tevent_context *ev,
748 struct tstream_context *stream,
749 struct iovec *vector,
750 size_t count)
752 struct tevent_req *req;
753 struct tstream_smbXcli_np_readv_state *state;
754 struct tstream_smbXcli_np *cli_nps =
755 tstream_context_data(stream, struct tstream_smbXcli_np);
757 req = tevent_req_create(mem_ctx, &state,
758 struct tstream_smbXcli_np_readv_state);
759 if (!req) {
760 return NULL;
762 state->stream = stream;
763 state->ev = ev;
764 state->ret = 0;
766 talloc_set_destructor(state, tstream_smbXcli_np_readv_state_destructor);
768 if (!smbXcli_conn_is_connected(cli_nps->conn)) {
769 tevent_req_error(req, ENOTCONN);
770 return tevent_req_post(req, ev);
774 * we make a copy of the vector so we can change the structure
776 state->vector = talloc_array(state, struct iovec, count);
777 if (tevent_req_nomem(state->vector, req)) {
778 return tevent_req_post(req, ev);
780 memcpy(state->vector, vector, sizeof(struct iovec) * count);
781 state->count = count;
783 tstream_smbXcli_np_readv_read_next(req);
784 if (!tevent_req_is_in_progress(req)) {
785 return tevent_req_post(req, ev);
788 return req;
791 static void tstream_smbXcli_np_readv_read_done(struct tevent_req *subreq);
793 static void tstream_smbXcli_np_readv_read_next(struct tevent_req *req)
795 struct tstream_smbXcli_np_readv_state *state =
796 tevent_req_data(req,
797 struct tstream_smbXcli_np_readv_state);
798 struct tstream_smbXcli_np *cli_nps =
799 tstream_context_data(state->stream,
800 struct tstream_smbXcli_np);
801 struct tevent_req *subreq;
804 * copy the pending buffer first
806 while (cli_nps->read.left > 0 && state->count > 0) {
807 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
808 size_t len = MIN(cli_nps->read.left, state->vector[0].iov_len);
810 memcpy(base, cli_nps->read.buf + cli_nps->read.ofs, len);
812 base += len;
813 state->vector[0].iov_base = base;
814 state->vector[0].iov_len -= len;
816 cli_nps->read.ofs += len;
817 cli_nps->read.left -= len;
819 if (state->vector[0].iov_len == 0) {
820 state->vector += 1;
821 state->count -= 1;
824 state->ret += len;
827 if (cli_nps->read.left == 0) {
828 TALLOC_FREE(cli_nps->read.buf);
831 if (state->count == 0) {
832 tevent_req_done(req);
833 return;
836 if (cli_nps->trans.active) {
837 cli_nps->trans.active = false;
838 cli_nps->trans.read_req = req;
839 return;
842 if (cli_nps->trans.write_req) {
843 cli_nps->trans.read_req = req;
844 tstream_smbXcli_np_readv_trans_start(req);
845 return;
848 if (cli_nps->is_smb1) {
849 subreq = smb1cli_readx_send(state, state->ev,
850 cli_nps->conn,
851 cli_nps->timeout,
852 cli_nps->pid,
853 cli_nps->tcon,
854 cli_nps->session,
855 cli_nps->fnum,
856 0, /* offset */
857 TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE);
858 } else {
859 subreq = smb2cli_read_send(state, state->ev,
860 cli_nps->conn,
861 cli_nps->timeout,
862 cli_nps->session,
863 cli_nps->tcon,
864 TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE, /* length */
865 0, /* offset */
866 cli_nps->fid_persistent,
867 cli_nps->fid_volatile,
868 0, /* minimum_count */
869 0); /* remaining_bytes */
871 if (tevent_req_nomem(subreq, req)) {
872 return;
874 tevent_req_set_callback(subreq,
875 tstream_smbXcli_np_readv_read_done,
876 req);
879 static void tstream_smbXcli_np_readv_trans_done(struct tevent_req *subreq);
881 static void tstream_smbXcli_np_readv_trans_start(struct tevent_req *req)
883 struct tstream_smbXcli_np_readv_state *state =
884 tevent_req_data(req,
885 struct tstream_smbXcli_np_readv_state);
886 struct tstream_smbXcli_np *cli_nps =
887 tstream_context_data(state->stream,
888 struct tstream_smbXcli_np);
889 struct tevent_req *subreq;
891 state->trans.im = tevent_create_immediate(state);
892 if (tevent_req_nomem(state->trans.im, req)) {
893 return;
896 if (cli_nps->is_smb1) {
897 subreq = smb1cli_trans_send(state, state->ev,
898 cli_nps->conn, SMBtrans,
899 0, 0, /* *_flags */
900 0, 0, /* *_flags2 */
901 cli_nps->timeout,
902 cli_nps->pid,
903 cli_nps->tcon,
904 cli_nps->session,
905 "\\PIPE\\",
906 0, 0, 0,
907 cli_nps->trans.setup, 2,
909 NULL, 0, 0,
910 cli_nps->write.buf,
911 cli_nps->write.ofs,
912 TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE);
913 } else {
914 DATA_BLOB in_input_buffer = data_blob_null;
915 DATA_BLOB in_output_buffer = data_blob_null;
917 in_input_buffer = data_blob_const(cli_nps->write.buf,
918 cli_nps->write.ofs);
920 subreq = smb2cli_ioctl_send(state, state->ev,
921 cli_nps->conn,
922 cli_nps->timeout,
923 cli_nps->session,
924 cli_nps->tcon,
925 cli_nps->fid_persistent,
926 cli_nps->fid_volatile,
927 FSCTL_NAMED_PIPE_READ_WRITE,
928 0, /* in_max_input_length */
929 &in_input_buffer,
930 /* in_max_output_length */
931 TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE,
932 &in_output_buffer,
933 SMB2_IOCTL_FLAG_IS_FSCTL);
935 if (tevent_req_nomem(subreq, req)) {
936 return;
938 tevent_req_set_callback(subreq,
939 tstream_smbXcli_np_readv_trans_done,
940 req);
943 static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req *req,
944 int error,
945 const char *location);
946 static void tstream_smbXcli_np_readv_trans_next(struct tevent_context *ctx,
947 struct tevent_immediate *im,
948 void *private_data);
950 static void tstream_smbXcli_np_readv_trans_done(struct tevent_req *subreq)
952 struct tevent_req *req =
953 tevent_req_callback_data(subreq, struct tevent_req);
954 struct tstream_smbXcli_np_readv_state *state =
955 tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
956 struct tstream_smbXcli_np *cli_nps =
957 tstream_context_data(state->stream, struct tstream_smbXcli_np);
958 uint8_t *rcvbuf;
959 uint32_t received;
960 NTSTATUS status;
962 if (cli_nps->is_smb1) {
963 status = smb1cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
964 NULL, 0, NULL,
965 &rcvbuf, 0, &received);
966 } else {
967 DATA_BLOB out_input_buffer = data_blob_null;
968 DATA_BLOB out_output_buffer = data_blob_null;
970 status = smb2cli_ioctl_recv(subreq, state,
971 &out_input_buffer,
972 &out_output_buffer);
974 /* Note that rcvbuf is not a talloc pointer here */
975 rcvbuf = out_output_buffer.data;
976 received = out_output_buffer.length;
978 TALLOC_FREE(subreq);
979 if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
980 status = NT_STATUS_OK;
982 if (!NT_STATUS_IS_OK(status)) {
983 tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
984 return;
987 if (received > TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE) {
988 tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
989 return;
992 if (received == 0) {
993 tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
994 return;
997 cli_nps->read.ofs = 0;
998 cli_nps->read.left = received;
999 cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received);
1000 if (cli_nps->read.buf == NULL) {
1001 TALLOC_FREE(subreq);
1002 tevent_req_nomem(cli_nps->read.buf, req);
1003 return;
1005 memcpy(cli_nps->read.buf, rcvbuf, received);
1007 if (cli_nps->trans.write_req == NULL) {
1008 tstream_smbXcli_np_readv_read_next(req);
1009 return;
1012 tevent_schedule_immediate(state->trans.im, state->ev,
1013 tstream_smbXcli_np_readv_trans_next, req);
1015 tevent_req_done(cli_nps->trans.write_req);
1018 static void tstream_smbXcli_np_readv_trans_next(struct tevent_context *ctx,
1019 struct tevent_immediate *im,
1020 void *private_data)
1022 struct tevent_req *req =
1023 talloc_get_type_abort(private_data,
1024 struct tevent_req);
1026 tstream_smbXcli_np_readv_read_next(req);
1029 static void tstream_smbXcli_np_readv_read_done(struct tevent_req *subreq)
1031 struct tevent_req *req =
1032 tevent_req_callback_data(subreq, struct tevent_req);
1033 struct tstream_smbXcli_np_readv_state *state =
1034 tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
1035 struct tstream_smbXcli_np *cli_nps =
1036 tstream_context_data(state->stream, struct tstream_smbXcli_np);
1037 uint8_t *rcvbuf;
1038 uint32_t received;
1039 NTSTATUS status;
1042 * We must free subreq in this function as there is
1043 * a timer event attached to it.
1046 if (cli_nps->is_smb1) {
1047 status = smb1cli_readx_recv(subreq, &received, &rcvbuf);
1048 } else {
1049 status = smb2cli_read_recv(subreq, state, &rcvbuf, &received);
1052 * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
1053 * child of that.
1055 if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
1057 * NT_STATUS_BUFFER_TOO_SMALL means that there's
1058 * more data to read when the named pipe is used
1059 * in message mode (which is the case here).
1061 * But we hide this from the caller.
1063 status = NT_STATUS_OK;
1065 if (!NT_STATUS_IS_OK(status)) {
1066 TALLOC_FREE(subreq);
1067 tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
1068 return;
1071 if (received > TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE) {
1072 TALLOC_FREE(subreq);
1073 tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
1074 return;
1077 if (received == 0) {
1078 TALLOC_FREE(subreq);
1079 tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
1080 return;
1083 cli_nps->read.ofs = 0;
1084 cli_nps->read.left = received;
1085 cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received);
1086 if (cli_nps->read.buf == NULL) {
1087 TALLOC_FREE(subreq);
1088 tevent_req_nomem(cli_nps->read.buf, req);
1089 return;
1091 memcpy(cli_nps->read.buf, rcvbuf, received);
1092 TALLOC_FREE(subreq);
1094 tstream_smbXcli_np_readv_read_next(req);
1097 static void tstream_smbXcli_np_readv_disconnect_done(struct tevent_req *subreq);
1099 static void tstream_smbXcli_np_readv_error(struct tevent_req *req);
1101 static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req *req,
1102 int error,
1103 const char *location)
1105 struct tstream_smbXcli_np_readv_state *state =
1106 tevent_req_data(req,
1107 struct tstream_smbXcli_np_readv_state);
1108 struct tstream_smbXcli_np *cli_nps =
1109 tstream_context_data(state->stream,
1110 struct tstream_smbXcli_np);
1111 struct tevent_req *subreq;
1113 state->error.val = error;
1114 state->error.location = location;
1116 if (!smbXcli_conn_is_connected(cli_nps->conn)) {
1117 /* return the original error */
1118 tstream_smbXcli_np_readv_error(req);
1119 return;
1122 subreq = tstream_smbXcli_np_disconnect_send(state, state->ev,
1123 state->stream);
1124 if (subreq == NULL) {
1125 /* return the original error */
1126 tstream_smbXcli_np_readv_error(req);
1127 return;
1129 tevent_req_set_callback(subreq,
1130 tstream_smbXcli_np_readv_disconnect_done,
1131 req);
1134 static void tstream_smbXcli_np_readv_disconnect_done(struct tevent_req *subreq)
1136 struct tevent_req *req =
1137 tevent_req_callback_data(subreq, struct tevent_req);
1138 int error;
1140 tstream_smbXcli_np_disconnect_recv(subreq, &error);
1141 TALLOC_FREE(subreq);
1143 tstream_smbXcli_np_readv_error(req);
1146 static void tstream_smbXcli_np_readv_error_trigger(struct tevent_context *ctx,
1147 struct tevent_immediate *im,
1148 void *private_data);
1150 static void tstream_smbXcli_np_readv_error(struct tevent_req *req)
1152 struct tstream_smbXcli_np_readv_state *state =
1153 tevent_req_data(req,
1154 struct tstream_smbXcli_np_readv_state);
1155 struct tstream_smbXcli_np *cli_nps =
1156 tstream_context_data(state->stream,
1157 struct tstream_smbXcli_np);
1159 if (cli_nps->trans.write_req == NULL) {
1160 /* return the original error */
1161 _tevent_req_error(req, state->error.val, state->error.location);
1162 return;
1165 if (state->trans.im == NULL) {
1166 /* return the original error */
1167 _tevent_req_error(req, state->error.val, state->error.location);
1168 return;
1171 tevent_schedule_immediate(state->trans.im, state->ev,
1172 tstream_smbXcli_np_readv_error_trigger, req);
1174 /* return the original error for writev */
1175 _tevent_req_error(cli_nps->trans.write_req,
1176 state->error.val, state->error.location);
1179 static void tstream_smbXcli_np_readv_error_trigger(struct tevent_context *ctx,
1180 struct tevent_immediate *im,
1181 void *private_data)
1183 struct tevent_req *req =
1184 talloc_get_type_abort(private_data,
1185 struct tevent_req);
1186 struct tstream_smbXcli_np_readv_state *state =
1187 tevent_req_data(req,
1188 struct tstream_smbXcli_np_readv_state);
1190 /* return the original error */
1191 _tevent_req_error(req, state->error.val, state->error.location);
1194 static int tstream_smbXcli_np_readv_recv(struct tevent_req *req,
1195 int *perrno)
1197 struct tstream_smbXcli_np_readv_state *state =
1198 tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
1199 int ret;
1201 ret = tsocket_simple_int_recv(req, perrno);
1202 if (ret == 0) {
1203 ret = state->ret;
1206 tevent_req_received(req);
1207 return ret;
1210 struct tstream_smbXcli_np_disconnect_state {
1211 struct tstream_context *stream;
1212 struct tevent_req *subreq;
1215 static void tstream_smbXcli_np_disconnect_done(struct tevent_req *subreq);
1216 static void tstream_smbXcli_np_disconnect_cleanup(struct tevent_req *req,
1217 enum tevent_req_state req_state);
1219 static struct tevent_req *tstream_smbXcli_np_disconnect_send(TALLOC_CTX *mem_ctx,
1220 struct tevent_context *ev,
1221 struct tstream_context *stream)
1223 struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
1224 struct tstream_smbXcli_np);
1225 struct tevent_req *req;
1226 struct tstream_smbXcli_np_disconnect_state *state;
1227 struct tevent_req *subreq;
1229 req = tevent_req_create(mem_ctx, &state,
1230 struct tstream_smbXcli_np_disconnect_state);
1231 if (req == NULL) {
1232 return NULL;
1235 state->stream = stream;
1237 if (!smbXcli_conn_is_connected(cli_nps->conn)) {
1238 tevent_req_error(req, ENOTCONN);
1239 return tevent_req_post(req, ev);
1242 if (cli_nps->is_smb1) {
1243 subreq = smb1cli_close_send(state, ev, cli_nps->conn,
1244 cli_nps->timeout,
1245 cli_nps->pid,
1246 cli_nps->tcon,
1247 cli_nps->session,
1248 cli_nps->fnum, UINT32_MAX);
1249 } else {
1250 subreq = smb2cli_close_send(state, ev, cli_nps->conn,
1251 cli_nps->timeout,
1252 cli_nps->session,
1253 cli_nps->tcon,
1254 0, /* flags */
1255 cli_nps->fid_persistent,
1256 cli_nps->fid_volatile);
1258 if (tevent_req_nomem(subreq, req)) {
1259 return tevent_req_post(req, ev);
1261 tevent_req_set_callback(subreq, tstream_smbXcli_np_disconnect_done, req);
1262 state->subreq = subreq;
1264 tevent_req_set_cleanup_fn(req, tstream_smbXcli_np_disconnect_cleanup);
1267 * Make sure we don't send any requests anymore.
1269 cli_nps->conn = NULL;
1271 return req;
1274 static void tstream_smbXcli_np_disconnect_done(struct tevent_req *subreq)
1276 struct tevent_req *req = tevent_req_callback_data(subreq,
1277 struct tevent_req);
1278 struct tstream_smbXcli_np_disconnect_state *state =
1279 tevent_req_data(req, struct tstream_smbXcli_np_disconnect_state);
1280 struct tstream_smbXcli_np *cli_nps =
1281 tstream_context_data(state->stream, struct tstream_smbXcli_np);
1282 NTSTATUS status;
1284 state->subreq = NULL;
1286 if (cli_nps->is_smb1) {
1287 status = smb1cli_close_recv(subreq);
1288 } else {
1289 status = smb2cli_close_recv(subreq);
1291 TALLOC_FREE(subreq);
1292 if (!NT_STATUS_IS_OK(status)) {
1293 tevent_req_error(req, EIO);
1294 return;
1297 cli_nps->conn = NULL;
1298 cli_nps->session = NULL;
1299 cli_nps->tcon = NULL;
1301 tevent_req_done(req);
1304 static void tstream_smbXcli_np_disconnect_free(struct tevent_req *subreq);
1306 static void tstream_smbXcli_np_disconnect_cleanup(struct tevent_req *req,
1307 enum tevent_req_state req_state)
1309 struct tstream_smbXcli_np_disconnect_state *state =
1310 tevent_req_data(req, struct tstream_smbXcli_np_disconnect_state);
1311 struct tstream_smbXcli_np *cli_nps = NULL;
1313 if (state->subreq == NULL) {
1314 return;
1317 cli_nps = tstream_context_data(state->stream, struct tstream_smbXcli_np);
1319 if (cli_nps->tcon == NULL) {
1320 return;
1324 * We're no longer interested in the result
1325 * any more, but need to make sure that the close
1326 * request arrives at the server if the smb connection,
1327 * session and tcon are still alive.
1329 * We move the low level request to the tcon,
1330 * which means that it stays as long as the tcon
1331 * is available.
1333 talloc_steal(cli_nps->tcon, state->subreq);
1334 tevent_req_set_callback(state->subreq,
1335 tstream_smbXcli_np_disconnect_free,
1336 NULL);
1337 state->subreq = NULL;
1339 cli_nps->conn = NULL;
1340 cli_nps->session = NULL;
1341 cli_nps->tcon = NULL;
1344 static void tstream_smbXcli_np_disconnect_free(struct tevent_req *subreq)
1346 TALLOC_FREE(subreq);
1349 static int tstream_smbXcli_np_disconnect_recv(struct tevent_req *req,
1350 int *perrno)
1352 int ret;
1354 ret = tsocket_simple_int_recv(req, perrno);
1356 tevent_req_received(req);
1357 return ret;
1360 static const struct tstream_context_ops tstream_smbXcli_np_ops = {
1361 .name = "smbXcli_np",
1363 .pending_bytes = tstream_smbXcli_np_pending_bytes,
1365 .readv_send = tstream_smbXcli_np_readv_send,
1366 .readv_recv = tstream_smbXcli_np_readv_recv,
1368 .writev_send = tstream_smbXcli_np_writev_send,
1369 .writev_recv = tstream_smbXcli_np_writev_recv,
1371 .disconnect_send = tstream_smbXcli_np_disconnect_send,
1372 .disconnect_recv = tstream_smbXcli_np_disconnect_recv,