5e11a92d06834e93c6afdfe5d349801005ff47fc
[samba.git] / source3 / libsmb / cli_np_tstream.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Stefan Metzmacher 2010
5
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.
10
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.
15
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/>.
18 */
19
20 #include "includes.h"
21 #include "system/network.h"
22 #include "libsmb/libsmb.h"
23 #include "../lib/util/tevent_ntstatus.h"
24 #include "../lib/tsocket/tsocket.h"
25 #include "../lib/tsocket/tsocket_internal.h"
26 #include "cli_np_tstream.h"
27
28 static const struct tstream_context_ops tstream_cli_np_ops;
29
30 /*
31  * Windows uses 4280 (the max xmit/recv size negotiated on DCERPC).
32  * This is fits into the max_xmit negotiated at the SMB layer.
33  *
34  * On the sending side they may use SMBtranss if the request does not
35  * fit into a single SMBtrans call.
36  *
37  * Windows uses 1024 as max data size of a SMBtrans request and then
38  * possibly reads the rest of the DCERPC fragment (up to 3256 bytes)
39  * via a SMBreadX.
40  *
41  * For now we just ask for the full 4280 bytes (max data size) in the SMBtrans
42  * request to get the whole fragment at once (like samba 3.5.x and below did.
43  *
44  * It is important that we use do SMBwriteX with the size of a full fragment,
45  * otherwise we may get NT_STATUS_PIPE_BUSY on the SMBtrans request
46  * from NT4 servers. (See bug #8195)
47  */
48 #define TSTREAM_CLI_NP_BUF_SIZE 4280
49
50 struct tstream_cli_np {
51         struct cli_state *cli;
52         const char *npipe;
53         uint16_t fnum;
54         unsigned int default_timeout;
55
56         struct {
57                 bool active;
58                 struct tevent_req *read_req;
59                 struct tevent_req *write_req;
60                 uint16_t setup[2];
61         } trans;
62
63         struct {
64                 off_t ofs;
65                 size_t left;
66                 uint8_t buf[TSTREAM_CLI_NP_BUF_SIZE];
67         } read, write;
68 };
69
70 static int tstream_cli_np_destructor(struct tstream_cli_np *cli_nps)
71 {
72         NTSTATUS status;
73
74         if (!cli_state_is_connected(cli_nps->cli)) {
75                 return 0;
76         }
77
78         /*
79          * TODO: do not use a sync call with a destructor!!!
80          *
81          * This only happens, if a caller does talloc_free(),
82          * while the everything was still ok.
83          *
84          * If we get an unexpected failure within a normal
85          * operation, we already do an async cli_close_send()/_recv().
86          *
87          * Once we've fixed all callers to call
88          * tstream_disconnect_send()/_recv(), this will
89          * never be called.
90          */
91         status = cli_close(cli_nps->cli, cli_nps->fnum);
92         if (!NT_STATUS_IS_OK(status)) {
93                 DEBUG(1, ("tstream_cli_np_destructor: cli_close "
94                           "failed on pipe %s. Error was %s\n",
95                           cli_nps->npipe, nt_errstr(status)));
96         }
97         /*
98          * We can't do much on failure
99          */
100         return 0;
101 }
102
103 struct tstream_cli_np_open_state {
104         struct cli_state *cli;
105         uint16_t fnum;
106         const char *npipe;
107 };
108
109 static void tstream_cli_np_open_done(struct tevent_req *subreq);
110
111 struct tevent_req *tstream_cli_np_open_send(TALLOC_CTX *mem_ctx,
112                                             struct tevent_context *ev,
113                                             struct cli_state *cli,
114                                             const char *npipe)
115 {
116         struct tevent_req *req;
117         struct tstream_cli_np_open_state *state;
118         struct tevent_req *subreq;
119
120         req = tevent_req_create(mem_ctx, &state,
121                                 struct tstream_cli_np_open_state);
122         if (!req) {
123                 return NULL;
124         }
125         state->cli = cli;
126
127         state->npipe = talloc_strdup(state, npipe);
128         if (tevent_req_nomem(state->npipe, req)) {
129                 return tevent_req_post(req, ev);
130         }
131
132         subreq = cli_ntcreate_send(state, ev, cli,
133                                    npipe,
134                                    0,
135                                    DESIRED_ACCESS_PIPE,
136                                    0,
137                                    FILE_SHARE_READ|FILE_SHARE_WRITE,
138                                    FILE_OPEN,
139                                    0,
140                                    0);
141         if (tevent_req_nomem(subreq, req)) {
142                 return tevent_req_post(req, ev);
143         }
144         tevent_req_set_callback(subreq, tstream_cli_np_open_done, req);
145
146         return req;
147 }
148
149 static void tstream_cli_np_open_done(struct tevent_req *subreq)
150 {
151         struct tevent_req *req =
152                 tevent_req_callback_data(subreq, struct tevent_req);
153         struct tstream_cli_np_open_state *state =
154                 tevent_req_data(req, struct tstream_cli_np_open_state);
155         NTSTATUS status;
156
157         status = cli_ntcreate_recv(subreq, &state->fnum);
158         TALLOC_FREE(subreq);
159         if (!NT_STATUS_IS_OK(status)) {
160                 tevent_req_nterror(req, status);
161                 return;
162         }
163
164         tevent_req_done(req);
165 }
166
167 NTSTATUS _tstream_cli_np_open_recv(struct tevent_req *req,
168                                    TALLOC_CTX *mem_ctx,
169                                    struct tstream_context **_stream,
170                                    const char *location)
171 {
172         struct tstream_cli_np_open_state *state =
173                 tevent_req_data(req, struct tstream_cli_np_open_state);
174         struct tstream_context *stream;
175         struct tstream_cli_np *cli_nps;
176         NTSTATUS status;
177
178         if (tevent_req_is_nterror(req, &status)) {
179                 tevent_req_received(req);
180                 return status;
181         }
182
183         stream = tstream_context_create(mem_ctx,
184                                         &tstream_cli_np_ops,
185                                         &cli_nps,
186                                         struct tstream_cli_np,
187                                         location);
188         if (!stream) {
189                 tevent_req_received(req);
190                 return NT_STATUS_NO_MEMORY;
191         }
192         ZERO_STRUCTP(cli_nps);
193
194         cli_nps->cli = state->cli;
195         cli_nps->npipe = talloc_move(cli_nps, &state->npipe);
196         cli_nps->fnum = state->fnum;
197         cli_nps->default_timeout = state->cli->timeout;
198
199         talloc_set_destructor(cli_nps, tstream_cli_np_destructor);
200
201         cli_nps->trans.active = false;
202         cli_nps->trans.read_req = NULL;
203         cli_nps->trans.write_req = NULL;
204         SSVAL(cli_nps->trans.setup+0, 0, TRANSACT_DCERPCCMD);
205         SSVAL(cli_nps->trans.setup+1, 0, cli_nps->fnum);
206
207         *_stream = stream;
208         tevent_req_received(req);
209         return NT_STATUS_OK;
210 }
211
212 static ssize_t tstream_cli_np_pending_bytes(struct tstream_context *stream)
213 {
214         struct tstream_cli_np *cli_nps = tstream_context_data(stream,
215                                          struct tstream_cli_np);
216
217         if (!cli_state_is_connected(cli_nps->cli)) {
218                 errno = ENOTCONN;
219                 return -1;
220         }
221
222         return cli_nps->read.left;
223 }
224
225 bool tstream_is_cli_np(struct tstream_context *stream)
226 {
227         struct tstream_cli_np *cli_nps =
228                 talloc_get_type(_tstream_context_data(stream),
229                 struct tstream_cli_np);
230
231         if (!cli_nps) {
232                 return false;
233         }
234
235         return true;
236 }
237
238 NTSTATUS tstream_cli_np_use_trans(struct tstream_context *stream)
239 {
240         struct tstream_cli_np *cli_nps = tstream_context_data(stream,
241                                          struct tstream_cli_np);
242
243         if (cli_nps->trans.read_req) {
244                 return NT_STATUS_PIPE_BUSY;
245         }
246
247         if (cli_nps->trans.write_req) {
248                 return NT_STATUS_PIPE_BUSY;
249         }
250
251         if (cli_nps->trans.active) {
252                 return NT_STATUS_PIPE_BUSY;
253         }
254
255         cli_nps->trans.active = true;
256
257         return NT_STATUS_OK;
258 }
259
260 unsigned int tstream_cli_np_set_timeout(struct tstream_context *stream,
261                                         unsigned int timeout)
262 {
263         struct tstream_cli_np *cli_nps = tstream_context_data(stream,
264                                          struct tstream_cli_np);
265
266         if (!cli_state_is_connected(cli_nps->cli)) {
267                 return cli_nps->default_timeout;
268         }
269
270         return cli_set_timeout(cli_nps->cli, timeout);
271 }
272
273 struct cli_state *tstream_cli_np_get_cli_state(struct tstream_context *stream)
274 {
275         struct tstream_cli_np *cli_nps = tstream_context_data(stream,
276                                          struct tstream_cli_np);
277
278         return cli_nps->cli;
279 }
280
281 struct tstream_cli_np_writev_state {
282         struct tstream_context *stream;
283         struct tevent_context *ev;
284
285         struct iovec *vector;
286         size_t count;
287
288         int ret;
289
290         struct {
291                 int val;
292                 const char *location;
293         } error;
294 };
295
296 static int tstream_cli_np_writev_state_destructor(struct tstream_cli_np_writev_state *state)
297 {
298         struct tstream_cli_np *cli_nps =
299                 tstream_context_data(state->stream,
300                 struct tstream_cli_np);
301
302         cli_nps->trans.write_req = NULL;
303
304         return 0;
305 }
306
307 static void tstream_cli_np_writev_write_next(struct tevent_req *req);
308
309 static struct tevent_req *tstream_cli_np_writev_send(TALLOC_CTX *mem_ctx,
310                                         struct tevent_context *ev,
311                                         struct tstream_context *stream,
312                                         const struct iovec *vector,
313                                         size_t count)
314 {
315         struct tevent_req *req;
316         struct tstream_cli_np_writev_state *state;
317         struct tstream_cli_np *cli_nps = tstream_context_data(stream,
318                                          struct tstream_cli_np);
319
320         req = tevent_req_create(mem_ctx, &state,
321                                 struct tstream_cli_np_writev_state);
322         if (!req) {
323                 return NULL;
324         }
325         state->stream = stream;
326         state->ev = ev;
327         state->ret = 0;
328
329         talloc_set_destructor(state, tstream_cli_np_writev_state_destructor);
330
331         if (!cli_state_is_connected(cli_nps->cli)) {
332                 tevent_req_error(req, ENOTCONN);
333                 return tevent_req_post(req, ev);
334         }
335
336         /*
337          * we make a copy of the vector so we can change the structure
338          */
339         state->vector = talloc_array(state, struct iovec, count);
340         if (tevent_req_nomem(state->vector, req)) {
341                 return tevent_req_post(req, ev);
342         }
343         memcpy(state->vector, vector, sizeof(struct iovec) * count);
344         state->count = count;
345
346         tstream_cli_np_writev_write_next(req);
347         if (!tevent_req_is_in_progress(req)) {
348                 return tevent_req_post(req, ev);
349         }
350
351         return req;
352 }
353
354 static void tstream_cli_np_readv_trans_start(struct tevent_req *req);
355 static void tstream_cli_np_writev_write_done(struct tevent_req *subreq);
356
357 static void tstream_cli_np_writev_write_next(struct tevent_req *req)
358 {
359         struct tstream_cli_np_writev_state *state =
360                 tevent_req_data(req,
361                 struct tstream_cli_np_writev_state);
362         struct tstream_cli_np *cli_nps =
363                 tstream_context_data(state->stream,
364                 struct tstream_cli_np);
365         struct tevent_req *subreq;
366
367         cli_nps->write.ofs = 0;
368         cli_nps->write.left = TSTREAM_CLI_NP_BUF_SIZE;
369
370         /*
371          * copy the pending buffer first
372          */
373         while (cli_nps->write.left > 0 && state->count > 0) {
374                 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
375                 size_t len = MIN(cli_nps->write.left, state->vector[0].iov_len);
376
377                 memcpy(cli_nps->write.buf + cli_nps->write.ofs, base, len);
378
379                 base += len;
380                 state->vector[0].iov_base = base;
381                 state->vector[0].iov_len -= len;
382
383                 cli_nps->write.ofs += len;
384                 cli_nps->write.left -= len;
385
386                 if (state->vector[0].iov_len == 0) {
387                         state->vector += 1;
388                         state->count -= 1;
389                 }
390
391                 state->ret += len;
392         }
393
394         if (cli_nps->write.ofs == 0) {
395                 tevent_req_done(req);
396                 return;
397         }
398
399         if (cli_nps->trans.active && state->count == 0) {
400                 cli_nps->trans.active = false;
401                 cli_nps->trans.write_req = req;
402                 return;
403         }
404
405         if (cli_nps->trans.read_req && state->count == 0) {
406                 cli_nps->trans.write_req = req;
407                 tstream_cli_np_readv_trans_start(cli_nps->trans.read_req);
408                 return;
409         }
410
411         subreq = cli_write_andx_send(state, state->ev, cli_nps->cli,
412                                      cli_nps->fnum,
413                                      8, /* 8 means message mode. */
414                                      cli_nps->write.buf, 0,
415                                      cli_nps->write.ofs);
416         if (tevent_req_nomem(subreq, req)) {
417                 return;
418         }
419         tevent_req_set_callback(subreq,
420                                 tstream_cli_np_writev_write_done,
421                                 req);
422 }
423
424 static void tstream_cli_np_writev_disconnect_now(struct tevent_req *req,
425                                                  int error,
426                                                  const char *location);
427
428 static void tstream_cli_np_writev_write_done(struct tevent_req *subreq)
429 {
430         struct tevent_req *req =
431                 tevent_req_callback_data(subreq, struct tevent_req);
432         struct tstream_cli_np_writev_state *state =
433                 tevent_req_data(req, struct tstream_cli_np_writev_state);
434         struct tstream_cli_np *cli_nps =
435                 tstream_context_data(state->stream,
436                 struct tstream_cli_np);
437         size_t written;
438         NTSTATUS status;
439
440         status = cli_write_andx_recv(subreq, &written);
441         TALLOC_FREE(subreq);
442         if (!NT_STATUS_IS_OK(status)) {
443                 tstream_cli_np_writev_disconnect_now(req, EIO, __location__);
444                 return;
445         }
446
447         if (written != cli_nps->write.ofs) {
448                 tstream_cli_np_writev_disconnect_now(req, EIO, __location__);
449                 return;
450         }
451
452         tstream_cli_np_writev_write_next(req);
453 }
454
455 static void tstream_cli_np_writev_disconnect_done(struct tevent_req *subreq);
456
457 static void tstream_cli_np_writev_disconnect_now(struct tevent_req *req,
458                                                  int error,
459                                                  const char *location)
460 {
461         struct tstream_cli_np_writev_state *state =
462                 tevent_req_data(req,
463                 struct tstream_cli_np_writev_state);
464         struct tstream_cli_np *cli_nps =
465                 tstream_context_data(state->stream,
466                 struct tstream_cli_np);
467         struct tevent_req *subreq;
468
469         state->error.val = error;
470         state->error.location = location;
471
472         if (!cli_state_is_connected(cli_nps->cli)) {
473                 /* return the original error */
474                 _tevent_req_error(req, state->error.val, state->error.location);
475                 return;
476         }
477
478         subreq = cli_close_send(state, state->ev, cli_nps->cli, cli_nps->fnum);
479         if (subreq == NULL) {
480                 /* return the original error */
481                 _tevent_req_error(req, state->error.val, state->error.location);
482                 return;
483         }
484         tevent_req_set_callback(subreq,
485                                 tstream_cli_np_writev_disconnect_done,
486                                 req);
487 }
488
489 static void tstream_cli_np_writev_disconnect_done(struct tevent_req *subreq)
490 {
491         struct tevent_req *req =
492                 tevent_req_callback_data(subreq, struct tevent_req);
493         struct tstream_cli_np_writev_state *state =
494                 tevent_req_data(req, struct tstream_cli_np_writev_state);
495         struct tstream_cli_np *cli_nps =
496                 tstream_context_data(state->stream, struct tstream_cli_np);
497
498         cli_close_recv(subreq);
499         TALLOC_FREE(subreq);
500
501         cli_nps->cli = NULL;
502
503         /* return the original error */
504         _tevent_req_error(req, state->error.val, state->error.location);
505 }
506
507 static int tstream_cli_np_writev_recv(struct tevent_req *req,
508                                       int *perrno)
509 {
510         struct tstream_cli_np_writev_state *state =
511                 tevent_req_data(req,
512                 struct tstream_cli_np_writev_state);
513         int ret;
514
515         ret = tsocket_simple_int_recv(req, perrno);
516         if (ret == 0) {
517                 ret = state->ret;
518         }
519
520         tevent_req_received(req);
521         return ret;
522 }
523
524 struct tstream_cli_np_readv_state {
525         struct tstream_context *stream;
526         struct tevent_context *ev;
527
528         struct iovec *vector;
529         size_t count;
530
531         int ret;
532
533         struct {
534                 struct tevent_immediate *im;
535         } trans;
536
537         struct {
538                 int val;
539                 const char *location;
540         } error;
541 };
542
543 static int tstream_cli_np_readv_state_destructor(struct tstream_cli_np_readv_state *state)
544 {
545         struct tstream_cli_np *cli_nps =
546                 tstream_context_data(state->stream,
547                 struct tstream_cli_np);
548
549         cli_nps->trans.read_req = NULL;
550
551         return 0;
552 }
553
554 static void tstream_cli_np_readv_read_next(struct tevent_req *req);
555
556 static struct tevent_req *tstream_cli_np_readv_send(TALLOC_CTX *mem_ctx,
557                                         struct tevent_context *ev,
558                                         struct tstream_context *stream,
559                                         struct iovec *vector,
560                                         size_t count)
561 {
562         struct tevent_req *req;
563         struct tstream_cli_np_readv_state *state;
564         struct tstream_cli_np *cli_nps =
565                 tstream_context_data(stream, struct tstream_cli_np);
566
567         req = tevent_req_create(mem_ctx, &state,
568                                 struct tstream_cli_np_readv_state);
569         if (!req) {
570                 return NULL;
571         }
572         state->stream = stream;
573         state->ev = ev;
574         state->ret = 0;
575
576         talloc_set_destructor(state, tstream_cli_np_readv_state_destructor);
577
578         if (!cli_state_is_connected(cli_nps->cli)) {
579                 tevent_req_error(req, ENOTCONN);
580                 return tevent_req_post(req, ev);
581         }
582
583         /*
584          * we make a copy of the vector so we can change the structure
585          */
586         state->vector = talloc_array(state, struct iovec, count);
587         if (tevent_req_nomem(state->vector, req)) {
588                 return tevent_req_post(req, ev);
589         }
590         memcpy(state->vector, vector, sizeof(struct iovec) * count);
591         state->count = count;
592
593         tstream_cli_np_readv_read_next(req);
594         if (!tevent_req_is_in_progress(req)) {
595                 return tevent_req_post(req, ev);
596         }
597
598         return req;
599 }
600
601 static void tstream_cli_np_readv_read_done(struct tevent_req *subreq);
602
603 static void tstream_cli_np_readv_read_next(struct tevent_req *req)
604 {
605         struct tstream_cli_np_readv_state *state =
606                 tevent_req_data(req,
607                 struct tstream_cli_np_readv_state);
608         struct tstream_cli_np *cli_nps =
609                 tstream_context_data(state->stream,
610                 struct tstream_cli_np);
611         struct tevent_req *subreq;
612
613         /*
614          * copy the pending buffer first
615          */
616         while (cli_nps->read.left > 0 && state->count > 0) {
617                 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
618                 size_t len = MIN(cli_nps->read.left, state->vector[0].iov_len);
619
620                 memcpy(base, cli_nps->read.buf + cli_nps->read.ofs, len);
621
622                 base += len;
623                 state->vector[0].iov_base = base;
624                 state->vector[0].iov_len -= len;
625
626                 cli_nps->read.ofs += len;
627                 cli_nps->read.left -= len;
628
629                 if (state->vector[0].iov_len == 0) {
630                         state->vector += 1;
631                         state->count -= 1;
632                 }
633
634                 state->ret += len;
635         }
636
637         if (state->count == 0) {
638                 tevent_req_done(req);
639                 return;
640         }
641
642         if (cli_nps->trans.active) {
643                 cli_nps->trans.active = false;
644                 cli_nps->trans.read_req = req;
645                 return;
646         }
647
648         if (cli_nps->trans.write_req) {
649                 cli_nps->trans.read_req = req;
650                 tstream_cli_np_readv_trans_start(req);
651                 return;
652         }
653
654         subreq = cli_read_andx_send(state, state->ev, cli_nps->cli,
655                                     cli_nps->fnum, 0, TSTREAM_CLI_NP_BUF_SIZE);
656         if (tevent_req_nomem(subreq, req)) {
657                 return;
658         }
659         tevent_req_set_callback(subreq,
660                                 tstream_cli_np_readv_read_done,
661                                 req);
662 }
663
664 static void tstream_cli_np_readv_trans_done(struct tevent_req *subreq);
665
666 static void tstream_cli_np_readv_trans_start(struct tevent_req *req)
667 {
668         struct tstream_cli_np_readv_state *state =
669                 tevent_req_data(req,
670                 struct tstream_cli_np_readv_state);
671         struct tstream_cli_np *cli_nps =
672                 tstream_context_data(state->stream,
673                 struct tstream_cli_np);
674         struct tevent_req *subreq;
675
676         state->trans.im = tevent_create_immediate(state);
677         if (tevent_req_nomem(state->trans.im, req)) {
678                 return;
679         }
680
681         subreq = cli_trans_send(state, state->ev,
682                                 cli_nps->cli,
683                                 SMBtrans,
684                                 "\\PIPE\\",
685                                 0, 0, 0,
686                                 cli_nps->trans.setup, 2,
687                                 0,
688                                 NULL, 0, 0,
689                                 cli_nps->write.buf,
690                                 cli_nps->write.ofs,
691                                 TSTREAM_CLI_NP_BUF_SIZE);
692         if (tevent_req_nomem(subreq, req)) {
693                 return;
694         }
695         tevent_req_set_callback(subreq,
696                                 tstream_cli_np_readv_trans_done,
697                                 req);
698 }
699
700 static void tstream_cli_np_readv_disconnect_now(struct tevent_req *req,
701                                                 int error,
702                                                 const char *location);
703 static void tstream_cli_np_readv_trans_next(struct tevent_context *ctx,
704                                             struct tevent_immediate *im,
705                                             void *private_data);
706
707 static void tstream_cli_np_readv_trans_done(struct tevent_req *subreq)
708 {
709         struct tevent_req *req =
710                 tevent_req_callback_data(subreq, struct tevent_req);
711         struct tstream_cli_np_readv_state *state =
712                 tevent_req_data(req, struct tstream_cli_np_readv_state);
713         struct tstream_cli_np *cli_nps =
714                 tstream_context_data(state->stream, struct tstream_cli_np);
715         uint8_t *rcvbuf;
716         uint32_t received;
717         NTSTATUS status;
718
719         status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
720                                 NULL, 0, NULL,
721                                 &rcvbuf, 0, &received);
722         TALLOC_FREE(subreq);
723         if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
724                 status = NT_STATUS_OK;
725         }
726         if (!NT_STATUS_IS_OK(status)) {
727                 tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
728                 return;
729         }
730
731         if (received > TSTREAM_CLI_NP_BUF_SIZE) {
732                 tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
733                 return;
734         }
735
736         if (received == 0) {
737                 tstream_cli_np_readv_disconnect_now(req, EPIPE, __location__);
738                 return;
739         }
740
741         cli_nps->read.ofs = 0;
742         cli_nps->read.left = received;
743         memcpy(cli_nps->read.buf, rcvbuf, received);
744         TALLOC_FREE(rcvbuf);
745
746         if (cli_nps->trans.write_req == NULL) {
747                 tstream_cli_np_readv_read_next(req);
748                 return;
749         }
750
751         tevent_schedule_immediate(state->trans.im, state->ev,
752                                   tstream_cli_np_readv_trans_next, req);
753
754         tevent_req_done(cli_nps->trans.write_req);
755 }
756
757 static void tstream_cli_np_readv_trans_next(struct tevent_context *ctx,
758                                             struct tevent_immediate *im,
759                                             void *private_data)
760 {
761         struct tevent_req *req =
762                 talloc_get_type_abort(private_data,
763                 struct tevent_req);
764
765         tstream_cli_np_readv_read_next(req);
766 }
767
768 static void tstream_cli_np_readv_read_done(struct tevent_req *subreq)
769 {
770         struct tevent_req *req =
771                 tevent_req_callback_data(subreq, struct tevent_req);
772         struct tstream_cli_np_readv_state *state =
773                 tevent_req_data(req, struct tstream_cli_np_readv_state);
774         struct tstream_cli_np *cli_nps =
775                 tstream_context_data(state->stream, struct tstream_cli_np);
776         uint8_t *rcvbuf;
777         ssize_t received;
778         NTSTATUS status;
779
780         /*
781          * We must free subreq in this function as there is
782          * a timer event attached to it.
783          */
784
785         status = cli_read_andx_recv(subreq, &received, &rcvbuf);
786         /*
787          * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
788          * child of that.
789          */
790         if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
791                 /*
792                  * NT_STATUS_BUFFER_TOO_SMALL means that there's
793                  * more data to read when the named pipe is used
794                  * in message mode (which is the case here).
795                  *
796                  * But we hide this from the caller.
797                  */
798                 status = NT_STATUS_OK;
799         }
800         if (!NT_STATUS_IS_OK(status)) {
801                 TALLOC_FREE(subreq);
802                 tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
803                 return;
804         }
805
806         if (received > TSTREAM_CLI_NP_BUF_SIZE) {
807                 TALLOC_FREE(subreq);
808                 tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
809                 return;
810         }
811
812         if (received == 0) {
813                 TALLOC_FREE(subreq);
814                 tstream_cli_np_readv_disconnect_now(req, EPIPE, __location__);
815                 return;
816         }
817
818         cli_nps->read.ofs = 0;
819         cli_nps->read.left = received;
820         memcpy(cli_nps->read.buf, rcvbuf, received);
821         TALLOC_FREE(subreq);
822
823         tstream_cli_np_readv_read_next(req);
824 }
825
826 static void tstream_cli_np_readv_disconnect_done(struct tevent_req *subreq);
827
828 static void tstream_cli_np_readv_error(struct tevent_req *req);
829
830 static void tstream_cli_np_readv_disconnect_now(struct tevent_req *req,
831                                                 int error,
832                                                 const char *location)
833 {
834         struct tstream_cli_np_readv_state *state =
835                 tevent_req_data(req,
836                 struct tstream_cli_np_readv_state);
837         struct tstream_cli_np *cli_nps =
838                 tstream_context_data(state->stream,
839                 struct tstream_cli_np);
840         struct tevent_req *subreq;
841
842         state->error.val = error;
843         state->error.location = location;
844
845         if (!cli_state_is_connected(cli_nps->cli)) {
846                 /* return the original error */
847                 tstream_cli_np_readv_error(req);
848                 return;
849         }
850
851         subreq = cli_close_send(state, state->ev, cli_nps->cli, cli_nps->fnum);
852         if (subreq == NULL) {
853                 /* return the original error */
854                 tstream_cli_np_readv_error(req);
855                 return;
856         }
857         tevent_req_set_callback(subreq,
858                                 tstream_cli_np_readv_disconnect_done,
859                                 req);
860 }
861
862 static void tstream_cli_np_readv_disconnect_done(struct tevent_req *subreq)
863 {
864         struct tevent_req *req =
865                 tevent_req_callback_data(subreq, struct tevent_req);
866         struct tstream_cli_np_readv_state *state =
867                 tevent_req_data(req, struct tstream_cli_np_readv_state);
868         struct tstream_cli_np *cli_nps =
869                 tstream_context_data(state->stream, struct tstream_cli_np);
870
871         cli_close_recv(subreq);
872         TALLOC_FREE(subreq);
873
874         cli_nps->cli = NULL;
875
876         tstream_cli_np_readv_error(req);
877 }
878
879 static void tstream_cli_np_readv_error_trigger(struct tevent_context *ctx,
880                                                struct tevent_immediate *im,
881                                                void *private_data);
882
883 static void tstream_cli_np_readv_error(struct tevent_req *req)
884 {
885         struct tstream_cli_np_readv_state *state =
886                 tevent_req_data(req,
887                 struct tstream_cli_np_readv_state);
888         struct tstream_cli_np *cli_nps =
889                 tstream_context_data(state->stream,
890                 struct tstream_cli_np);
891
892         if (cli_nps->trans.write_req == NULL) {
893                 /* return the original error */
894                 _tevent_req_error(req, state->error.val, state->error.location);
895                 return;
896         }
897
898         if (state->trans.im == NULL) {
899                 /* return the original error */
900                 _tevent_req_error(req, state->error.val, state->error.location);
901                 return;
902         }
903
904         tevent_schedule_immediate(state->trans.im, state->ev,
905                                   tstream_cli_np_readv_error_trigger, req);
906
907         /* return the original error for writev */
908         _tevent_req_error(cli_nps->trans.write_req,
909                           state->error.val, state->error.location);
910 }
911
912 static void tstream_cli_np_readv_error_trigger(struct tevent_context *ctx,
913                                                struct tevent_immediate *im,
914                                                void *private_data)
915 {
916         struct tevent_req *req =
917                 talloc_get_type_abort(private_data,
918                 struct tevent_req);
919         struct tstream_cli_np_readv_state *state =
920                 tevent_req_data(req,
921                 struct tstream_cli_np_readv_state);
922
923         /* return the original error */
924         _tevent_req_error(req, state->error.val, state->error.location);
925 }
926
927 static int tstream_cli_np_readv_recv(struct tevent_req *req,
928                                    int *perrno)
929 {
930         struct tstream_cli_np_readv_state *state =
931                 tevent_req_data(req, struct tstream_cli_np_readv_state);
932         int ret;
933
934         ret = tsocket_simple_int_recv(req, perrno);
935         if (ret == 0) {
936                 ret = state->ret;
937         }
938
939         tevent_req_received(req);
940         return ret;
941 }
942
943 struct tstream_cli_np_disconnect_state {
944         struct tstream_context *stream;
945 };
946
947 static void tstream_cli_np_disconnect_done(struct tevent_req *subreq);
948
949 static struct tevent_req *tstream_cli_np_disconnect_send(TALLOC_CTX *mem_ctx,
950                                                 struct tevent_context *ev,
951                                                 struct tstream_context *stream)
952 {
953         struct tstream_cli_np *cli_nps = tstream_context_data(stream,
954                                          struct tstream_cli_np);
955         struct tevent_req *req;
956         struct tstream_cli_np_disconnect_state *state;
957         struct tevent_req *subreq;
958
959         req = tevent_req_create(mem_ctx, &state,
960                                 struct tstream_cli_np_disconnect_state);
961         if (req == NULL) {
962                 return NULL;
963         }
964
965         state->stream = stream;
966
967         if (!cli_state_is_connected(cli_nps->cli)) {
968                 tevent_req_error(req, ENOTCONN);
969                 return tevent_req_post(req, ev);
970         }
971
972         subreq = cli_close_send(state, ev, cli_nps->cli, cli_nps->fnum);
973         if (tevent_req_nomem(subreq, req)) {
974                 return tevent_req_post(req, ev);
975         }
976         tevent_req_set_callback(subreq, tstream_cli_np_disconnect_done, req);
977
978         return req;
979 }
980
981 static void tstream_cli_np_disconnect_done(struct tevent_req *subreq)
982 {
983         struct tevent_req *req = tevent_req_callback_data(subreq,
984                                                           struct tevent_req);
985         struct tstream_cli_np_disconnect_state *state =
986                 tevent_req_data(req, struct tstream_cli_np_disconnect_state);
987         struct tstream_cli_np *cli_nps =
988                 tstream_context_data(state->stream, struct tstream_cli_np);
989         NTSTATUS status;
990
991         status = cli_close_recv(subreq);
992         TALLOC_FREE(subreq);
993         if (!NT_STATUS_IS_OK(status)) {
994                 tevent_req_error(req, EIO);
995                 return;
996         }
997
998         cli_nps->cli = NULL;
999
1000         tevent_req_done(req);
1001 }
1002
1003 static int tstream_cli_np_disconnect_recv(struct tevent_req *req,
1004                                           int *perrno)
1005 {
1006         int ret;
1007
1008         ret = tsocket_simple_int_recv(req, perrno);
1009
1010         tevent_req_received(req);
1011         return ret;
1012 }
1013
1014 static const struct tstream_context_ops tstream_cli_np_ops = {
1015         .name                   = "cli_np",
1016
1017         .pending_bytes          = tstream_cli_np_pending_bytes,
1018
1019         .readv_send             = tstream_cli_np_readv_send,
1020         .readv_recv             = tstream_cli_np_readv_recv,
1021
1022         .writev_send            = tstream_cli_np_writev_send,
1023         .writev_recv            = tstream_cli_np_writev_recv,
1024
1025         .disconnect_send        = tstream_cli_np_disconnect_send,
1026         .disconnect_recv        = tstream_cli_np_disconnect_recv,
1027 };
1028
1029 NTSTATUS _tstream_cli_np_existing(TALLOC_CTX *mem_ctx,
1030                                   struct cli_state *cli,
1031                                   uint16_t fnum,
1032                                   struct tstream_context **_stream,
1033                                   const char *location)
1034 {
1035         struct tstream_context *stream;
1036         struct tstream_cli_np *cli_nps;
1037
1038         stream = tstream_context_create(mem_ctx,
1039                                         &tstream_cli_np_ops,
1040                                         &cli_nps,
1041                                         struct tstream_cli_np,
1042                                         location);
1043         if (!stream) {
1044                 return NT_STATUS_NO_MEMORY;
1045         }
1046         ZERO_STRUCTP(cli_nps);
1047
1048         cli_nps->cli = cli;
1049         cli_nps->fnum = fnum;
1050
1051         *_stream = stream;
1052         return NT_STATUS_OK;
1053 }