libcli/smb/smb2_signing: pass down 'protocol' to smb2_signing_[sign|check]_pdu()
[nivanova/samba-autobuild/.git] / source3 / libsmb / clireadwrite.c
1 /*
2    Unix SMB/CIFS implementation.
3    client file read/write routines
4    Copyright (C) Andrew Tridgell 1994-1998
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 "libsmb/libsmb.h"
22 #include "../lib/util/tevent_ntstatus.h"
23 #include "async_smb.h"
24 #include "trans2.h"
25
26 /****************************************************************************
27   Calculate the recommended read buffer size
28 ****************************************************************************/
29 static size_t cli_read_max_bufsize(struct cli_state *cli)
30 {
31         uint8_t wct = 12;
32         uint32_t min_space;
33         uint32_t data_offset;
34         uint32_t useable_space = 0;
35
36         data_offset = HDR_VWV;
37         data_offset += wct * sizeof(uint16_t);
38         data_offset += sizeof(uint16_t); /* byte count */
39         data_offset += 1; /* pad */
40
41         min_space = cli_state_available_size(cli, data_offset);
42
43         if (cli->server_posix_capabilities & CIFS_UNIX_LARGE_READ_CAP) {
44                 useable_space = 0xFFFFFF - data_offset;
45
46                 if (client_is_signing_on(cli)) {
47                         return min_space;
48                 }
49
50                 if (cli_state_encryption_on(cli)) {
51                         return min_space;
52                 }
53
54                 return useable_space;
55         } else if (cli_state_capabilities(cli) & CAP_LARGE_READX) {
56                 /*
57                  * Note: CAP_LARGE_READX also works with signing
58                  */
59                 useable_space = 0x1FFFF - data_offset;
60
61                 useable_space = MIN(useable_space, UINT16_MAX);
62
63                 return useable_space;
64         }
65
66         return min_space;
67 }
68
69 /****************************************************************************
70   Calculate the recommended write buffer size
71 ****************************************************************************/
72 static size_t cli_write_max_bufsize(struct cli_state *cli,
73                                     uint16_t write_mode,
74                                     uint8_t wct)
75 {
76         uint32_t min_space;
77         uint32_t data_offset;
78         uint32_t useable_space = 0;
79
80         data_offset = HDR_VWV;
81         data_offset += wct * sizeof(uint16_t);
82         data_offset += sizeof(uint16_t); /* byte count */
83         data_offset += 1; /* pad */
84
85         min_space = cli_state_available_size(cli, data_offset);
86
87         if (cli->server_posix_capabilities & CIFS_UNIX_LARGE_WRITE_CAP) {
88                 useable_space = 0xFFFFFF - data_offset;
89         } else if (cli_state_capabilities(cli) & CAP_LARGE_WRITEX) {
90                 useable_space = 0x1FFFF - data_offset;
91         } else {
92                 return min_space;
93         }
94
95         if (write_mode != 0) {
96                 return min_space;
97         }
98
99         if (client_is_signing_on(cli)) {
100                 return min_space;
101         }
102
103         if (cli_state_encryption_on(cli)) {
104                 return min_space;
105         }
106
107         if (strequal(cli->dev, "LPT1:")) {
108                 return min_space;
109         }
110
111         return useable_space;
112 }
113
114 struct cli_read_andx_state {
115         size_t size;
116         uint16_t vwv[12];
117         NTSTATUS status;
118         size_t received;
119         uint8_t *buf;
120 };
121
122 static void cli_read_andx_done(struct tevent_req *subreq);
123
124 struct tevent_req *cli_read_andx_create(TALLOC_CTX *mem_ctx,
125                                         struct event_context *ev,
126                                         struct cli_state *cli, uint16_t fnum,
127                                         off_t offset, size_t size,
128                                         struct tevent_req **psmbreq)
129 {
130         struct tevent_req *req, *subreq;
131         struct cli_read_andx_state *state;
132         uint8_t wct = 10;
133
134         if (size > cli_read_max_bufsize(cli)) {
135                 DEBUG(0, ("cli_read_andx_send got size=%d, can only handle "
136                           "size=%d\n", (int)size,
137                           (int)cli_read_max_bufsize(cli)));
138                 return NULL;
139         }
140
141         req = tevent_req_create(mem_ctx, &state, struct cli_read_andx_state);
142         if (req == NULL) {
143                 return NULL;
144         }
145         state->size = size;
146
147         SCVAL(state->vwv + 0, 0, 0xFF);
148         SCVAL(state->vwv + 0, 1, 0);
149         SSVAL(state->vwv + 1, 0, 0);
150         SSVAL(state->vwv + 2, 0, fnum);
151         SIVAL(state->vwv + 3, 0, offset);
152         SSVAL(state->vwv + 5, 0, size);
153         SSVAL(state->vwv + 6, 0, size);
154         SSVAL(state->vwv + 7, 0, (size >> 16));
155         SSVAL(state->vwv + 8, 0, 0);
156         SSVAL(state->vwv + 9, 0, 0);
157
158         if (cli_state_capabilities(cli) & CAP_LARGE_FILES) {
159                 SIVAL(state->vwv + 10, 0,
160                       (((uint64_t)offset)>>32) & 0xffffffff);
161                 wct = 12;
162         } else {
163                 if ((((uint64_t)offset) & 0xffffffff00000000LL) != 0) {
164                         DEBUG(10, ("cli_read_andx_send got large offset where "
165                                    "the server does not support it\n"));
166                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
167                         return tevent_req_post(req, ev);
168                 }
169         }
170
171         subreq = cli_smb_req_create(state, ev, cli, SMBreadX, 0, wct,
172                                     state->vwv, 0, NULL);
173         if (subreq == NULL) {
174                 TALLOC_FREE(req);
175                 return NULL;
176         }
177         tevent_req_set_callback(subreq, cli_read_andx_done, req);
178         *psmbreq = subreq;
179         return req;
180 }
181
182 struct tevent_req *cli_read_andx_send(TALLOC_CTX *mem_ctx,
183                                       struct event_context *ev,
184                                       struct cli_state *cli, uint16_t fnum,
185                                       off_t offset, size_t size)
186 {
187         struct tevent_req *req, *subreq;
188         NTSTATUS status;
189
190         req = cli_read_andx_create(mem_ctx, ev, cli, fnum, offset, size,
191                                    &subreq);
192         if (req == NULL) {
193                 return NULL;
194         }
195
196         status = cli_smb_req_send(subreq);
197         if (tevent_req_nterror(req, status)) {
198                 return tevent_req_post(req, ev);
199         }
200         return req;
201 }
202
203 static void cli_read_andx_done(struct tevent_req *subreq)
204 {
205         struct tevent_req *req = tevent_req_callback_data(
206                 subreq, struct tevent_req);
207         struct cli_read_andx_state *state = tevent_req_data(
208                 req, struct cli_read_andx_state);
209         uint8_t *inbuf;
210         uint8_t wct;
211         uint16_t *vwv;
212         uint32_t num_bytes;
213         uint8_t *bytes;
214
215         state->status = cli_smb_recv(subreq, state, &inbuf, 12, &wct, &vwv,
216                                      &num_bytes, &bytes);
217         TALLOC_FREE(subreq);
218         if (NT_STATUS_IS_ERR(state->status)) {
219                 tevent_req_nterror(req, state->status);
220                 return;
221         }
222
223         /* size is the number of bytes the server returned.
224          * Might be zero. */
225         state->received = SVAL(vwv + 5, 0);
226         state->received |= (((unsigned int)SVAL(vwv + 7, 0)) << 16);
227
228         if (state->received > state->size) {
229                 DEBUG(5,("server returned more than we wanted!\n"));
230                 tevent_req_nterror(req, NT_STATUS_UNEXPECTED_IO_ERROR);
231                 return;
232         }
233
234         /*
235          * bcc field must be valid for small reads, for large reads the 16-bit
236          * bcc field can't be correct.
237          */
238
239         if ((state->received < 0xffff) && (state->received > num_bytes)) {
240                 DEBUG(5, ("server announced more bytes than sent\n"));
241                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
242                 return;
243         }
244
245         state->buf = discard_const_p(uint8_t, smb_base(inbuf)) + SVAL(vwv+6, 0);
246
247         if (trans_oob(smb_len_tcp(inbuf), SVAL(vwv+6, 0), state->received)
248             || ((state->received != 0) && (state->buf < bytes))) {
249                 DEBUG(5, ("server returned invalid read&x data offset\n"));
250                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
251                 return;
252         }
253         tevent_req_done(req);
254 }
255
256 /*
257  * Pull the data out of a finished async read_and_x request. rcvbuf is
258  * talloced from the request, so better make sure that you copy it away before
259  * you talloc_free(req). "rcvbuf" is NOT a talloc_ctx of its own, so do not
260  * talloc_move it!
261  */
262
263 NTSTATUS cli_read_andx_recv(struct tevent_req *req, ssize_t *received,
264                             uint8_t **rcvbuf)
265 {
266         struct cli_read_andx_state *state = tevent_req_data(
267                 req, struct cli_read_andx_state);
268         NTSTATUS status;
269
270         if (tevent_req_is_nterror(req, &status)) {
271                 return status;
272         }
273         *received = state->received;
274         *rcvbuf = state->buf;
275         return NT_STATUS_OK;
276 }
277
278 struct cli_readall_state {
279         struct tevent_context *ev;
280         struct cli_state *cli;
281         uint16_t fnum;
282         off_t start_offset;
283         size_t size;
284         size_t received;
285         uint8_t *buf;
286 };
287
288 static void cli_readall_done(struct tevent_req *subreq);
289
290 static struct tevent_req *cli_readall_send(TALLOC_CTX *mem_ctx,
291                                            struct event_context *ev,
292                                            struct cli_state *cli,
293                                            uint16_t fnum,
294                                            off_t offset, size_t size)
295 {
296         struct tevent_req *req, *subreq;
297         struct cli_readall_state *state;
298
299         req = tevent_req_create(mem_ctx, &state, struct cli_readall_state);
300         if (req == NULL) {
301                 return NULL;
302         }
303         state->ev = ev;
304         state->cli = cli;
305         state->fnum = fnum;
306         state->start_offset = offset;
307         state->size = size;
308         state->received = 0;
309         state->buf = NULL;
310
311         subreq = cli_read_andx_send(state, ev, cli, fnum, offset, size);
312         if (tevent_req_nomem(subreq, req)) {
313                 return tevent_req_post(req, ev);
314         }
315         tevent_req_set_callback(subreq, cli_readall_done, req);
316         return req;
317 }
318
319 static void cli_readall_done(struct tevent_req *subreq)
320 {
321         struct tevent_req *req = tevent_req_callback_data(
322                 subreq, struct tevent_req);
323         struct cli_readall_state *state = tevent_req_data(
324                 req, struct cli_readall_state);
325         ssize_t received;
326         uint8_t *buf;
327         NTSTATUS status;
328
329         status = cli_read_andx_recv(subreq, &received, &buf);
330         if (tevent_req_nterror(req, status)) {
331                 return;
332         }
333
334         if (received == 0) {
335                 /* EOF */
336                 tevent_req_done(req);
337                 return;
338         }
339
340         if ((state->received == 0) && (received == state->size)) {
341                 /* Ideal case: Got it all in one run */
342                 state->buf = buf;
343                 state->received += received;
344                 tevent_req_done(req);
345                 return;
346         }
347
348         /*
349          * We got a short read, issue a read for the
350          * rest. Unfortunately we have to allocate the buffer
351          * ourselves now, as our caller expects to receive a single
352          * buffer. cli_read_andx does it from the buffer received from
353          * the net, but with a short read we have to put it together
354          * from several reads.
355          */
356
357         if (state->buf == NULL) {
358                 state->buf = talloc_array(state, uint8_t, state->size);
359                 if (tevent_req_nomem(state->buf, req)) {
360                         return;
361                 }
362         }
363         memcpy(state->buf + state->received, buf, received);
364         state->received += received;
365
366         TALLOC_FREE(subreq);
367
368         if (state->received >= state->size) {
369                 tevent_req_done(req);
370                 return;
371         }
372
373         subreq = cli_read_andx_send(state, state->ev, state->cli, state->fnum,
374                                     state->start_offset + state->received,
375                                     state->size - state->received);
376         if (tevent_req_nomem(subreq, req)) {
377                 return;
378         }
379         tevent_req_set_callback(subreq, cli_readall_done, req);
380 }
381
382 static NTSTATUS cli_readall_recv(struct tevent_req *req, ssize_t *received,
383                                  uint8_t **rcvbuf)
384 {
385         struct cli_readall_state *state = tevent_req_data(
386                 req, struct cli_readall_state);
387         NTSTATUS status;
388
389         if (tevent_req_is_nterror(req, &status)) {
390                 return status;
391         }
392         *received = state->received;
393         *rcvbuf = state->buf;
394         return NT_STATUS_OK;
395 }
396
397 struct cli_pull_subreq {
398         struct tevent_req *req;
399         ssize_t received;
400         uint8_t *buf;
401 };
402
403 /*
404  * Parallel read support.
405  *
406  * cli_pull sends as many read&x requests as the server would allow via
407  * max_mux at a time. When replies flow back in, the data is written into
408  * the callback function "sink" in the right order.
409  */
410
411 struct cli_pull_state {
412         struct tevent_req *req;
413
414         struct event_context *ev;
415         struct cli_state *cli;
416         uint16_t fnum;
417         off_t start_offset;
418         SMB_OFF_T size;
419
420         NTSTATUS (*sink)(char *buf, size_t n, void *priv);
421         void *priv;
422
423         size_t chunk_size;
424
425         /*
426          * Outstanding requests
427          */
428         uint16_t max_reqs;
429         int num_reqs;
430         struct cli_pull_subreq *reqs;
431
432         /*
433          * For how many bytes did we send requests already?
434          */
435         SMB_OFF_T requested;
436
437         /*
438          * Next request index to push into "sink". This walks around the "req"
439          * array, taking care that the requests are pushed to "sink" in the
440          * right order. If necessary (i.e. replies don't come in in the right
441          * order), replies are held back in "reqs".
442          */
443         int top_req;
444
445         /*
446          * How many bytes did we push into "sink"?
447          */
448
449         SMB_OFF_T pushed;
450 };
451
452 static char *cli_pull_print(struct tevent_req *req, TALLOC_CTX *mem_ctx)
453 {
454         struct cli_pull_state *state = tevent_req_data(
455                 req, struct cli_pull_state);
456         char *result;
457
458         result = tevent_req_default_print(req, mem_ctx);
459         if (result == NULL) {
460                 return NULL;
461         }
462
463         return talloc_asprintf_append_buffer(
464                 result, "num_reqs=%d, top_req=%d",
465                 state->num_reqs, state->top_req);
466 }
467
468 static void cli_pull_read_done(struct tevent_req *read_req);
469
470 /*
471  * Prepare an async pull request
472  */
473
474 struct tevent_req *cli_pull_send(TALLOC_CTX *mem_ctx,
475                                  struct event_context *ev,
476                                  struct cli_state *cli,
477                                  uint16_t fnum, off_t start_offset,
478                                  SMB_OFF_T size, size_t window_size,
479                                  NTSTATUS (*sink)(char *buf, size_t n,
480                                                   void *priv),
481                                  void *priv)
482 {
483         struct tevent_req *req;
484         struct cli_pull_state *state;
485         int i;
486         size_t page_size = 1024;
487
488         req = tevent_req_create(mem_ctx, &state, struct cli_pull_state);
489         if (req == NULL) {
490                 return NULL;
491         }
492         tevent_req_set_print_fn(req, cli_pull_print);
493         state->req = req;
494
495         state->cli = cli;
496         state->ev = ev;
497         state->fnum = fnum;
498         state->start_offset = start_offset;
499         state->size = size;
500         state->sink = sink;
501         state->priv = priv;
502
503         state->pushed = 0;
504         state->top_req = 0;
505
506         if (size == 0) {
507                 tevent_req_done(req);
508                 return tevent_req_post(req, ev);
509         }
510
511         state->chunk_size = cli_read_max_bufsize(cli);
512         if (state->chunk_size > page_size) {
513                 state->chunk_size &= ~(page_size - 1);
514         }
515
516         state->max_reqs = cli_state_max_requests(cli);
517
518         state->num_reqs = MAX(window_size/state->chunk_size, 1);
519         state->num_reqs = MIN(state->num_reqs, state->max_reqs);
520
521         state->reqs = talloc_zero_array(state, struct cli_pull_subreq,
522                                         state->num_reqs);
523         if (state->reqs == NULL) {
524                 goto failed;
525         }
526
527         state->requested = 0;
528
529         for (i=0; i<state->num_reqs; i++) {
530                 struct cli_pull_subreq *subreq = &state->reqs[i];
531                 SMB_OFF_T size_left;
532                 size_t request_thistime;
533
534                 if (state->requested >= size) {
535                         state->num_reqs = i;
536                         break;
537                 }
538
539                 size_left = size - state->requested;
540                 request_thistime = MIN(size_left, state->chunk_size);
541
542                 subreq->req = cli_readall_send(
543                         state->reqs, ev, cli, fnum,
544                         state->start_offset + state->requested,
545                         request_thistime);
546
547                 if (subreq->req == NULL) {
548                         goto failed;
549                 }
550                 tevent_req_set_callback(subreq->req, cli_pull_read_done, req);
551                 state->requested += request_thistime;
552         }
553         return req;
554
555 failed:
556         TALLOC_FREE(req);
557         return NULL;
558 }
559
560 /*
561  * Handle incoming read replies, push the data into sink and send out new
562  * requests if necessary.
563  */
564
565 static void cli_pull_read_done(struct tevent_req *subreq)
566 {
567         struct tevent_req *req = tevent_req_callback_data(
568                 subreq, struct tevent_req);
569         struct cli_pull_state *state = tevent_req_data(
570                 req, struct cli_pull_state);
571         struct cli_pull_subreq *pull_subreq = NULL;
572         NTSTATUS status;
573         int i;
574
575         for (i = 0; i < state->num_reqs; i++) {
576                 pull_subreq = &state->reqs[i];
577                 if (subreq == pull_subreq->req) {
578                         break;
579                 }
580         }
581         if (i == state->num_reqs) {
582                 /* Huh -- received something we did not send?? */
583                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
584                 return;
585         }
586
587         status = cli_readall_recv(subreq, &pull_subreq->received,
588                                   &pull_subreq->buf);
589         if (!NT_STATUS_IS_OK(status)) {
590                 tevent_req_nterror(state->req, status);
591                 return;
592         }
593
594         /*
595          * This loop is the one to take care of out-of-order replies. All
596          * pending requests are in state->reqs, state->reqs[top_req] is the
597          * one that is to be pushed next. If however a request later than
598          * top_req is replied to, then we can't push yet. If top_req is
599          * replied to at a later point then, we need to push all the finished
600          * requests.
601          */
602
603         while (state->reqs[state->top_req].req != NULL) {
604                 struct cli_pull_subreq *top_subreq;
605
606                 DEBUG(11, ("cli_pull_read_done: top_req = %d\n",
607                            state->top_req));
608
609                 top_subreq = &state->reqs[state->top_req];
610
611                 if (tevent_req_is_in_progress(top_subreq->req)) {
612                         DEBUG(11, ("cli_pull_read_done: top request not yet "
613                                    "done\n"));
614                         return;
615                 }
616
617                 DEBUG(10, ("cli_pull_read_done: Pushing %d bytes, %d already "
618                            "pushed\n", (int)top_subreq->received,
619                            (int)state->pushed));
620
621                 status = state->sink((char *)top_subreq->buf,
622                                      top_subreq->received, state->priv);
623                 if (tevent_req_nterror(state->req, status)) {
624                         return;
625                 }
626                 state->pushed += top_subreq->received;
627
628                 TALLOC_FREE(state->reqs[state->top_req].req);
629
630                 if (state->requested < state->size) {
631                         struct tevent_req *new_req;
632                         SMB_OFF_T size_left;
633                         size_t request_thistime;
634
635                         size_left = state->size - state->requested;
636                         request_thistime = MIN(size_left, state->chunk_size);
637
638                         DEBUG(10, ("cli_pull_read_done: Requesting %d bytes "
639                                    "at %d, position %d\n",
640                                    (int)request_thistime,
641                                    (int)(state->start_offset
642                                          + state->requested),
643                                    state->top_req));
644
645                         new_req = cli_readall_send(
646                                 state->reqs, state->ev, state->cli,
647                                 state->fnum,
648                                 state->start_offset + state->requested,
649                                 request_thistime);
650
651                         if (tevent_req_nomem(new_req, state->req)) {
652                                 return;
653                         }
654                         tevent_req_set_callback(new_req, cli_pull_read_done,
655                                                 req);
656
657                         state->reqs[state->top_req].req = new_req;
658                         state->requested += request_thistime;
659                 }
660
661                 state->top_req = (state->top_req+1) % state->num_reqs;
662         }
663
664         tevent_req_done(req);
665 }
666
667 NTSTATUS cli_pull_recv(struct tevent_req *req, SMB_OFF_T *received)
668 {
669         struct cli_pull_state *state = tevent_req_data(
670                 req, struct cli_pull_state);
671         NTSTATUS status;
672
673         if (tevent_req_is_nterror(req, &status)) {
674                 return status;
675         }
676         *received = state->pushed;
677         return NT_STATUS_OK;
678 }
679
680 NTSTATUS cli_pull(struct cli_state *cli, uint16_t fnum,
681                   off_t start_offset, SMB_OFF_T size, size_t window_size,
682                   NTSTATUS (*sink)(char *buf, size_t n, void *priv),
683                   void *priv, SMB_OFF_T *received)
684 {
685         TALLOC_CTX *frame = talloc_stackframe();
686         struct event_context *ev;
687         struct tevent_req *req;
688         NTSTATUS status = NT_STATUS_OK;
689
690         if (cli_has_async_calls(cli)) {
691                 /*
692                  * Can't use sync call while an async call is in flight
693                  */
694                 status = NT_STATUS_INVALID_PARAMETER;
695                 goto fail;
696         }
697
698         ev = event_context_init(frame);
699         if (ev == NULL) {
700                 status = NT_STATUS_NO_MEMORY;
701                 goto fail;
702         }
703
704         req = cli_pull_send(frame, ev, cli, fnum, start_offset, size,
705                             window_size, sink, priv);
706         if (req == NULL) {
707                 status = NT_STATUS_NO_MEMORY;
708                 goto fail;
709         }
710
711         if (!tevent_req_poll(req, ev)) {
712                 status = map_nt_error_from_unix(errno);
713                 goto fail;
714         }
715
716         status = cli_pull_recv(req, received);
717  fail:
718         TALLOC_FREE(frame);
719         return status;
720 }
721
722 static NTSTATUS cli_read_sink(char *buf, size_t n, void *priv)
723 {
724         char **pbuf = (char **)priv;
725         memcpy(*pbuf, buf, n);
726         *pbuf += n;
727         return NT_STATUS_OK;
728 }
729
730 NTSTATUS cli_read(struct cli_state *cli, uint16_t fnum,
731                  char *buf, off_t offset, size_t size,
732                  size_t *nread)
733 {
734         NTSTATUS status;
735         SMB_OFF_T ret;
736
737         status = cli_pull(cli, fnum, offset, size, size,
738                           cli_read_sink, &buf, &ret);
739         if (!NT_STATUS_IS_OK(status)) {
740                 return status;
741         }
742
743         if (nread) {
744                 *nread = ret;
745         }
746
747         return NT_STATUS_OK;
748 }
749
750 /****************************************************************************
751   write to a file using a SMBwrite and not bypassing 0 byte writes
752 ****************************************************************************/
753
754 NTSTATUS cli_smbwrite(struct cli_state *cli, uint16_t fnum, char *buf,
755                       off_t offset, size_t size1, size_t *ptotal)
756 {
757         uint8_t *bytes;
758         ssize_t total = 0;
759
760         /*
761          * 3 bytes prefix
762          */
763
764         bytes = talloc_array(talloc_tos(), uint8_t, 3);
765         if (bytes == NULL) {
766                 return NT_STATUS_NO_MEMORY;
767         }
768         bytes[0] = 1;
769
770         do {
771                 uint32_t usable_space = cli_state_available_size(cli, 48);
772                 size_t size = MIN(size1, usable_space);
773                 struct tevent_req *req;
774                 uint16_t vwv[5];
775                 uint16_t *ret_vwv;
776                 NTSTATUS status;
777
778                 SSVAL(vwv+0, 0, fnum);
779                 SSVAL(vwv+1, 0, size);
780                 SIVAL(vwv+2, 0, offset);
781                 SSVAL(vwv+4, 0, 0);
782
783                 bytes = talloc_realloc(talloc_tos(), bytes, uint8_t,
784                                              size+3);
785                 if (bytes == NULL) {
786                         return NT_STATUS_NO_MEMORY;
787                 }
788                 SSVAL(bytes, 1, size);
789                 memcpy(bytes + 3, buf + total, size);
790
791                 status = cli_smb(talloc_tos(), cli, SMBwrite, 0, 5, vwv,
792                                  size+3, bytes, &req, 1, NULL, &ret_vwv,
793                                  NULL, NULL);
794                 if (!NT_STATUS_IS_OK(status)) {
795                         TALLOC_FREE(bytes);
796                         return status;
797                 }
798
799                 size = SVAL(ret_vwv+0, 0);
800                 TALLOC_FREE(req);
801                 if (size == 0) {
802                         break;
803                 }
804                 size1 -= size;
805                 total += size;
806                 offset += size;
807
808         } while (size1);
809
810         TALLOC_FREE(bytes);
811
812         if (ptotal != NULL) {
813                 *ptotal = total;
814         }
815         return NT_STATUS_OK;
816 }
817
818 /*
819  * Send a write&x request
820  */
821
822 struct cli_write_andx_state {
823         size_t size;
824         uint16_t vwv[14];
825         size_t written;
826         uint8_t pad;
827         struct iovec iov[2];
828 };
829
830 static void cli_write_andx_done(struct tevent_req *subreq);
831
832 struct tevent_req *cli_write_andx_create(TALLOC_CTX *mem_ctx,
833                                          struct event_context *ev,
834                                          struct cli_state *cli, uint16_t fnum,
835                                          uint16_t mode, const uint8_t *buf,
836                                          off_t offset, size_t size,
837                                          struct tevent_req **reqs_before,
838                                          int num_reqs_before,
839                                          struct tevent_req **psmbreq)
840 {
841         struct tevent_req *req, *subreq;
842         struct cli_write_andx_state *state;
843         bool bigoffset = ((cli_state_capabilities(cli) & CAP_LARGE_FILES) != 0);
844         uint8_t wct = bigoffset ? 14 : 12;
845         size_t max_write = cli_write_max_bufsize(cli, mode, wct);
846         uint16_t *vwv;
847
848         req = tevent_req_create(mem_ctx, &state, struct cli_write_andx_state);
849         if (req == NULL) {
850                 return NULL;
851         }
852
853         state->size = MIN(size, max_write);
854
855         vwv = state->vwv;
856
857         SCVAL(vwv+0, 0, 0xFF);
858         SCVAL(vwv+0, 1, 0);
859         SSVAL(vwv+1, 0, 0);
860         SSVAL(vwv+2, 0, fnum);
861         SIVAL(vwv+3, 0, offset);
862         SIVAL(vwv+5, 0, 0);
863         SSVAL(vwv+7, 0, mode);
864         SSVAL(vwv+8, 0, 0);
865         SSVAL(vwv+9, 0, (state->size>>16));
866         SSVAL(vwv+10, 0, state->size);
867
868         SSVAL(vwv+11, 0,
869               cli_smb_wct_ofs(reqs_before, num_reqs_before)
870               + 1               /* the wct field */
871               + wct * 2         /* vwv */
872               + 2               /* num_bytes field */
873               + 1               /* pad */);
874
875         if (bigoffset) {
876                 SIVAL(vwv+12, 0, (((uint64_t)offset)>>32) & 0xffffffff);
877         }
878
879         state->pad = 0;
880         state->iov[0].iov_base = (void *)&state->pad;
881         state->iov[0].iov_len = 1;
882         state->iov[1].iov_base = discard_const_p(void, buf);
883         state->iov[1].iov_len = state->size;
884
885         subreq = cli_smb_req_create(state, ev, cli, SMBwriteX, 0, wct, vwv,
886                                     2, state->iov);
887         if (tevent_req_nomem(subreq, req)) {
888                 return tevent_req_post(req, ev);
889         }
890         tevent_req_set_callback(subreq, cli_write_andx_done, req);
891         *psmbreq = subreq;
892         return req;
893 }
894
895 struct tevent_req *cli_write_andx_send(TALLOC_CTX *mem_ctx,
896                                        struct event_context *ev,
897                                        struct cli_state *cli, uint16_t fnum,
898                                        uint16_t mode, const uint8_t *buf,
899                                        off_t offset, size_t size)
900 {
901         struct tevent_req *req, *subreq;
902         NTSTATUS status;
903
904         req = cli_write_andx_create(mem_ctx, ev, cli, fnum, mode, buf, offset,
905                                     size, NULL, 0, &subreq);
906         if (req == NULL) {
907                 return NULL;
908         }
909
910         status = cli_smb_req_send(subreq);
911         if (tevent_req_nterror(req, status)) {
912                 return tevent_req_post(req, ev);
913         }
914         return req;
915 }
916
917 static void cli_write_andx_done(struct tevent_req *subreq)
918 {
919         struct tevent_req *req = tevent_req_callback_data(
920                 subreq, struct tevent_req);
921         struct cli_write_andx_state *state = tevent_req_data(
922                 req, struct cli_write_andx_state);
923         uint8_t wct;
924         uint16_t *vwv;
925         uint8_t *inbuf;
926         NTSTATUS status;
927
928         status = cli_smb_recv(subreq, state, &inbuf, 6, &wct, &vwv,
929                               NULL, NULL);
930         TALLOC_FREE(subreq);
931         if (NT_STATUS_IS_ERR(status)) {
932                 tevent_req_nterror(req, status);
933                 return;
934         }
935         state->written = SVAL(vwv+2, 0);
936         if (state->size > UINT16_MAX) {
937                 /*
938                  * It is important that we only set the
939                  * high bits only if we asked for a large write.
940                  *
941                  * OS/2 print shares get this wrong and may send
942                  * invalid values.
943                  *
944                  * See bug #5326.
945                  */
946                 state->written |= SVAL(vwv+4, 0)<<16;
947         }
948         tevent_req_done(req);
949 }
950
951 NTSTATUS cli_write_andx_recv(struct tevent_req *req, size_t *pwritten)
952 {
953         struct cli_write_andx_state *state = tevent_req_data(
954                 req, struct cli_write_andx_state);
955         NTSTATUS status;
956
957         if (tevent_req_is_nterror(req, &status)) {
958                 return status;
959         }
960         if (pwritten != 0) {
961                 *pwritten = state->written;
962         }
963         return NT_STATUS_OK;
964 }
965
966 struct cli_writeall_state {
967         struct event_context *ev;
968         struct cli_state *cli;
969         uint16_t fnum;
970         uint16_t mode;
971         const uint8_t *buf;
972         off_t offset;
973         size_t size;
974         size_t written;
975 };
976
977 static void cli_writeall_written(struct tevent_req *req);
978
979 static struct tevent_req *cli_writeall_send(TALLOC_CTX *mem_ctx,
980                                             struct event_context *ev,
981                                             struct cli_state *cli,
982                                             uint16_t fnum,
983                                             uint16_t mode,
984                                             const uint8_t *buf,
985                                             off_t offset, size_t size)
986 {
987         struct tevent_req *req, *subreq;
988         struct cli_writeall_state *state;
989
990         req = tevent_req_create(mem_ctx, &state, struct cli_writeall_state);
991         if (req == NULL) {
992                 return NULL;
993         }
994         state->ev = ev;
995         state->cli = cli;
996         state->fnum = fnum;
997         state->mode = mode;
998         state->buf = buf;
999         state->offset = offset;
1000         state->size = size;
1001         state->written = 0;
1002
1003         subreq = cli_write_andx_send(state, state->ev, state->cli, state->fnum,
1004                                      state->mode, state->buf, state->offset,
1005                                      state->size);
1006         if (tevent_req_nomem(subreq, req)) {
1007                 return tevent_req_post(req, ev);
1008         }
1009         tevent_req_set_callback(subreq, cli_writeall_written, req);
1010         return req;
1011 }
1012
1013 static void cli_writeall_written(struct tevent_req *subreq)
1014 {
1015         struct tevent_req *req = tevent_req_callback_data(
1016                 subreq, struct tevent_req);
1017         struct cli_writeall_state *state = tevent_req_data(
1018                 req, struct cli_writeall_state);
1019         NTSTATUS status;
1020         size_t written, to_write;
1021
1022         status = cli_write_andx_recv(subreq, &written);
1023         TALLOC_FREE(subreq);
1024         if (tevent_req_nterror(req, status)) {
1025                 return;
1026         }
1027
1028         state->written += written;
1029
1030         if (state->written > state->size) {
1031                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1032                 return;
1033         }
1034
1035         to_write = state->size - state->written;
1036
1037         if (to_write == 0) {
1038                 tevent_req_done(req);
1039                 return;
1040         }
1041
1042         subreq = cli_write_andx_send(state, state->ev, state->cli, state->fnum,
1043                                      state->mode,
1044                                      state->buf + state->written,
1045                                      state->offset + state->written, to_write);
1046         if (tevent_req_nomem(subreq, req)) {
1047                 return;
1048         }
1049         tevent_req_set_callback(subreq, cli_writeall_written, req);
1050 }
1051
1052 static NTSTATUS cli_writeall_recv(struct tevent_req *req,
1053                                   size_t *pwritten)
1054 {
1055         struct cli_writeall_state *state = tevent_req_data(
1056                 req, struct cli_writeall_state);
1057         NTSTATUS status;
1058
1059         if (tevent_req_is_nterror(req, &status)) {
1060                 return status;
1061         }
1062         if (pwritten != NULL) {
1063                 *pwritten = state->written;
1064         }
1065         return NT_STATUS_OK;
1066 }
1067
1068 NTSTATUS cli_writeall(struct cli_state *cli, uint16_t fnum, uint16_t mode,
1069                       const uint8_t *buf, off_t offset, size_t size,
1070                       size_t *pwritten)
1071 {
1072         TALLOC_CTX *frame = talloc_stackframe();
1073         struct event_context *ev;
1074         struct tevent_req *req;
1075         NTSTATUS status = NT_STATUS_NO_MEMORY;
1076
1077         if (cli_has_async_calls(cli)) {
1078                 /*
1079                  * Can't use sync call while an async call is in flight
1080                  */
1081                 status = NT_STATUS_INVALID_PARAMETER;
1082                 goto fail;
1083         }
1084         ev = event_context_init(frame);
1085         if (ev == NULL) {
1086                 goto fail;
1087         }
1088         req = cli_writeall_send(frame, ev, cli, fnum, mode, buf, offset, size);
1089         if (req == NULL) {
1090                 goto fail;
1091         }
1092         if (!tevent_req_poll(req, ev)) {
1093                 status = map_nt_error_from_unix(errno);
1094                 goto fail;
1095         }
1096         status = cli_writeall_recv(req, pwritten);
1097  fail:
1098         TALLOC_FREE(frame);
1099         return status;
1100 }
1101
1102 struct cli_push_write_state {
1103         struct tevent_req *req;/* This is the main request! Not the subreq */
1104         uint32_t idx;
1105         off_t ofs;
1106         uint8_t *buf;
1107         size_t size;
1108 };
1109
1110 struct cli_push_state {
1111         struct event_context *ev;
1112         struct cli_state *cli;
1113         uint16_t fnum;
1114         uint16_t mode;
1115         off_t start_offset;
1116         size_t window_size;
1117
1118         size_t (*source)(uint8_t *buf, size_t n, void *priv);
1119         void *priv;
1120
1121         bool eof;
1122
1123         size_t chunk_size;
1124         off_t next_offset;
1125
1126         /*
1127          * Outstanding requests
1128          */
1129         uint32_t pending;
1130         uint16_t max_reqs;
1131         uint32_t num_reqs;
1132         struct cli_push_write_state **reqs;
1133 };
1134
1135 static void cli_push_written(struct tevent_req *req);
1136
1137 static bool cli_push_write_setup(struct tevent_req *req,
1138                                  struct cli_push_state *state,
1139                                  uint32_t idx)
1140 {
1141         struct cli_push_write_state *substate;
1142         struct tevent_req *subreq;
1143
1144         substate = talloc(state->reqs, struct cli_push_write_state);
1145         if (!substate) {
1146                 return false;
1147         }
1148         substate->req = req;
1149         substate->idx = idx;
1150         substate->ofs = state->next_offset;
1151         substate->buf = talloc_array(substate, uint8_t, state->chunk_size);
1152         if (!substate->buf) {
1153                 talloc_free(substate);
1154                 return false;
1155         }
1156         substate->size = state->source(substate->buf,
1157                                        state->chunk_size,
1158                                        state->priv);
1159         if (substate->size == 0) {
1160                 state->eof = true;
1161                 /* nothing to send */
1162                 talloc_free(substate);
1163                 return true;
1164         }
1165
1166         subreq = cli_writeall_send(substate,
1167                                    state->ev, state->cli,
1168                                    state->fnum, state->mode,
1169                                    substate->buf,
1170                                    substate->ofs,
1171                                    substate->size);
1172         if (!subreq) {
1173                 talloc_free(substate);
1174                 return false;
1175         }
1176         tevent_req_set_callback(subreq, cli_push_written, substate);
1177
1178         state->reqs[idx] = substate;
1179         state->pending += 1;
1180         state->next_offset += substate->size;
1181
1182         return true;
1183 }
1184
1185 struct tevent_req *cli_push_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
1186                                  struct cli_state *cli,
1187                                  uint16_t fnum, uint16_t mode,
1188                                  off_t start_offset, size_t window_size,
1189                                  size_t (*source)(uint8_t *buf, size_t n,
1190                                                   void *priv),
1191                                  void *priv)
1192 {
1193         struct tevent_req *req;
1194         struct cli_push_state *state;
1195         uint32_t i;
1196         size_t page_size = 1024;
1197
1198         req = tevent_req_create(mem_ctx, &state, struct cli_push_state);
1199         if (req == NULL) {
1200                 return NULL;
1201         }
1202         state->cli = cli;
1203         state->ev = ev;
1204         state->fnum = fnum;
1205         state->start_offset = start_offset;
1206         state->mode = mode;
1207         state->source = source;
1208         state->priv = priv;
1209         state->eof = false;
1210         state->pending = 0;
1211         state->next_offset = start_offset;
1212
1213         state->chunk_size = cli_write_max_bufsize(cli, mode, 14);
1214         if (state->chunk_size > page_size) {
1215                 state->chunk_size &= ~(page_size - 1);
1216         }
1217
1218         state->max_reqs = cli_state_max_requests(cli);
1219
1220         if (window_size == 0) {
1221                 window_size = state->max_reqs * state->chunk_size;
1222         }
1223         state->num_reqs = window_size/state->chunk_size;
1224         if ((window_size % state->chunk_size) > 0) {
1225                 state->num_reqs += 1;
1226         }
1227         state->num_reqs = MIN(state->num_reqs, state->max_reqs);
1228         state->num_reqs = MAX(state->num_reqs, 1);
1229
1230         state->reqs = talloc_zero_array(state, struct cli_push_write_state *,
1231                                         state->num_reqs);
1232         if (state->reqs == NULL) {
1233                 goto failed;
1234         }
1235
1236         for (i=0; i<state->num_reqs; i++) {
1237                 if (!cli_push_write_setup(req, state, i)) {
1238                         goto failed;
1239                 }
1240
1241                 if (state->eof) {
1242                         break;
1243                 }
1244         }
1245
1246         if (state->pending == 0) {
1247                 tevent_req_done(req);
1248                 return tevent_req_post(req, ev);
1249         }
1250
1251         return req;
1252
1253  failed:
1254         tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1255         return tevent_req_post(req, ev);
1256 }
1257
1258 static void cli_push_written(struct tevent_req *subreq)
1259 {
1260         struct cli_push_write_state *substate = tevent_req_callback_data(
1261                 subreq, struct cli_push_write_state);
1262         struct tevent_req *req = substate->req;
1263         struct cli_push_state *state = tevent_req_data(
1264                 req, struct cli_push_state);
1265         NTSTATUS status;
1266         uint32_t idx = substate->idx;
1267
1268         state->reqs[idx] = NULL;
1269         state->pending -= 1;
1270
1271         status = cli_writeall_recv(subreq, NULL);
1272         TALLOC_FREE(subreq);
1273         TALLOC_FREE(substate);
1274         if (tevent_req_nterror(req, status)) {
1275                 return;
1276         }
1277
1278         if (!state->eof) {
1279                 if (!cli_push_write_setup(req, state, idx)) {
1280                         tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1281                         return;
1282                 }
1283         }
1284
1285         if (state->pending == 0) {
1286                 tevent_req_done(req);
1287                 return;
1288         }
1289 }
1290
1291 NTSTATUS cli_push_recv(struct tevent_req *req)
1292 {
1293         return tevent_req_simple_recv_ntstatus(req);
1294 }
1295
1296 NTSTATUS cli_push(struct cli_state *cli, uint16_t fnum, uint16_t mode,
1297                   off_t start_offset, size_t window_size,
1298                   size_t (*source)(uint8_t *buf, size_t n, void *priv),
1299                   void *priv)
1300 {
1301         TALLOC_CTX *frame = talloc_stackframe();
1302         struct event_context *ev;
1303         struct tevent_req *req;
1304         NTSTATUS status = NT_STATUS_OK;
1305
1306         if (cli_has_async_calls(cli)) {
1307                 /*
1308                  * Can't use sync call while an async call is in flight
1309                  */
1310                 status = NT_STATUS_INVALID_PARAMETER;
1311                 goto fail;
1312         }
1313
1314         ev = event_context_init(frame);
1315         if (ev == NULL) {
1316                 status = NT_STATUS_NO_MEMORY;
1317                 goto fail;
1318         }
1319
1320         req = cli_push_send(frame, ev, cli, fnum, mode, start_offset,
1321                             window_size, source, priv);
1322         if (req == NULL) {
1323                 status = NT_STATUS_NO_MEMORY;
1324                 goto fail;
1325         }
1326
1327         if (!tevent_req_poll(req, ev)) {
1328                 status = map_nt_error_from_unix(errno);
1329                 goto fail;
1330         }
1331
1332         status = cli_push_recv(req);
1333  fail:
1334         TALLOC_FREE(frame);
1335         return status;
1336 }