libcli/smb/smbXcli: maintain smb2 channel_signing_key separate from the signing_key
[nivanova/samba-autobuild/.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_MAX_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;
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 = cli_set_timeout(state->cli, 0);
198         cli_set_timeout(state->cli, cli_nps->default_timeout);
199
200         talloc_set_destructor(cli_nps, tstream_cli_np_destructor);
201
202         cli_nps->trans.active = false;
203         cli_nps->trans.read_req = NULL;
204         cli_nps->trans.write_req = NULL;
205         SSVAL(cli_nps->trans.setup+0, 0, TRANSACT_DCERPCCMD);
206         SSVAL(cli_nps->trans.setup+1, 0, cli_nps->fnum);
207
208         *_stream = stream;
209         tevent_req_received(req);
210         return NT_STATUS_OK;
211 }
212
213 static ssize_t tstream_cli_np_pending_bytes(struct tstream_context *stream)
214 {
215         struct tstream_cli_np *cli_nps = tstream_context_data(stream,
216                                          struct tstream_cli_np);
217
218         if (!cli_state_is_connected(cli_nps->cli)) {
219                 errno = ENOTCONN;
220                 return -1;
221         }
222
223         return cli_nps->read.left;
224 }
225
226 bool tstream_is_cli_np(struct tstream_context *stream)
227 {
228         struct tstream_cli_np *cli_nps =
229                 talloc_get_type(_tstream_context_data(stream),
230                 struct tstream_cli_np);
231
232         if (!cli_nps) {
233                 return false;
234         }
235
236         return true;
237 }
238
239 NTSTATUS tstream_cli_np_use_trans(struct tstream_context *stream)
240 {
241         struct tstream_cli_np *cli_nps = tstream_context_data(stream,
242                                          struct tstream_cli_np);
243
244         if (cli_nps->trans.read_req) {
245                 return NT_STATUS_PIPE_BUSY;
246         }
247
248         if (cli_nps->trans.write_req) {
249                 return NT_STATUS_PIPE_BUSY;
250         }
251
252         if (cli_nps->trans.active) {
253                 return NT_STATUS_PIPE_BUSY;
254         }
255
256         cli_nps->trans.active = true;
257
258         return NT_STATUS_OK;
259 }
260
261 unsigned int tstream_cli_np_set_timeout(struct tstream_context *stream,
262                                         unsigned int timeout)
263 {
264         struct tstream_cli_np *cli_nps = tstream_context_data(stream,
265                                          struct tstream_cli_np);
266
267         if (!cli_state_is_connected(cli_nps->cli)) {
268                 return cli_nps->default_timeout;
269         }
270
271         return cli_set_timeout(cli_nps->cli, timeout);
272 }
273
274 struct cli_state *tstream_cli_np_get_cli_state(struct tstream_context *stream)
275 {
276         struct tstream_cli_np *cli_nps = tstream_context_data(stream,
277                                          struct tstream_cli_np);
278
279         return cli_nps->cli;
280 }
281
282 struct tstream_cli_np_writev_state {
283         struct tstream_context *stream;
284         struct tevent_context *ev;
285
286         struct iovec *vector;
287         size_t count;
288
289         int ret;
290
291         struct {
292                 int val;
293                 const char *location;
294         } error;
295 };
296
297 static int tstream_cli_np_writev_state_destructor(struct tstream_cli_np_writev_state *state)
298 {
299         struct tstream_cli_np *cli_nps =
300                 tstream_context_data(state->stream,
301                 struct tstream_cli_np);
302
303         cli_nps->trans.write_req = NULL;
304
305         return 0;
306 }
307
308 static void tstream_cli_np_writev_write_next(struct tevent_req *req);
309
310 static struct tevent_req *tstream_cli_np_writev_send(TALLOC_CTX *mem_ctx,
311                                         struct tevent_context *ev,
312                                         struct tstream_context *stream,
313                                         const struct iovec *vector,
314                                         size_t count)
315 {
316         struct tevent_req *req;
317         struct tstream_cli_np_writev_state *state;
318         struct tstream_cli_np *cli_nps = tstream_context_data(stream,
319                                          struct tstream_cli_np);
320
321         req = tevent_req_create(mem_ctx, &state,
322                                 struct tstream_cli_np_writev_state);
323         if (!req) {
324                 return NULL;
325         }
326         state->stream = stream;
327         state->ev = ev;
328         state->ret = 0;
329
330         talloc_set_destructor(state, tstream_cli_np_writev_state_destructor);
331
332         if (!cli_state_is_connected(cli_nps->cli)) {
333                 tevent_req_error(req, ENOTCONN);
334                 return tevent_req_post(req, ev);
335         }
336
337         /*
338          * we make a copy of the vector so we can change the structure
339          */
340         state->vector = talloc_array(state, struct iovec, count);
341         if (tevent_req_nomem(state->vector, req)) {
342                 return tevent_req_post(req, ev);
343         }
344         memcpy(state->vector, vector, sizeof(struct iovec) * count);
345         state->count = count;
346
347         tstream_cli_np_writev_write_next(req);
348         if (!tevent_req_is_in_progress(req)) {
349                 return tevent_req_post(req, ev);
350         }
351
352         return req;
353 }
354
355 static void tstream_cli_np_readv_trans_start(struct tevent_req *req);
356 static void tstream_cli_np_writev_write_done(struct tevent_req *subreq);
357
358 static void tstream_cli_np_writev_write_next(struct tevent_req *req)
359 {
360         struct tstream_cli_np_writev_state *state =
361                 tevent_req_data(req,
362                 struct tstream_cli_np_writev_state);
363         struct tstream_cli_np *cli_nps =
364                 tstream_context_data(state->stream,
365                 struct tstream_cli_np);
366         struct tevent_req *subreq;
367         size_t i;
368         size_t left = 0;
369
370         for (i=0; i < state->count; i++) {
371                 left += state->vector[i].iov_len;
372         }
373
374         if (left == 0) {
375                 TALLOC_FREE(cli_nps->write.buf);
376                 tevent_req_done(req);
377                 return;
378         }
379
380         cli_nps->write.ofs = 0;
381         cli_nps->write.left = MIN(left, TSTREAM_CLI_NP_MAX_BUF_SIZE);
382         cli_nps->write.buf = talloc_realloc(cli_nps, cli_nps->write.buf,
383                                             uint8_t, cli_nps->write.left);
384         if (tevent_req_nomem(cli_nps->write.buf, req)) {
385                 return;
386         }
387
388         /*
389          * copy the pending buffer first
390          */
391         while (cli_nps->write.left > 0 && state->count > 0) {
392                 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
393                 size_t len = MIN(cli_nps->write.left, state->vector[0].iov_len);
394
395                 memcpy(cli_nps->write.buf + cli_nps->write.ofs, base, len);
396
397                 base += len;
398                 state->vector[0].iov_base = base;
399                 state->vector[0].iov_len -= len;
400
401                 cli_nps->write.ofs += len;
402                 cli_nps->write.left -= len;
403
404                 if (state->vector[0].iov_len == 0) {
405                         state->vector += 1;
406                         state->count -= 1;
407                 }
408
409                 state->ret += len;
410         }
411
412         if (cli_nps->trans.active && state->count == 0) {
413                 cli_nps->trans.active = false;
414                 cli_nps->trans.write_req = req;
415                 return;
416         }
417
418         if (cli_nps->trans.read_req && state->count == 0) {
419                 cli_nps->trans.write_req = req;
420                 tstream_cli_np_readv_trans_start(cli_nps->trans.read_req);
421                 return;
422         }
423
424         subreq = cli_write_andx_send(state, state->ev, cli_nps->cli,
425                                      cli_nps->fnum,
426                                      8, /* 8 means message mode. */
427                                      cli_nps->write.buf, 0,
428                                      cli_nps->write.ofs);
429         if (tevent_req_nomem(subreq, req)) {
430                 return;
431         }
432         tevent_req_set_callback(subreq,
433                                 tstream_cli_np_writev_write_done,
434                                 req);
435 }
436
437 static void tstream_cli_np_writev_disconnect_now(struct tevent_req *req,
438                                                  int error,
439                                                  const char *location);
440
441 static void tstream_cli_np_writev_write_done(struct tevent_req *subreq)
442 {
443         struct tevent_req *req =
444                 tevent_req_callback_data(subreq, struct tevent_req);
445         struct tstream_cli_np_writev_state *state =
446                 tevent_req_data(req, struct tstream_cli_np_writev_state);
447         struct tstream_cli_np *cli_nps =
448                 tstream_context_data(state->stream,
449                 struct tstream_cli_np);
450         size_t written;
451         NTSTATUS status;
452
453         status = cli_write_andx_recv(subreq, &written);
454         TALLOC_FREE(subreq);
455         if (!NT_STATUS_IS_OK(status)) {
456                 tstream_cli_np_writev_disconnect_now(req, EIO, __location__);
457                 return;
458         }
459
460         if (written != cli_nps->write.ofs) {
461                 tstream_cli_np_writev_disconnect_now(req, EIO, __location__);
462                 return;
463         }
464
465         tstream_cli_np_writev_write_next(req);
466 }
467
468 static void tstream_cli_np_writev_disconnect_done(struct tevent_req *subreq);
469
470 static void tstream_cli_np_writev_disconnect_now(struct tevent_req *req,
471                                                  int error,
472                                                  const char *location)
473 {
474         struct tstream_cli_np_writev_state *state =
475                 tevent_req_data(req,
476                 struct tstream_cli_np_writev_state);
477         struct tstream_cli_np *cli_nps =
478                 tstream_context_data(state->stream,
479                 struct tstream_cli_np);
480         struct tevent_req *subreq;
481
482         state->error.val = error;
483         state->error.location = location;
484
485         if (!cli_state_is_connected(cli_nps->cli)) {
486                 /* return the original error */
487                 _tevent_req_error(req, state->error.val, state->error.location);
488                 return;
489         }
490
491         subreq = cli_close_send(state, state->ev, cli_nps->cli, cli_nps->fnum);
492         if (subreq == NULL) {
493                 /* return the original error */
494                 _tevent_req_error(req, state->error.val, state->error.location);
495                 return;
496         }
497         tevent_req_set_callback(subreq,
498                                 tstream_cli_np_writev_disconnect_done,
499                                 req);
500 }
501
502 static void tstream_cli_np_writev_disconnect_done(struct tevent_req *subreq)
503 {
504         struct tevent_req *req =
505                 tevent_req_callback_data(subreq, struct tevent_req);
506         struct tstream_cli_np_writev_state *state =
507                 tevent_req_data(req, struct tstream_cli_np_writev_state);
508         struct tstream_cli_np *cli_nps =
509                 tstream_context_data(state->stream, struct tstream_cli_np);
510
511         cli_close_recv(subreq);
512         TALLOC_FREE(subreq);
513
514         cli_nps->cli = NULL;
515
516         /* return the original error */
517         _tevent_req_error(req, state->error.val, state->error.location);
518 }
519
520 static int tstream_cli_np_writev_recv(struct tevent_req *req,
521                                       int *perrno)
522 {
523         struct tstream_cli_np_writev_state *state =
524                 tevent_req_data(req,
525                 struct tstream_cli_np_writev_state);
526         int ret;
527
528         ret = tsocket_simple_int_recv(req, perrno);
529         if (ret == 0) {
530                 ret = state->ret;
531         }
532
533         tevent_req_received(req);
534         return ret;
535 }
536
537 struct tstream_cli_np_readv_state {
538         struct tstream_context *stream;
539         struct tevent_context *ev;
540
541         struct iovec *vector;
542         size_t count;
543
544         int ret;
545
546         struct {
547                 struct tevent_immediate *im;
548         } trans;
549
550         struct {
551                 int val;
552                 const char *location;
553         } error;
554 };
555
556 static int tstream_cli_np_readv_state_destructor(struct tstream_cli_np_readv_state *state)
557 {
558         struct tstream_cli_np *cli_nps =
559                 tstream_context_data(state->stream,
560                 struct tstream_cli_np);
561
562         cli_nps->trans.read_req = NULL;
563
564         return 0;
565 }
566
567 static void tstream_cli_np_readv_read_next(struct tevent_req *req);
568
569 static struct tevent_req *tstream_cli_np_readv_send(TALLOC_CTX *mem_ctx,
570                                         struct tevent_context *ev,
571                                         struct tstream_context *stream,
572                                         struct iovec *vector,
573                                         size_t count)
574 {
575         struct tevent_req *req;
576         struct tstream_cli_np_readv_state *state;
577         struct tstream_cli_np *cli_nps =
578                 tstream_context_data(stream, struct tstream_cli_np);
579
580         req = tevent_req_create(mem_ctx, &state,
581                                 struct tstream_cli_np_readv_state);
582         if (!req) {
583                 return NULL;
584         }
585         state->stream = stream;
586         state->ev = ev;
587         state->ret = 0;
588
589         talloc_set_destructor(state, tstream_cli_np_readv_state_destructor);
590
591         if (!cli_state_is_connected(cli_nps->cli)) {
592                 tevent_req_error(req, ENOTCONN);
593                 return tevent_req_post(req, ev);
594         }
595
596         /*
597          * we make a copy of the vector so we can change the structure
598          */
599         state->vector = talloc_array(state, struct iovec, count);
600         if (tevent_req_nomem(state->vector, req)) {
601                 return tevent_req_post(req, ev);
602         }
603         memcpy(state->vector, vector, sizeof(struct iovec) * count);
604         state->count = count;
605
606         tstream_cli_np_readv_read_next(req);
607         if (!tevent_req_is_in_progress(req)) {
608                 return tevent_req_post(req, ev);
609         }
610
611         return req;
612 }
613
614 static void tstream_cli_np_readv_read_done(struct tevent_req *subreq);
615
616 static void tstream_cli_np_readv_read_next(struct tevent_req *req)
617 {
618         struct tstream_cli_np_readv_state *state =
619                 tevent_req_data(req,
620                 struct tstream_cli_np_readv_state);
621         struct tstream_cli_np *cli_nps =
622                 tstream_context_data(state->stream,
623                 struct tstream_cli_np);
624         struct tevent_req *subreq;
625
626         /*
627          * copy the pending buffer first
628          */
629         while (cli_nps->read.left > 0 && state->count > 0) {
630                 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
631                 size_t len = MIN(cli_nps->read.left, state->vector[0].iov_len);
632
633                 memcpy(base, cli_nps->read.buf + cli_nps->read.ofs, len);
634
635                 base += len;
636                 state->vector[0].iov_base = base;
637                 state->vector[0].iov_len -= len;
638
639                 cli_nps->read.ofs += len;
640                 cli_nps->read.left -= len;
641
642                 if (state->vector[0].iov_len == 0) {
643                         state->vector += 1;
644                         state->count -= 1;
645                 }
646
647                 state->ret += len;
648         }
649
650         if (cli_nps->read.left == 0) {
651                 TALLOC_FREE(cli_nps->read.buf);
652         }
653
654         if (state->count == 0) {
655                 tevent_req_done(req);
656                 return;
657         }
658
659         if (cli_nps->trans.active) {
660                 cli_nps->trans.active = false;
661                 cli_nps->trans.read_req = req;
662                 return;
663         }
664
665         if (cli_nps->trans.write_req) {
666                 cli_nps->trans.read_req = req;
667                 tstream_cli_np_readv_trans_start(req);
668                 return;
669         }
670
671         subreq = cli_read_andx_send(state, state->ev, cli_nps->cli,
672                                     cli_nps->fnum, 0, TSTREAM_CLI_NP_MAX_BUF_SIZE);
673         if (tevent_req_nomem(subreq, req)) {
674                 return;
675         }
676         tevent_req_set_callback(subreq,
677                                 tstream_cli_np_readv_read_done,
678                                 req);
679 }
680
681 static void tstream_cli_np_readv_trans_done(struct tevent_req *subreq);
682
683 static void tstream_cli_np_readv_trans_start(struct tevent_req *req)
684 {
685         struct tstream_cli_np_readv_state *state =
686                 tevent_req_data(req,
687                 struct tstream_cli_np_readv_state);
688         struct tstream_cli_np *cli_nps =
689                 tstream_context_data(state->stream,
690                 struct tstream_cli_np);
691         struct tevent_req *subreq;
692
693         state->trans.im = tevent_create_immediate(state);
694         if (tevent_req_nomem(state->trans.im, req)) {
695                 return;
696         }
697
698         subreq = cli_trans_send(state, state->ev,
699                                 cli_nps->cli,
700                                 SMBtrans,
701                                 "\\PIPE\\",
702                                 0, 0, 0,
703                                 cli_nps->trans.setup, 2,
704                                 0,
705                                 NULL, 0, 0,
706                                 cli_nps->write.buf,
707                                 cli_nps->write.ofs,
708                                 TSTREAM_CLI_NP_MAX_BUF_SIZE);
709         if (tevent_req_nomem(subreq, req)) {
710                 return;
711         }
712         tevent_req_set_callback(subreq,
713                                 tstream_cli_np_readv_trans_done,
714                                 req);
715 }
716
717 static void tstream_cli_np_readv_disconnect_now(struct tevent_req *req,
718                                                 int error,
719                                                 const char *location);
720 static void tstream_cli_np_readv_trans_next(struct tevent_context *ctx,
721                                             struct tevent_immediate *im,
722                                             void *private_data);
723
724 static void tstream_cli_np_readv_trans_done(struct tevent_req *subreq)
725 {
726         struct tevent_req *req =
727                 tevent_req_callback_data(subreq, struct tevent_req);
728         struct tstream_cli_np_readv_state *state =
729                 tevent_req_data(req, struct tstream_cli_np_readv_state);
730         struct tstream_cli_np *cli_nps =
731                 tstream_context_data(state->stream, struct tstream_cli_np);
732         uint8_t *rcvbuf;
733         uint32_t received;
734         NTSTATUS status;
735
736         status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
737                                 NULL, 0, NULL,
738                                 &rcvbuf, 0, &received);
739         TALLOC_FREE(subreq);
740         if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
741                 status = NT_STATUS_OK;
742         }
743         if (!NT_STATUS_IS_OK(status)) {
744                 tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
745                 return;
746         }
747
748         if (received > TSTREAM_CLI_NP_MAX_BUF_SIZE) {
749                 tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
750                 return;
751         }
752
753         if (received == 0) {
754                 tstream_cli_np_readv_disconnect_now(req, EPIPE, __location__);
755                 return;
756         }
757
758         cli_nps->read.ofs = 0;
759         cli_nps->read.left = received;
760         cli_nps->read.buf = talloc_move(cli_nps, &rcvbuf);
761
762         if (cli_nps->trans.write_req == NULL) {
763                 tstream_cli_np_readv_read_next(req);
764                 return;
765         }
766
767         tevent_schedule_immediate(state->trans.im, state->ev,
768                                   tstream_cli_np_readv_trans_next, req);
769
770         tevent_req_done(cli_nps->trans.write_req);
771 }
772
773 static void tstream_cli_np_readv_trans_next(struct tevent_context *ctx,
774                                             struct tevent_immediate *im,
775                                             void *private_data)
776 {
777         struct tevent_req *req =
778                 talloc_get_type_abort(private_data,
779                 struct tevent_req);
780
781         tstream_cli_np_readv_read_next(req);
782 }
783
784 static void tstream_cli_np_readv_read_done(struct tevent_req *subreq)
785 {
786         struct tevent_req *req =
787                 tevent_req_callback_data(subreq, struct tevent_req);
788         struct tstream_cli_np_readv_state *state =
789                 tevent_req_data(req, struct tstream_cli_np_readv_state);
790         struct tstream_cli_np *cli_nps =
791                 tstream_context_data(state->stream, struct tstream_cli_np);
792         uint8_t *rcvbuf;
793         ssize_t received;
794         NTSTATUS status;
795
796         /*
797          * We must free subreq in this function as there is
798          * a timer event attached to it.
799          */
800
801         status = cli_read_andx_recv(subreq, &received, &rcvbuf);
802         /*
803          * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
804          * child of that.
805          */
806         if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
807                 /*
808                  * NT_STATUS_BUFFER_TOO_SMALL means that there's
809                  * more data to read when the named pipe is used
810                  * in message mode (which is the case here).
811                  *
812                  * But we hide this from the caller.
813                  */
814                 status = NT_STATUS_OK;
815         }
816         if (!NT_STATUS_IS_OK(status)) {
817                 TALLOC_FREE(subreq);
818                 tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
819                 return;
820         }
821
822         if (received > TSTREAM_CLI_NP_MAX_BUF_SIZE) {
823                 TALLOC_FREE(subreq);
824                 tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
825                 return;
826         }
827
828         if (received == 0) {
829                 TALLOC_FREE(subreq);
830                 tstream_cli_np_readv_disconnect_now(req, EPIPE, __location__);
831                 return;
832         }
833
834         cli_nps->read.ofs = 0;
835         cli_nps->read.left = received;
836         cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received);
837         if (cli_nps->read.buf == NULL) {
838                 TALLOC_FREE(subreq);
839                 tevent_req_nomem(cli_nps->read.buf, req);
840                 return;
841         }
842         memcpy(cli_nps->read.buf, rcvbuf, received);
843         TALLOC_FREE(subreq);
844
845         tstream_cli_np_readv_read_next(req);
846 }
847
848 static void tstream_cli_np_readv_disconnect_done(struct tevent_req *subreq);
849
850 static void tstream_cli_np_readv_error(struct tevent_req *req);
851
852 static void tstream_cli_np_readv_disconnect_now(struct tevent_req *req,
853                                                 int error,
854                                                 const char *location)
855 {
856         struct tstream_cli_np_readv_state *state =
857                 tevent_req_data(req,
858                 struct tstream_cli_np_readv_state);
859         struct tstream_cli_np *cli_nps =
860                 tstream_context_data(state->stream,
861                 struct tstream_cli_np);
862         struct tevent_req *subreq;
863
864         state->error.val = error;
865         state->error.location = location;
866
867         if (!cli_state_is_connected(cli_nps->cli)) {
868                 /* return the original error */
869                 tstream_cli_np_readv_error(req);
870                 return;
871         }
872
873         subreq = cli_close_send(state, state->ev, cli_nps->cli, cli_nps->fnum);
874         if (subreq == NULL) {
875                 /* return the original error */
876                 tstream_cli_np_readv_error(req);
877                 return;
878         }
879         tevent_req_set_callback(subreq,
880                                 tstream_cli_np_readv_disconnect_done,
881                                 req);
882 }
883
884 static void tstream_cli_np_readv_disconnect_done(struct tevent_req *subreq)
885 {
886         struct tevent_req *req =
887                 tevent_req_callback_data(subreq, struct tevent_req);
888         struct tstream_cli_np_readv_state *state =
889                 tevent_req_data(req, struct tstream_cli_np_readv_state);
890         struct tstream_cli_np *cli_nps =
891                 tstream_context_data(state->stream, struct tstream_cli_np);
892
893         cli_close_recv(subreq);
894         TALLOC_FREE(subreq);
895
896         cli_nps->cli = NULL;
897
898         tstream_cli_np_readv_error(req);
899 }
900
901 static void tstream_cli_np_readv_error_trigger(struct tevent_context *ctx,
902                                                struct tevent_immediate *im,
903                                                void *private_data);
904
905 static void tstream_cli_np_readv_error(struct tevent_req *req)
906 {
907         struct tstream_cli_np_readv_state *state =
908                 tevent_req_data(req,
909                 struct tstream_cli_np_readv_state);
910         struct tstream_cli_np *cli_nps =
911                 tstream_context_data(state->stream,
912                 struct tstream_cli_np);
913
914         if (cli_nps->trans.write_req == NULL) {
915                 /* return the original error */
916                 _tevent_req_error(req, state->error.val, state->error.location);
917                 return;
918         }
919
920         if (state->trans.im == NULL) {
921                 /* return the original error */
922                 _tevent_req_error(req, state->error.val, state->error.location);
923                 return;
924         }
925
926         tevent_schedule_immediate(state->trans.im, state->ev,
927                                   tstream_cli_np_readv_error_trigger, req);
928
929         /* return the original error for writev */
930         _tevent_req_error(cli_nps->trans.write_req,
931                           state->error.val, state->error.location);
932 }
933
934 static void tstream_cli_np_readv_error_trigger(struct tevent_context *ctx,
935                                                struct tevent_immediate *im,
936                                                void *private_data)
937 {
938         struct tevent_req *req =
939                 talloc_get_type_abort(private_data,
940                 struct tevent_req);
941         struct tstream_cli_np_readv_state *state =
942                 tevent_req_data(req,
943                 struct tstream_cli_np_readv_state);
944
945         /* return the original error */
946         _tevent_req_error(req, state->error.val, state->error.location);
947 }
948
949 static int tstream_cli_np_readv_recv(struct tevent_req *req,
950                                    int *perrno)
951 {
952         struct tstream_cli_np_readv_state *state =
953                 tevent_req_data(req, struct tstream_cli_np_readv_state);
954         int ret;
955
956         ret = tsocket_simple_int_recv(req, perrno);
957         if (ret == 0) {
958                 ret = state->ret;
959         }
960
961         tevent_req_received(req);
962         return ret;
963 }
964
965 struct tstream_cli_np_disconnect_state {
966         struct tstream_context *stream;
967 };
968
969 static void tstream_cli_np_disconnect_done(struct tevent_req *subreq);
970
971 static struct tevent_req *tstream_cli_np_disconnect_send(TALLOC_CTX *mem_ctx,
972                                                 struct tevent_context *ev,
973                                                 struct tstream_context *stream)
974 {
975         struct tstream_cli_np *cli_nps = tstream_context_data(stream,
976                                          struct tstream_cli_np);
977         struct tevent_req *req;
978         struct tstream_cli_np_disconnect_state *state;
979         struct tevent_req *subreq;
980
981         req = tevent_req_create(mem_ctx, &state,
982                                 struct tstream_cli_np_disconnect_state);
983         if (req == NULL) {
984                 return NULL;
985         }
986
987         state->stream = stream;
988
989         if (!cli_state_is_connected(cli_nps->cli)) {
990                 tevent_req_error(req, ENOTCONN);
991                 return tevent_req_post(req, ev);
992         }
993
994         subreq = cli_close_send(state, ev, cli_nps->cli, cli_nps->fnum);
995         if (tevent_req_nomem(subreq, req)) {
996                 return tevent_req_post(req, ev);
997         }
998         tevent_req_set_callback(subreq, tstream_cli_np_disconnect_done, req);
999
1000         return req;
1001 }
1002
1003 static void tstream_cli_np_disconnect_done(struct tevent_req *subreq)
1004 {
1005         struct tevent_req *req = tevent_req_callback_data(subreq,
1006                                                           struct tevent_req);
1007         struct tstream_cli_np_disconnect_state *state =
1008                 tevent_req_data(req, struct tstream_cli_np_disconnect_state);
1009         struct tstream_cli_np *cli_nps =
1010                 tstream_context_data(state->stream, struct tstream_cli_np);
1011         NTSTATUS status;
1012
1013         status = cli_close_recv(subreq);
1014         TALLOC_FREE(subreq);
1015         if (!NT_STATUS_IS_OK(status)) {
1016                 tevent_req_error(req, EIO);
1017                 return;
1018         }
1019
1020         cli_nps->cli = NULL;
1021
1022         tevent_req_done(req);
1023 }
1024
1025 static int tstream_cli_np_disconnect_recv(struct tevent_req *req,
1026                                           int *perrno)
1027 {
1028         int ret;
1029
1030         ret = tsocket_simple_int_recv(req, perrno);
1031
1032         tevent_req_received(req);
1033         return ret;
1034 }
1035
1036 static const struct tstream_context_ops tstream_cli_np_ops = {
1037         .name                   = "cli_np",
1038
1039         .pending_bytes          = tstream_cli_np_pending_bytes,
1040
1041         .readv_send             = tstream_cli_np_readv_send,
1042         .readv_recv             = tstream_cli_np_readv_recv,
1043
1044         .writev_send            = tstream_cli_np_writev_send,
1045         .writev_recv            = tstream_cli_np_writev_recv,
1046
1047         .disconnect_send        = tstream_cli_np_disconnect_send,
1048         .disconnect_recv        = tstream_cli_np_disconnect_recv,
1049 };
1050
1051 NTSTATUS _tstream_cli_np_existing(TALLOC_CTX *mem_ctx,
1052                                   struct cli_state *cli,
1053                                   uint16_t fnum,
1054                                   struct tstream_context **_stream,
1055                                   const char *location)
1056 {
1057         struct tstream_context *stream;
1058         struct tstream_cli_np *cli_nps;
1059
1060         stream = tstream_context_create(mem_ctx,
1061                                         &tstream_cli_np_ops,
1062                                         &cli_nps,
1063                                         struct tstream_cli_np,
1064                                         location);
1065         if (!stream) {
1066                 return NT_STATUS_NO_MEMORY;
1067         }
1068         ZERO_STRUCTP(cli_nps);
1069
1070         cli_nps->cli = cli;
1071         cli_nps->fnum = fnum;
1072
1073         *_stream = stream;
1074         return NT_STATUS_OK;
1075 }