s3:utils: let smbstatus report anonymous signing/encryption explicitly
[samba.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 #include "../libcli/smb/smbXcli_base.h"
26
27 /****************************************************************************
28   Calculate the recommended read buffer size
29 ****************************************************************************/
30 static size_t cli_read_max_bufsize(struct cli_state *cli)
31 {
32         uint8_t wct = 12;
33         uint32_t min_space;
34         uint32_t data_offset;
35         uint32_t useable_space = 0;
36
37         data_offset = HDR_VWV;
38         data_offset += wct * sizeof(uint16_t);
39         data_offset += sizeof(uint16_t); /* byte count */
40         data_offset += 1; /* pad */
41
42         min_space = cli_state_available_size(cli, data_offset);
43
44         if (cli->server_posix_capabilities & CIFS_UNIX_LARGE_READ_CAP) {
45                 useable_space = 0xFFFFFF - data_offset;
46
47                 if (smb1cli_conn_signing_is_active(cli->conn)) {
48                         return min_space;
49                 }
50
51                 if (smb1cli_conn_encryption_on(cli->conn)) {
52                         return min_space;
53                 }
54
55                 return useable_space;
56         } else if (smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_READX) {
57                 /*
58                  * Note: CAP_LARGE_READX also works with signing
59                  */
60                 useable_space = 0x1FFFF - data_offset;
61
62                 useable_space = MIN(useable_space, UINT16_MAX);
63
64                 return useable_space;
65         }
66
67         return min_space;
68 }
69
70 /****************************************************************************
71   Calculate the recommended write buffer size
72 ****************************************************************************/
73 static size_t cli_write_max_bufsize(struct cli_state *cli,
74                                     uint16_t write_mode,
75                                     uint8_t wct)
76 {
77         uint32_t min_space;
78         uint32_t data_offset;
79         uint32_t useable_space = 0;
80
81         data_offset = HDR_VWV;
82         data_offset += wct * sizeof(uint16_t);
83         data_offset += sizeof(uint16_t); /* byte count */
84         data_offset += 1; /* pad */
85
86         min_space = cli_state_available_size(cli, data_offset);
87
88         if (cli->server_posix_capabilities & CIFS_UNIX_LARGE_WRITE_CAP) {
89                 useable_space = 0xFFFFFF - data_offset;
90         } else if (smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_WRITEX) {
91                 useable_space = 0x1FFFF - data_offset;
92         } else {
93                 return min_space;
94         }
95
96         if (write_mode != 0) {
97                 return min_space;
98         }
99
100         if (smb1cli_conn_signing_is_active(cli->conn)) {
101                 return min_space;
102         }
103
104         if (smb1cli_conn_encryption_on(cli->conn)) {
105                 return min_space;
106         }
107
108         if (strequal(cli->dev, "LPT1:")) {
109                 return min_space;
110         }
111
112         return useable_space;
113 }
114
115 struct cli_read_andx_state {
116         size_t size;
117         uint16_t vwv[12];
118         NTSTATUS status;
119         size_t received;
120         uint8_t *buf;
121 };
122
123 static void cli_read_andx_done(struct tevent_req *subreq);
124
125 struct tevent_req *cli_read_andx_create(TALLOC_CTX *mem_ctx,
126                                         struct tevent_context *ev,
127                                         struct cli_state *cli, uint16_t fnum,
128                                         off_t offset, size_t size,
129                                         struct tevent_req **psmbreq)
130 {
131         struct tevent_req *req, *subreq;
132         struct cli_read_andx_state *state;
133         uint8_t wct = 10;
134
135         req = tevent_req_create(mem_ctx, &state, struct cli_read_andx_state);
136         if (req == NULL) {
137                 return NULL;
138         }
139         state->size = size;
140
141         SCVAL(state->vwv + 0, 0, 0xFF);
142         SCVAL(state->vwv + 0, 1, 0);
143         SSVAL(state->vwv + 1, 0, 0);
144         SSVAL(state->vwv + 2, 0, fnum);
145         SIVAL(state->vwv + 3, 0, offset);
146         SSVAL(state->vwv + 5, 0, size);
147         SSVAL(state->vwv + 6, 0, size);
148         SSVAL(state->vwv + 7, 0, (size >> 16));
149         SSVAL(state->vwv + 8, 0, 0);
150         SSVAL(state->vwv + 9, 0, 0);
151
152         if (smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_FILES) {
153                 SIVAL(state->vwv + 10, 0,
154                       (((uint64_t)offset)>>32) & 0xffffffff);
155                 wct = 12;
156         } else {
157                 if ((((uint64_t)offset) & 0xffffffff00000000LL) != 0) {
158                         DEBUG(10, ("cli_read_andx_send got large offset where "
159                                    "the server does not support it\n"));
160                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
161                         return tevent_req_post(req, ev);
162                 }
163         }
164
165         subreq = cli_smb_req_create(state, ev, cli, SMBreadX, 0, 0, wct,
166                                     state->vwv, 0, NULL);
167         if (subreq == NULL) {
168                 TALLOC_FREE(req);
169                 return NULL;
170         }
171         tevent_req_set_callback(subreq, cli_read_andx_done, req);
172         *psmbreq = subreq;
173         return req;
174 }
175
176 struct tevent_req *cli_read_andx_send(TALLOC_CTX *mem_ctx,
177                                       struct tevent_context *ev,
178                                       struct cli_state *cli, uint16_t fnum,
179                                       off_t offset, size_t size)
180 {
181         struct tevent_req *req, *subreq;
182         NTSTATUS status;
183
184         req = cli_read_andx_create(mem_ctx, ev, cli, fnum, offset, size,
185                                    &subreq);
186         if (req == NULL) {
187                 return NULL;
188         }
189
190         status = smb1cli_req_chain_submit(&subreq, 1);
191         if (tevent_req_nterror(req, status)) {
192                 return tevent_req_post(req, ev);
193         }
194         return req;
195 }
196
197 static void cli_read_andx_done(struct tevent_req *subreq)
198 {
199         struct tevent_req *req = tevent_req_callback_data(
200                 subreq, struct tevent_req);
201         struct cli_read_andx_state *state = tevent_req_data(
202                 req, struct cli_read_andx_state);
203         uint8_t *inbuf;
204         uint8_t wct;
205         uint16_t *vwv;
206         uint32_t num_bytes;
207         uint8_t *bytes;
208
209         state->status = cli_smb_recv(subreq, state, &inbuf, 12, &wct, &vwv,
210                                      &num_bytes, &bytes);
211         TALLOC_FREE(subreq);
212         if (NT_STATUS_IS_ERR(state->status)) {
213                 tevent_req_nterror(req, state->status);
214                 return;
215         }
216
217         /* size is the number of bytes the server returned.
218          * Might be zero. */
219         state->received = SVAL(vwv + 5, 0);
220         state->received |= (((unsigned int)SVAL(vwv + 7, 0)) << 16);
221
222         if (state->received > state->size) {
223                 DEBUG(5,("server returned more than we wanted!\n"));
224                 tevent_req_nterror(req, NT_STATUS_UNEXPECTED_IO_ERROR);
225                 return;
226         }
227
228         /*
229          * bcc field must be valid for small reads, for large reads the 16-bit
230          * bcc field can't be correct.
231          */
232
233         if ((state->received < 0xffff) && (state->received > num_bytes)) {
234                 DEBUG(5, ("server announced more bytes than sent\n"));
235                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
236                 return;
237         }
238
239         state->buf = discard_const_p(uint8_t, smb_base(inbuf)) + SVAL(vwv+6, 0);
240
241         if (smb_buffer_oob(smb_len_tcp(inbuf), SVAL(vwv+6, 0), state->received)
242             || ((state->received != 0) && (state->buf < bytes))) {
243                 DEBUG(5, ("server returned invalid read&x data offset\n"));
244                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
245                 return;
246         }
247         tevent_req_done(req);
248 }
249
250 /*
251  * Pull the data out of a finished async read_and_x request. rcvbuf is
252  * talloced from the request, so better make sure that you copy it away before
253  * you talloc_free(req). "rcvbuf" is NOT a talloc_ctx of its own, so do not
254  * talloc_move it!
255  */
256
257 NTSTATUS cli_read_andx_recv(struct tevent_req *req, ssize_t *received,
258                             uint8_t **rcvbuf)
259 {
260         struct cli_read_andx_state *state = tevent_req_data(
261                 req, struct cli_read_andx_state);
262         NTSTATUS status;
263
264         if (tevent_req_is_nterror(req, &status)) {
265                 return status;
266         }
267         *received = state->received;
268         *rcvbuf = state->buf;
269         return NT_STATUS_OK;
270 }
271
272 struct cli_pull_chunk;
273
274 struct cli_pull_state {
275         struct tevent_context *ev;
276         struct cli_state *cli;
277         uint16_t fnum;
278         off_t start_offset;
279         off_t size;
280
281         NTSTATUS (*sink)(char *buf, size_t n, void *priv);
282         void *priv;
283
284         size_t chunk_size;
285         off_t next_offset;
286         off_t remaining;
287
288         /*
289          * How many bytes did we push into "sink"?
290          */
291         off_t pushed;
292
293         /*
294          * Outstanding requests
295          *
296          * The maximum is 256:
297          * - which would be a window of 256 MByte
298          *   for SMB2 with multi-credit
299          *   or smb1 unix extensions.
300          */
301         uint16_t max_chunks;
302         uint16_t num_chunks;
303         uint16_t num_waiting;
304         struct cli_pull_chunk *chunks;
305 };
306
307 struct cli_pull_chunk {
308         struct cli_pull_chunk *prev, *next;
309         struct tevent_req *req;/* This is the main request! Not the subreq */
310         struct tevent_req *subreq;
311         off_t ofs;
312         uint8_t *buf;
313         size_t total_size;
314         size_t tmp_size;
315         bool done;
316 };
317
318 static void cli_pull_setup_chunks(struct tevent_req *req);
319 static void cli_pull_chunk_ship(struct cli_pull_chunk *chunk);
320 static void cli_pull_chunk_done(struct tevent_req *subreq);
321
322 /*
323  * Parallel read support.
324  *
325  * cli_pull sends as many read&x requests as the server would allow via
326  * max_mux at a time. When replies flow back in, the data is written into
327  * the callback function "sink" in the right order.
328  */
329
330 struct tevent_req *cli_pull_send(TALLOC_CTX *mem_ctx,
331                                  struct tevent_context *ev,
332                                  struct cli_state *cli,
333                                  uint16_t fnum, off_t start_offset,
334                                  off_t size, size_t window_size,
335                                  NTSTATUS (*sink)(char *buf, size_t n,
336                                                   void *priv),
337                                  void *priv)
338 {
339         struct tevent_req *req;
340         struct cli_pull_state *state;
341         size_t page_size = 1024;
342         uint64_t tmp64;
343
344         req = tevent_req_create(mem_ctx, &state, struct cli_pull_state);
345         if (req == NULL) {
346                 return NULL;
347         }
348         state->cli = cli;
349         state->ev = ev;
350         state->fnum = fnum;
351         state->start_offset = start_offset;
352         state->size = size;
353         state->sink = sink;
354         state->priv = priv;
355         state->next_offset = start_offset;
356         state->remaining = size;
357
358         if (size == 0) {
359                 tevent_req_done(req);
360                 return tevent_req_post(req, ev);
361         }
362
363         if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
364                 state->chunk_size = smb2cli_conn_max_read_size(cli->conn);
365         } else {
366                 state->chunk_size = cli_read_max_bufsize(cli);
367         }
368         if (state->chunk_size > page_size) {
369                 state->chunk_size &= ~(page_size - 1);
370         }
371
372         if (window_size == 0) {
373                 /*
374                  * We use 16 MByte as default window size.
375                  */
376                 window_size = 16 * 1024 * 1024;
377         }
378
379         tmp64 = window_size/state->chunk_size;
380         if ((window_size % state->chunk_size) > 0) {
381                 tmp64 += 1;
382         }
383         tmp64 = MAX(tmp64, 1);
384         tmp64 = MIN(tmp64, 256);
385         state->max_chunks = tmp64;
386
387         /*
388          * We defer the callback because of the complex
389          * substate/subfunction logic
390          */
391         tevent_req_defer_callback(req, ev);
392
393         cli_pull_setup_chunks(req);
394         if (!tevent_req_is_in_progress(req)) {
395                 return tevent_req_post(req, ev);
396         }
397
398         return req;
399 }
400
401 static void cli_pull_setup_chunks(struct tevent_req *req)
402 {
403         struct cli_pull_state *state =
404                 tevent_req_data(req,
405                 struct cli_pull_state);
406         struct cli_pull_chunk *chunk, *next = NULL;
407         size_t i;
408
409         for (chunk = state->chunks; chunk; chunk = next) {
410                 /*
411                  * Note that chunk might be removed from this call.
412                  */
413                 next = chunk->next;
414                 cli_pull_chunk_ship(chunk);
415                 if (!tevent_req_is_in_progress(req)) {
416                         return;
417                 }
418         }
419
420         for (i = state->num_chunks; i < state->max_chunks; i++) {
421
422                 if (state->num_waiting > 0) {
423                         return;
424                 }
425
426                 if (state->remaining == 0) {
427                         break;
428                 }
429
430                 chunk = talloc_zero(state, struct cli_pull_chunk);
431                 if (tevent_req_nomem(chunk, req)) {
432                         return;
433                 }
434                 chunk->req = req;
435                 chunk->ofs = state->next_offset;
436                 chunk->total_size = MIN(state->remaining, state->chunk_size);
437                 state->next_offset += chunk->total_size;
438                 state->remaining -= chunk->total_size;
439
440                 DLIST_ADD_END(state->chunks, chunk);
441                 state->num_chunks++;
442                 state->num_waiting++;
443
444                 cli_pull_chunk_ship(chunk);
445                 if (!tevent_req_is_in_progress(req)) {
446                         return;
447                 }
448         }
449
450         if (state->remaining > 0) {
451                 return;
452         }
453
454         if (state->num_chunks > 0) {
455                 return;
456         }
457
458         tevent_req_done(req);
459 }
460
461 static void cli_pull_chunk_ship(struct cli_pull_chunk *chunk)
462 {
463         struct tevent_req *req = chunk->req;
464         struct cli_pull_state *state =
465                 tevent_req_data(req,
466                 struct cli_pull_state);
467         bool ok;
468         off_t ofs;
469         size_t size;
470
471         if (chunk->done) {
472                 NTSTATUS status;
473
474                 if (chunk != state->chunks) {
475                         /*
476                          * this chunk is not the
477                          * first one in the list.
478                          *
479                          * which means we should not
480                          * push it into the sink yet.
481                          */
482                         return;
483                 }
484
485                 if (chunk->tmp_size == 0) {
486                         /*
487                          * we got a short read, we're done
488                          */
489                         tevent_req_done(req);
490                         return;
491                 }
492
493                 status = state->sink((char *)chunk->buf,
494                                      chunk->tmp_size,
495                                      state->priv);
496                 if (tevent_req_nterror(req, status)) {
497                         return;
498                 }
499                 state->pushed += chunk->tmp_size;
500
501                 if (chunk->tmp_size < chunk->total_size) {
502                         /*
503                          * we got a short read, we're done
504                          */
505                         tevent_req_done(req);
506                         return;
507                 }
508
509                 DLIST_REMOVE(state->chunks, chunk);
510                 SMB_ASSERT(state->num_chunks > 0);
511                 state->num_chunks--;
512                 TALLOC_FREE(chunk);
513
514                 return;
515         }
516
517         if (chunk->subreq != NULL) {
518                 return;
519         }
520
521         SMB_ASSERT(state->num_waiting > 0);
522
523         ofs = chunk->ofs + chunk->tmp_size;
524         size = chunk->total_size - chunk->tmp_size;
525
526         if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
527                 uint32_t max_size;
528
529                 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
530                 if (!ok) {
531                         return;
532                 }
533
534                 /*
535                  * downgrade depending on the available credits
536                  */
537                 size = MIN(max_size, size);
538
539                 chunk->subreq = cli_smb2_read_send(chunk,
540                                                    state->ev,
541                                                    state->cli,
542                                                    state->fnum,
543                                                    ofs,
544                                                    size);
545                 if (tevent_req_nomem(chunk->subreq, req)) {
546                         return;
547                 }
548         } else {
549                 ok = smb1cli_conn_req_possible(state->cli->conn);
550                 if (!ok) {
551                         return;
552                 }
553
554                 chunk->subreq = cli_read_andx_send(chunk,
555                                                    state->ev,
556                                                    state->cli,
557                                                    state->fnum,
558                                                    ofs,
559                                                    size);
560                 if (tevent_req_nomem(chunk->subreq, req)) {
561                         return;
562                 }
563         }
564         tevent_req_set_callback(chunk->subreq,
565                                 cli_pull_chunk_done,
566                                 chunk);
567
568         state->num_waiting--;
569         return;
570 }
571
572 static void cli_pull_chunk_done(struct tevent_req *subreq)
573 {
574         struct cli_pull_chunk *chunk =
575                 tevent_req_callback_data(subreq,
576                 struct cli_pull_chunk);
577         struct tevent_req *req = chunk->req;
578         struct cli_pull_state *state =
579                 tevent_req_data(req,
580                 struct cli_pull_state);
581         NTSTATUS status;
582         size_t expected = chunk->total_size - chunk->tmp_size;
583         ssize_t received = 0;
584         uint8_t *buf = NULL;
585
586         chunk->subreq = NULL;
587
588         if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
589                 status = cli_smb2_read_recv(subreq, &received, &buf);
590         } else {
591                 status = cli_read_andx_recv(subreq, &received, &buf);
592         }
593         if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
594                 received = 0;
595                 status = NT_STATUS_OK;
596         }
597         if (tevent_req_nterror(req, status)) {
598                 return;
599         }
600
601         if (received > expected) {
602                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
603                 return;
604         }
605
606         if (received == 0) {
607                 /*
608                  * We got EOF we're done
609                  */
610                 chunk->done = true;
611                 cli_pull_setup_chunks(req);
612                 return;
613         }
614
615         if (received == chunk->total_size) {
616                 /*
617                  * We got it in the first run.
618                  *
619                  * We don't call TALLOC_FREE(subreq)
620                  * here and keep the returned buffer.
621                  */
622                 chunk->buf = buf;
623         } else if (chunk->buf == NULL) {
624                 chunk->buf = talloc_array(chunk, uint8_t, chunk->total_size);
625                 if (tevent_req_nomem(chunk->buf, req)) {
626                         return;
627                 }
628         }
629
630         if (received != chunk->total_size) {
631                 uint8_t *p = chunk->buf + chunk->tmp_size;
632                 memcpy(p, buf, received);
633                 TALLOC_FREE(subreq);
634         }
635
636         chunk->tmp_size += received;
637
638         if (chunk->tmp_size == chunk->total_size) {
639                 chunk->done = true;
640         } else {
641                 state->num_waiting++;
642         }
643
644         cli_pull_setup_chunks(req);
645 }
646
647 NTSTATUS cli_pull_recv(struct tevent_req *req, off_t *received)
648 {
649         struct cli_pull_state *state = tevent_req_data(
650                 req, struct cli_pull_state);
651         NTSTATUS status;
652
653         if (tevent_req_is_nterror(req, &status)) {
654                 tevent_req_received(req);
655                 return status;
656         }
657         *received = state->pushed;
658         tevent_req_received(req);
659         return NT_STATUS_OK;
660 }
661
662 NTSTATUS cli_pull(struct cli_state *cli, uint16_t fnum,
663                   off_t start_offset, off_t size, size_t window_size,
664                   NTSTATUS (*sink)(char *buf, size_t n, void *priv),
665                   void *priv, off_t *received)
666 {
667         TALLOC_CTX *frame = talloc_stackframe();
668         struct tevent_context *ev;
669         struct tevent_req *req;
670         NTSTATUS status = NT_STATUS_OK;
671
672         if (smbXcli_conn_has_async_calls(cli->conn)) {
673                 /*
674                  * Can't use sync call while an async call is in flight
675                  */
676                 status = NT_STATUS_INVALID_PARAMETER;
677                 goto fail;
678         }
679
680         ev = samba_tevent_context_init(frame);
681         if (ev == NULL) {
682                 status = NT_STATUS_NO_MEMORY;
683                 goto fail;
684         }
685
686         req = cli_pull_send(frame, ev, cli, fnum, start_offset, size,
687                             window_size, sink, priv);
688         if (req == NULL) {
689                 status = NT_STATUS_NO_MEMORY;
690                 goto fail;
691         }
692
693         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
694                 goto fail;
695         }
696
697         status = cli_pull_recv(req, received);
698  fail:
699         TALLOC_FREE(frame);
700         return status;
701 }
702
703 struct cli_read_state {
704         struct cli_state *cli;
705         char *buf;
706         size_t buflen;
707         size_t received;
708 };
709
710 static void cli_read_done(struct tevent_req *subreq);
711
712 struct tevent_req *cli_read_send(
713         TALLOC_CTX *mem_ctx,
714         struct tevent_context *ev,
715         struct cli_state *cli,
716         uint16_t fnum,
717         char *buf,
718         off_t offset,
719         size_t size)
720 {
721         struct tevent_req *req, *subreq;
722         struct cli_read_state *state;
723
724         req = tevent_req_create(mem_ctx, &state, struct cli_read_state);
725         if (req == NULL) {
726                 return NULL;
727         }
728         state->cli = cli;
729         state->buf = buf;
730         state->buflen = size;
731
732         if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
733                 uint32_t max_size;
734                 bool ok;
735
736                 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
737                 if (!ok) {
738                         tevent_req_nterror(
739                                 req,
740                                 NT_STATUS_INSUFFICIENT_RESOURCES);
741                         return tevent_req_post(req, ev);
742                 }
743
744                 /*
745                  * downgrade depending on the available credits
746                  */
747                 size = MIN(max_size, size);
748
749                 subreq = cli_smb2_read_send(
750                         state, ev, cli, fnum, offset, size);
751                 if (tevent_req_nomem(subreq, req)) {
752                         return tevent_req_post(req, ev);
753                 }
754         } else {
755                 bool ok;
756                 ok = smb1cli_conn_req_possible(state->cli->conn);
757                 if (!ok) {
758                         tevent_req_nterror(
759                                 req,
760                                 NT_STATUS_INSUFFICIENT_RESOURCES);
761                         return tevent_req_post(req, ev);
762                 }
763
764                 subreq = cli_read_andx_send(
765                         state, ev, cli, fnum, offset, size);
766                 if (tevent_req_nomem(subreq, req)) {
767                         return tevent_req_post(req, ev);
768                 }
769         }
770
771         tevent_req_set_callback(subreq, cli_read_done, req);
772
773         return req;
774 }
775
776 static void cli_read_done(struct tevent_req *subreq)
777 {
778         struct tevent_req *req = tevent_req_callback_data(
779                 subreq, struct tevent_req);
780         struct cli_read_state *state = tevent_req_data(
781                 req, struct cli_read_state);
782         NTSTATUS status;
783         ssize_t received;
784         uint8_t *buf = NULL;
785
786         if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
787                 status = cli_smb2_read_recv(subreq, &received, &buf);
788         } else {
789                 status = cli_read_andx_recv(subreq, &received, &buf);
790         }
791
792         if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
793                 received = 0;
794                 status = NT_STATUS_OK;
795         }
796         if (tevent_req_nterror(req, status)) {
797                 return;
798         }
799         if ((buf == NULL) || (received < 0) || (received > state->buflen)) {
800                 state->received = 0;
801                 tevent_req_nterror(req, NT_STATUS_UNEXPECTED_IO_ERROR);
802                 return;
803         }
804
805         memcpy(state->buf, buf, received);
806         state->received = received;
807         tevent_req_done(req);
808 }
809
810 NTSTATUS cli_read_recv(struct tevent_req *req, size_t *received)
811 {
812         struct cli_read_state *state = tevent_req_data(
813                 req, struct cli_read_state);
814         NTSTATUS status;
815
816         if (tevent_req_is_nterror(req, &status)) {
817                 return status;
818         }
819         if (received != NULL) {
820                 *received = state->received;
821         }
822         return NT_STATUS_OK;
823 }
824
825 /*
826  * Helper function for cli_pull(). This takes a chunk of data (buf) read from
827  * a remote file and copies it into the return buffer (priv).
828  */
829 NTSTATUS cli_read_sink(char *buf, size_t n, void *priv)
830 {
831         char **pbuf = (char **)priv;
832         memcpy(*pbuf, buf, n);
833         *pbuf += n;
834         return NT_STATUS_OK;
835 }
836
837 NTSTATUS cli_read(struct cli_state *cli, uint16_t fnum,
838                  char *buf, off_t offset, size_t size,
839                  size_t *nread)
840 {
841         NTSTATUS status;
842         off_t ret = 0;
843
844         status = cli_pull(cli, fnum, offset, size, size,
845                           cli_read_sink, &buf, &ret);
846         if (!NT_STATUS_IS_OK(status)) {
847                 return status;
848         }
849
850         if (nread) {
851                 *nread = ret;
852         }
853
854         return NT_STATUS_OK;
855 }
856
857 /****************************************************************************
858   write to a file using a SMBwrite and not bypassing 0 byte writes
859 ****************************************************************************/
860
861 NTSTATUS cli_smbwrite(struct cli_state *cli, uint16_t fnum, char *buf,
862                       off_t offset, size_t size1, size_t *ptotal)
863 {
864         uint8_t *bytes;
865         ssize_t total = 0;
866
867         /*
868          * 3 bytes prefix
869          */
870
871         bytes = talloc_array(talloc_tos(), uint8_t, 3);
872         if (bytes == NULL) {
873                 return NT_STATUS_NO_MEMORY;
874         }
875         bytes[0] = 1;
876
877         do {
878                 uint32_t usable_space = cli_state_available_size(cli, 48);
879                 size_t size = MIN(size1, usable_space);
880                 struct tevent_req *req;
881                 uint16_t vwv[5];
882                 uint16_t *ret_vwv;
883                 NTSTATUS status;
884
885                 SSVAL(vwv+0, 0, fnum);
886                 SSVAL(vwv+1, 0, size);
887                 SIVAL(vwv+2, 0, offset);
888                 SSVAL(vwv+4, 0, 0);
889
890                 bytes = talloc_realloc(talloc_tos(), bytes, uint8_t,
891                                              size+3);
892                 if (bytes == NULL) {
893                         return NT_STATUS_NO_MEMORY;
894                 }
895                 SSVAL(bytes, 1, size);
896                 memcpy(bytes + 3, buf + total, size);
897
898                 status = cli_smb(talloc_tos(), cli, SMBwrite, 0, 5, vwv,
899                                  size+3, bytes, &req, 1, NULL, &ret_vwv,
900                                  NULL, NULL);
901                 if (!NT_STATUS_IS_OK(status)) {
902                         TALLOC_FREE(bytes);
903                         return status;
904                 }
905
906                 size = SVAL(ret_vwv+0, 0);
907                 TALLOC_FREE(req);
908                 if (size == 0) {
909                         break;
910                 }
911                 size1 -= size;
912                 total += size;
913                 offset += size;
914
915         } while (size1);
916
917         TALLOC_FREE(bytes);
918
919         if (ptotal != NULL) {
920                 *ptotal = total;
921         }
922         return NT_STATUS_OK;
923 }
924
925 /*
926  * Send a write&x request
927  */
928
929 struct cli_write_andx_state {
930         size_t size;
931         uint16_t vwv[14];
932         size_t written;
933         uint8_t pad;
934         struct iovec iov[2];
935 };
936
937 static void cli_write_andx_done(struct tevent_req *subreq);
938
939 struct tevent_req *cli_write_andx_create(TALLOC_CTX *mem_ctx,
940                                          struct tevent_context *ev,
941                                          struct cli_state *cli, uint16_t fnum,
942                                          uint16_t mode, const uint8_t *buf,
943                                          off_t offset, size_t size,
944                                          struct tevent_req **reqs_before,
945                                          int num_reqs_before,
946                                          struct tevent_req **psmbreq)
947 {
948         struct tevent_req *req, *subreq;
949         struct cli_write_andx_state *state;
950         bool bigoffset = ((smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_FILES) != 0);
951         uint8_t wct = bigoffset ? 14 : 12;
952         size_t max_write = cli_write_max_bufsize(cli, mode, wct);
953         uint16_t *vwv;
954
955         req = tevent_req_create(mem_ctx, &state, struct cli_write_andx_state);
956         if (req == NULL) {
957                 return NULL;
958         }
959
960         state->size = MIN(size, max_write);
961
962         vwv = state->vwv;
963
964         SCVAL(vwv+0, 0, 0xFF);
965         SCVAL(vwv+0, 1, 0);
966         SSVAL(vwv+1, 0, 0);
967         SSVAL(vwv+2, 0, fnum);
968         SIVAL(vwv+3, 0, offset);
969         SIVAL(vwv+5, 0, 0);
970         SSVAL(vwv+7, 0, mode);
971         SSVAL(vwv+8, 0, 0);
972         SSVAL(vwv+9, 0, (state->size>>16));
973         SSVAL(vwv+10, 0, state->size);
974
975         SSVAL(vwv+11, 0,
976               smb1cli_req_wct_ofs(reqs_before, num_reqs_before)
977               + 1               /* the wct field */
978               + wct * 2         /* vwv */
979               + 2               /* num_bytes field */
980               + 1               /* pad */);
981
982         if (bigoffset) {
983                 SIVAL(vwv+12, 0, (((uint64_t)offset)>>32) & 0xffffffff);
984         }
985
986         state->pad = 0;
987         state->iov[0].iov_base = (void *)&state->pad;
988         state->iov[0].iov_len = 1;
989         state->iov[1].iov_base = discard_const_p(void, buf);
990         state->iov[1].iov_len = state->size;
991
992         subreq = cli_smb_req_create(state, ev, cli, SMBwriteX, 0, 0, wct, vwv,
993                                     2, state->iov);
994         if (tevent_req_nomem(subreq, req)) {
995                 return tevent_req_post(req, ev);
996         }
997         tevent_req_set_callback(subreq, cli_write_andx_done, req);
998         *psmbreq = subreq;
999         return req;
1000 }
1001
1002 struct tevent_req *cli_write_andx_send(TALLOC_CTX *mem_ctx,
1003                                        struct tevent_context *ev,
1004                                        struct cli_state *cli, uint16_t fnum,
1005                                        uint16_t mode, const uint8_t *buf,
1006                                        off_t offset, size_t size)
1007 {
1008         struct tevent_req *req, *subreq;
1009         NTSTATUS status;
1010
1011         req = cli_write_andx_create(mem_ctx, ev, cli, fnum, mode, buf, offset,
1012                                     size, NULL, 0, &subreq);
1013         if (req == NULL) {
1014                 return NULL;
1015         }
1016
1017         status = smb1cli_req_chain_submit(&subreq, 1);
1018         if (tevent_req_nterror(req, status)) {
1019                 return tevent_req_post(req, ev);
1020         }
1021         return req;
1022 }
1023
1024 static void cli_write_andx_done(struct tevent_req *subreq)
1025 {
1026         struct tevent_req *req = tevent_req_callback_data(
1027                 subreq, struct tevent_req);
1028         struct cli_write_andx_state *state = tevent_req_data(
1029                 req, struct cli_write_andx_state);
1030         uint8_t wct;
1031         uint16_t *vwv;
1032         NTSTATUS status;
1033
1034         status = cli_smb_recv(subreq, state, NULL, 6, &wct, &vwv,
1035                               NULL, NULL);
1036         TALLOC_FREE(subreq);
1037         if (NT_STATUS_IS_ERR(status)) {
1038                 tevent_req_nterror(req, status);
1039                 return;
1040         }
1041         state->written = SVAL(vwv+2, 0);
1042         if (state->size > UINT16_MAX) {
1043                 /*
1044                  * It is important that we only set the
1045                  * high bits only if we asked for a large write.
1046                  *
1047                  * OS/2 print shares get this wrong and may send
1048                  * invalid values.
1049                  *
1050                  * See bug #5326.
1051                  */
1052                 state->written |= SVAL(vwv+4, 0)<<16;
1053         }
1054         tevent_req_done(req);
1055 }
1056
1057 NTSTATUS cli_write_andx_recv(struct tevent_req *req, size_t *pwritten)
1058 {
1059         struct cli_write_andx_state *state = tevent_req_data(
1060                 req, struct cli_write_andx_state);
1061         NTSTATUS status;
1062
1063         if (tevent_req_is_nterror(req, &status)) {
1064                 return status;
1065         }
1066         if (pwritten != 0) {
1067                 *pwritten = state->written;
1068         }
1069         return NT_STATUS_OK;
1070 }
1071
1072 struct cli_write_state {
1073         struct cli_state *cli;
1074         size_t written;
1075 };
1076
1077 static void cli_write_done(struct tevent_req *subreq);
1078
1079 /*
1080  * Used to write to a file remotely.
1081  * This is similar in functionality to cli_push_send(), except this is a more
1082  * finer-grain API. For example, if the data we want to write exceeds the max
1083  * write size of the underlying connection, then it's the caller's
1084  * responsibility to handle this.
1085  * For writing a small amount of data to file, this is a simpler API to use.
1086  */
1087 struct tevent_req *cli_write_send(TALLOC_CTX *mem_ctx,
1088                                   struct tevent_context *ev,
1089                                   struct cli_state *cli, uint16_t fnum,
1090                                   uint16_t mode, const uint8_t *buf,
1091                                   off_t offset, size_t size)
1092 {
1093         struct tevent_req *req = NULL;
1094         struct cli_write_state *state = NULL;
1095         struct tevent_req *subreq = NULL;
1096
1097         req = tevent_req_create(mem_ctx, &state, struct cli_write_state);
1098         if (req == NULL) {
1099                 return NULL;
1100         }
1101         state->cli = cli;
1102
1103         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1104                 uint32_t max_size;
1105                 bool ok;
1106
1107                 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
1108                 if (!ok) {
1109                         tevent_req_nterror(
1110                                 req,
1111                                 NT_STATUS_INSUFFICIENT_RESOURCES);
1112                         return tevent_req_post(req, ev);
1113                 }
1114
1115                 /*
1116                  * downgrade depending on the available credits
1117                  */
1118                 size = MIN(max_size, size);
1119
1120                 subreq = cli_smb2_write_send(state,
1121                                              ev,
1122                                              cli,
1123                                              fnum,
1124                                              mode,
1125                                              buf,
1126                                              offset,
1127                                              size);
1128         } else {
1129                 bool ok;
1130
1131                 ok = smb1cli_conn_req_possible(state->cli->conn);
1132                 if (!ok) {
1133                         tevent_req_nterror(
1134                                 req,
1135                                 NT_STATUS_INSUFFICIENT_RESOURCES);
1136                         return tevent_req_post(req, ev);
1137                 }
1138
1139                 subreq = cli_write_andx_send(state,
1140                                              ev,
1141                                              cli,
1142                                              fnum,
1143                                              mode,
1144                                              buf,
1145                                              offset,
1146                                              size);
1147         }
1148         if (tevent_req_nomem(subreq, req)) {
1149                 return tevent_req_post(req, ev);
1150         }
1151         tevent_req_set_callback(subreq, cli_write_done, req);
1152
1153         return req;
1154 }
1155
1156 static void cli_write_done(struct tevent_req *subreq)
1157 {
1158         struct tevent_req *req =
1159                 tevent_req_callback_data(subreq,
1160                 struct tevent_req);
1161         struct cli_write_state *state =
1162                 tevent_req_data(req,
1163                 struct cli_write_state);
1164         NTSTATUS status;
1165
1166         if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
1167                 status = cli_smb2_write_recv(subreq, &state->written);
1168         } else {
1169                 status = cli_write_andx_recv(subreq, &state->written);
1170         }
1171         TALLOC_FREE(subreq);
1172         if (tevent_req_nterror(req, status)) {
1173                 return;
1174         }
1175         tevent_req_done(req);
1176 }
1177
1178 NTSTATUS cli_write_recv(struct tevent_req *req, size_t *pwritten)
1179 {
1180         struct cli_write_state *state =
1181                 tevent_req_data(req,
1182                 struct cli_write_state);
1183         NTSTATUS status;
1184
1185         if (tevent_req_is_nterror(req, &status)) {
1186                 tevent_req_received(req);
1187                 return status;
1188         }
1189         if (pwritten != NULL) {
1190                 *pwritten = state->written;
1191         }
1192         tevent_req_received(req);
1193         return NT_STATUS_OK;
1194 }
1195
1196 struct cli_smb1_writeall_state {
1197         struct tevent_context *ev;
1198         struct cli_state *cli;
1199         uint16_t fnum;
1200         uint16_t mode;
1201         const uint8_t *buf;
1202         off_t offset;
1203         size_t size;
1204         size_t written;
1205 };
1206
1207 static void cli_smb1_writeall_written(struct tevent_req *req);
1208
1209 static struct tevent_req *cli_smb1_writeall_send(TALLOC_CTX *mem_ctx,
1210                                                  struct tevent_context *ev,
1211                                                  struct cli_state *cli,
1212                                                  uint16_t fnum,
1213                                                  uint16_t mode,
1214                                                  const uint8_t *buf,
1215                                                  off_t offset, size_t size)
1216 {
1217         struct tevent_req *req, *subreq;
1218         struct cli_smb1_writeall_state *state;
1219
1220         req = tevent_req_create(mem_ctx, &state,
1221                                 struct cli_smb1_writeall_state);
1222         if (req == NULL) {
1223                 return NULL;
1224         }
1225         state->ev = ev;
1226         state->cli = cli;
1227         state->fnum = fnum;
1228         state->mode = mode;
1229         state->buf = buf;
1230         state->offset = offset;
1231         state->size = size;
1232         state->written = 0;
1233
1234         subreq = cli_write_andx_send(state, state->ev, state->cli, state->fnum,
1235                                      state->mode, state->buf, state->offset,
1236                                      state->size);
1237         if (tevent_req_nomem(subreq, req)) {
1238                 return tevent_req_post(req, ev);
1239         }
1240         tevent_req_set_callback(subreq, cli_smb1_writeall_written, req);
1241         return req;
1242 }
1243
1244 static void cli_smb1_writeall_written(struct tevent_req *subreq)
1245 {
1246         struct tevent_req *req = tevent_req_callback_data(
1247                 subreq, struct tevent_req);
1248         struct cli_smb1_writeall_state *state = tevent_req_data(
1249                 req, struct cli_smb1_writeall_state);
1250         NTSTATUS status;
1251         size_t written = 0, to_write;
1252
1253         status = cli_write_andx_recv(subreq, &written);
1254         TALLOC_FREE(subreq);
1255         if (tevent_req_nterror(req, status)) {
1256                 return;
1257         }
1258
1259         state->written += written;
1260
1261         if (state->written > state->size) {
1262                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1263                 return;
1264         }
1265
1266         to_write = state->size - state->written;
1267
1268         if (to_write == 0) {
1269                 tevent_req_done(req);
1270                 return;
1271         }
1272
1273         subreq = cli_write_andx_send(state, state->ev, state->cli, state->fnum,
1274                                      state->mode,
1275                                      state->buf + state->written,
1276                                      state->offset + state->written, to_write);
1277         if (tevent_req_nomem(subreq, req)) {
1278                 return;
1279         }
1280         tevent_req_set_callback(subreq, cli_smb1_writeall_written, req);
1281 }
1282
1283 static NTSTATUS cli_smb1_writeall_recv(struct tevent_req *req,
1284                                        size_t *pwritten)
1285 {
1286         struct cli_smb1_writeall_state *state = tevent_req_data(
1287                 req, struct cli_smb1_writeall_state);
1288         NTSTATUS status;
1289
1290         if (tevent_req_is_nterror(req, &status)) {
1291                 return status;
1292         }
1293         if (pwritten != NULL) {
1294                 *pwritten = state->written;
1295         }
1296         return NT_STATUS_OK;
1297 }
1298
1299 struct cli_writeall_state {
1300         struct cli_state *cli;
1301         size_t written;
1302 };
1303
1304 static void cli_writeall_done(struct tevent_req *subreq);
1305
1306 struct tevent_req *cli_writeall_send(
1307         TALLOC_CTX *mem_ctx,
1308         struct tevent_context *ev,
1309         struct cli_state *cli,
1310         uint16_t fnum,
1311         uint16_t mode,
1312         const uint8_t *buf,
1313         off_t offset,
1314         size_t size)
1315 {
1316         struct tevent_req *req, *subreq;
1317         struct cli_writeall_state *state;
1318
1319         req = tevent_req_create(mem_ctx, &state, struct cli_writeall_state);
1320         if (req == NULL) {
1321                 return NULL;
1322         }
1323         state->cli = cli;
1324
1325         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1326                 subreq = cli_smb2_writeall_send(
1327                         state,
1328                         ev,
1329                         cli,
1330                         fnum,
1331                         mode,
1332                         buf,
1333                         offset,
1334                         size);
1335         } else {
1336                 subreq = cli_smb1_writeall_send(
1337                         state,
1338                         ev,
1339                         cli,
1340                         fnum,
1341                         mode,
1342                         buf,
1343                         offset,
1344                         size);
1345         }
1346
1347         if (tevent_req_nomem(subreq, req)) {
1348                 return tevent_req_post(req, ev);
1349         }
1350         tevent_req_set_callback(subreq, cli_writeall_done, req);
1351
1352         return req;
1353 }
1354
1355 static void cli_writeall_done(struct tevent_req *subreq)
1356 {
1357         struct tevent_req *req = tevent_req_callback_data(
1358                 subreq, struct tevent_req);
1359         struct cli_writeall_state *state = tevent_req_data(
1360                 req, struct cli_writeall_state);
1361         NTSTATUS status;
1362
1363         if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
1364                 status = cli_smb2_writeall_recv(subreq, &state->written);
1365         } else {
1366                 status = cli_smb1_writeall_recv(subreq, &state->written);
1367         }
1368         TALLOC_FREE(subreq);
1369         if (tevent_req_nterror(req, status)) {
1370                 return;
1371         }
1372         tevent_req_done(req);
1373 }
1374
1375 NTSTATUS cli_writeall_recv(struct tevent_req *req, size_t *pwritten)
1376 {
1377         struct cli_writeall_state *state = tevent_req_data(
1378                 req, struct cli_writeall_state);
1379         NTSTATUS status;
1380
1381         if (tevent_req_is_nterror(req, &status)) {
1382                 return status;
1383         }
1384         if (pwritten != NULL) {
1385                 *pwritten = state->written;
1386         }
1387         return NT_STATUS_OK;
1388 }
1389
1390
1391 NTSTATUS cli_writeall(struct cli_state *cli, uint16_t fnum, uint16_t mode,
1392                       const uint8_t *buf, off_t offset, size_t size,
1393                       size_t *pwritten)
1394 {
1395         TALLOC_CTX *frame = talloc_stackframe();
1396         struct tevent_context *ev;
1397         struct tevent_req *req;
1398         NTSTATUS status = NT_STATUS_NO_MEMORY;
1399
1400         if (smbXcli_conn_has_async_calls(cli->conn)) {
1401                 /*
1402                  * Can't use sync call while an async call is in flight
1403                  */
1404                 status = NT_STATUS_INVALID_PARAMETER;
1405                 goto fail;
1406         }
1407         ev = samba_tevent_context_init(frame);
1408         if (ev == NULL) {
1409                 goto fail;
1410         }
1411         req = cli_writeall_send(frame, ev, cli, fnum, mode, buf, offset, size);
1412         if (req == NULL) {
1413                 goto fail;
1414         }
1415         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1416                 goto fail;
1417         }
1418         status = cli_writeall_recv(req, pwritten);
1419  fail:
1420         TALLOC_FREE(frame);
1421         return status;
1422 }
1423
1424 struct cli_push_chunk;
1425
1426 struct cli_push_state {
1427         struct tevent_context *ev;
1428         struct cli_state *cli;
1429         uint16_t fnum;
1430         uint16_t mode;
1431         off_t start_offset;
1432
1433         size_t (*source)(uint8_t *buf, size_t n, void *priv);
1434         void *priv;
1435
1436         bool eof;
1437
1438         size_t chunk_size;
1439         off_t next_offset;
1440
1441         /*
1442          * Outstanding requests
1443          *
1444          * The maximum is 256:
1445          * - which would be a window of 256 MByte
1446          *   for SMB2 with multi-credit
1447          *   or smb1 unix extensions.
1448          */
1449         uint16_t max_chunks;
1450         uint16_t num_chunks;
1451         uint16_t num_waiting;
1452         struct cli_push_chunk *chunks;
1453 };
1454
1455 struct cli_push_chunk {
1456         struct cli_push_chunk *prev, *next;
1457         struct tevent_req *req;/* This is the main request! Not the subreq */
1458         struct tevent_req *subreq;
1459         off_t ofs;
1460         uint8_t *buf;
1461         size_t total_size;
1462         size_t tmp_size;
1463         bool done;
1464 };
1465
1466 static void cli_push_setup_chunks(struct tevent_req *req);
1467 static void cli_push_chunk_ship(struct cli_push_chunk *chunk);
1468 static void cli_push_chunk_done(struct tevent_req *subreq);
1469
1470 /*
1471  * Used to write to a file remotely.
1472  * This is similar in functionality to cli_write_send(), except this API
1473  * handles writing a large file by breaking the data into chunks (so we don't
1474  * exceed the max write size of the underlying connection). To do this, the
1475  * (*source) callback handles copying the underlying file data into a message
1476  * buffer, one chunk at a time.
1477  * This API is recommended when writing a potentially large amount of data,
1478  * e.g. when copying a file (or doing a 'put').
1479  */
1480 struct tevent_req *cli_push_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
1481                                  struct cli_state *cli,
1482                                  uint16_t fnum, uint16_t mode,
1483                                  off_t start_offset, size_t window_size,
1484                                  size_t (*source)(uint8_t *buf, size_t n,
1485                                                   void *priv),
1486                                  void *priv)
1487 {
1488         struct tevent_req *req;
1489         struct cli_push_state *state;
1490         size_t page_size = 1024;
1491         uint64_t tmp64;
1492
1493         req = tevent_req_create(mem_ctx, &state, struct cli_push_state);
1494         if (req == NULL) {
1495                 return NULL;
1496         }
1497         state->cli = cli;
1498         state->ev = ev;
1499         state->fnum = fnum;
1500         state->start_offset = start_offset;
1501         state->mode = mode;
1502         state->source = source;
1503         state->priv = priv;
1504         state->next_offset = start_offset;
1505
1506         if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
1507                 state->chunk_size = smb2cli_conn_max_write_size(cli->conn);
1508         } else {
1509                 state->chunk_size = cli_write_max_bufsize(cli, mode, 14);
1510         }
1511         if (state->chunk_size > page_size) {
1512                 state->chunk_size &= ~(page_size - 1);
1513         }
1514
1515         if (window_size == 0) {
1516                 /*
1517                  * We use 16 MByte as default window size.
1518                  */
1519                 window_size = 16 * 1024 * 1024;
1520         }
1521
1522         tmp64 = window_size/state->chunk_size;
1523         if ((window_size % state->chunk_size) > 0) {
1524                 tmp64 += 1;
1525         }
1526         tmp64 = MAX(tmp64, 1);
1527         tmp64 = MIN(tmp64, 256);
1528         state->max_chunks = tmp64;
1529
1530         /*
1531          * We defer the callback because of the complex
1532          * substate/subfunction logic
1533          */
1534         tevent_req_defer_callback(req, ev);
1535
1536         cli_push_setup_chunks(req);
1537         if (!tevent_req_is_in_progress(req)) {
1538                 return tevent_req_post(req, ev);
1539         }
1540
1541         return req;
1542 }
1543
1544 static void cli_push_setup_chunks(struct tevent_req *req)
1545 {
1546         struct cli_push_state *state =
1547                 tevent_req_data(req,
1548                 struct cli_push_state);
1549         struct cli_push_chunk *chunk, *next = NULL;
1550         size_t i;
1551
1552         for (chunk = state->chunks; chunk; chunk = next) {
1553                 /*
1554                  * Note that chunk might be removed from this call.
1555                  */
1556                 next = chunk->next;
1557                 cli_push_chunk_ship(chunk);
1558                 if (!tevent_req_is_in_progress(req)) {
1559                         return;
1560                 }
1561         }
1562
1563         for (i = state->num_chunks; i < state->max_chunks; i++) {
1564
1565                 if (state->num_waiting > 0) {
1566                         return;
1567                 }
1568
1569                 if (state->eof) {
1570                         break;
1571                 }
1572
1573                 chunk = talloc_zero(state, struct cli_push_chunk);
1574                 if (tevent_req_nomem(chunk, req)) {
1575                         return;
1576                 }
1577                 chunk->req = req;
1578                 chunk->ofs = state->next_offset;
1579                 chunk->buf = talloc_array(chunk,
1580                                           uint8_t,
1581                                           state->chunk_size);
1582                 if (tevent_req_nomem(chunk->buf, req)) {
1583                         return;
1584                 }
1585                 chunk->total_size = state->source(chunk->buf,
1586                                                   state->chunk_size,
1587                                                   state->priv);
1588                 if (chunk->total_size == 0) {
1589                         /* nothing to send */
1590                         talloc_free(chunk);
1591                         state->eof = true;
1592                         break;
1593                 }
1594                 state->next_offset += chunk->total_size;
1595
1596                 DLIST_ADD_END(state->chunks, chunk);
1597                 state->num_chunks++;
1598                 state->num_waiting++;
1599
1600                 cli_push_chunk_ship(chunk);
1601                 if (!tevent_req_is_in_progress(req)) {
1602                         return;
1603                 }
1604         }
1605
1606         if (!state->eof) {
1607                 return;
1608         }
1609
1610         if (state->num_chunks > 0) {
1611                 return;
1612         }
1613
1614         tevent_req_done(req);
1615 }
1616
1617 static void cli_push_chunk_ship(struct cli_push_chunk *chunk)
1618 {
1619         struct tevent_req *req = chunk->req;
1620         struct cli_push_state *state =
1621                 tevent_req_data(req,
1622                 struct cli_push_state);
1623         bool ok;
1624         const uint8_t *buf;
1625         off_t ofs;
1626         size_t size;
1627
1628         if (chunk->done) {
1629                 DLIST_REMOVE(state->chunks, chunk);
1630                 SMB_ASSERT(state->num_chunks > 0);
1631                 state->num_chunks--;
1632                 TALLOC_FREE(chunk);
1633
1634                 return;
1635         }
1636
1637         if (chunk->subreq != NULL) {
1638                 return;
1639         }
1640
1641         SMB_ASSERT(state->num_waiting > 0);
1642
1643         buf = chunk->buf + chunk->tmp_size;
1644         ofs = chunk->ofs + chunk->tmp_size;
1645         size = chunk->total_size - chunk->tmp_size;
1646
1647         if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
1648                 uint32_t max_size;
1649
1650                 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
1651                 if (!ok) {
1652                         return;
1653                 }
1654
1655                 /*
1656                  * downgrade depending on the available credits
1657                  */
1658                 size = MIN(max_size, size);
1659
1660                 chunk->subreq = cli_smb2_write_send(chunk,
1661                                                     state->ev,
1662                                                     state->cli,
1663                                                     state->fnum,
1664                                                     state->mode,
1665                                                     buf,
1666                                                     ofs,
1667                                                     size);
1668                 if (tevent_req_nomem(chunk->subreq, req)) {
1669                         return;
1670                 }
1671         } else {
1672                 ok = smb1cli_conn_req_possible(state->cli->conn);
1673                 if (!ok) {
1674                         return;
1675                 }
1676
1677                 chunk->subreq = cli_write_andx_send(chunk,
1678                                                     state->ev,
1679                                                     state->cli,
1680                                                     state->fnum,
1681                                                     state->mode,
1682                                                     buf,
1683                                                     ofs,
1684                                                     size);
1685                 if (tevent_req_nomem(chunk->subreq, req)) {
1686                         return;
1687                 }
1688         }
1689         tevent_req_set_callback(chunk->subreq,
1690                                 cli_push_chunk_done,
1691                                 chunk);
1692
1693         state->num_waiting--;
1694         return;
1695 }
1696
1697 static void cli_push_chunk_done(struct tevent_req *subreq)
1698 {
1699         struct cli_push_chunk *chunk =
1700                 tevent_req_callback_data(subreq,
1701                 struct cli_push_chunk);
1702         struct tevent_req *req = chunk->req;
1703         struct cli_push_state *state =
1704                 tevent_req_data(req,
1705                 struct cli_push_state);
1706         NTSTATUS status;
1707         size_t expected = chunk->total_size - chunk->tmp_size;
1708         size_t written;
1709
1710         chunk->subreq = NULL;
1711
1712         if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
1713                 status = cli_smb2_write_recv(subreq, &written);
1714         } else {
1715                 status = cli_write_andx_recv(subreq, &written);
1716         }
1717         TALLOC_FREE(subreq);
1718         if (tevent_req_nterror(req, status)) {
1719                 return;
1720         }
1721
1722         if (written > expected) {
1723                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1724                 return;
1725         }
1726
1727         if (written == 0) {
1728                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1729                 return;
1730         }
1731
1732         chunk->tmp_size += written;
1733
1734         if (chunk->tmp_size == chunk->total_size) {
1735                 chunk->done = true;
1736         } else {
1737                 state->num_waiting++;
1738         }
1739
1740         cli_push_setup_chunks(req);
1741 }
1742
1743 NTSTATUS cli_push_recv(struct tevent_req *req)
1744 {
1745         return tevent_req_simple_recv_ntstatus(req);
1746 }
1747
1748 NTSTATUS cli_push(struct cli_state *cli, uint16_t fnum, uint16_t mode,
1749                   off_t start_offset, size_t window_size,
1750                   size_t (*source)(uint8_t *buf, size_t n, void *priv),
1751                   void *priv)
1752 {
1753         TALLOC_CTX *frame = talloc_stackframe();
1754         struct tevent_context *ev;
1755         struct tevent_req *req;
1756         NTSTATUS status = NT_STATUS_OK;
1757
1758         if (smbXcli_conn_has_async_calls(cli->conn)) {
1759                 /*
1760                  * Can't use sync call while an async call is in flight
1761                  */
1762                 status = NT_STATUS_INVALID_PARAMETER;
1763                 goto fail;
1764         }
1765
1766         ev = samba_tevent_context_init(frame);
1767         if (ev == NULL) {
1768                 status = NT_STATUS_NO_MEMORY;
1769                 goto fail;
1770         }
1771
1772         req = cli_push_send(frame, ev, cli, fnum, mode, start_offset,
1773                             window_size, source, priv);
1774         if (req == NULL) {
1775                 status = NT_STATUS_NO_MEMORY;
1776                 goto fail;
1777         }
1778
1779         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1780                 goto fail;
1781         }
1782
1783         status = cli_push_recv(req);
1784  fail:
1785         TALLOC_FREE(frame);
1786         return status;
1787 }
1788
1789 #define SPLICE_BLOCK_SIZE 1024 * 1024
1790
1791 static NTSTATUS cli_splice_fallback(TALLOC_CTX *frame,
1792                                     struct cli_state *srccli,
1793                                     struct cli_state *dstcli,
1794                                     uint16_t src_fnum, uint16_t dst_fnum,
1795                                     off_t initial_size,
1796                                     off_t src_offset, off_t dst_offset,
1797                                     off_t *written,
1798                                     int (*splice_cb)(off_t n, void *priv),
1799                                     void *priv)
1800 {
1801         NTSTATUS status;
1802         uint8_t *buf = talloc_size(frame, SPLICE_BLOCK_SIZE);
1803         size_t nread;
1804         off_t remaining = initial_size;
1805         *written = 0;
1806
1807         while (remaining) {
1808                 size_t to_read = MIN(remaining, SPLICE_BLOCK_SIZE);
1809
1810                 status = cli_read(srccli, src_fnum,
1811                                   (char *)buf, src_offset, to_read,
1812                                   &nread);
1813                 if (!NT_STATUS_IS_OK(status)) {
1814                         return status;
1815                 }
1816
1817                 status = cli_writeall(dstcli, dst_fnum, 0,
1818                                       buf, dst_offset, nread, NULL);
1819                 if (!NT_STATUS_IS_OK(status)) {
1820                         return status;
1821                 }
1822
1823                 if ((src_offset > INT64_MAX - nread) ||
1824                     (dst_offset > INT64_MAX - nread)) {
1825                         return NT_STATUS_FILE_TOO_LARGE;
1826                 }
1827                 src_offset += nread;
1828                 dst_offset += nread;
1829                 *written += nread;
1830                 if (remaining < nread) {
1831                         return NT_STATUS_INTERNAL_ERROR;
1832                 }
1833                 remaining -= nread;
1834                 if (!splice_cb(initial_size - remaining, priv)) {
1835                         return NT_STATUS_CANCELLED;
1836                 }
1837         }
1838
1839         return NT_STATUS_OK;
1840 }
1841
1842 NTSTATUS cli_splice(struct cli_state *srccli, struct cli_state *dstcli,
1843                     uint16_t src_fnum, uint16_t dst_fnum,
1844                     off_t size,
1845                     off_t src_offset, off_t dst_offset,
1846                     off_t *written,
1847                     int (*splice_cb)(off_t n, void *priv), void *priv)
1848 {
1849         TALLOC_CTX *frame = talloc_stackframe();
1850         struct tevent_context *ev;
1851         struct tevent_req *req;
1852         NTSTATUS status = NT_STATUS_NO_MEMORY;
1853         bool retry_fallback = false;
1854
1855         if (smbXcli_conn_has_async_calls(srccli->conn) ||
1856             smbXcli_conn_has_async_calls(dstcli->conn))
1857         {
1858                 /*
1859                  * Can't use sync call while an async call is in flight
1860                  */
1861                 status = NT_STATUS_INVALID_PARAMETER;
1862                 goto out;
1863         }
1864
1865         do {
1866                 ev = samba_tevent_context_init(frame);
1867                 if (ev == NULL) {
1868                         goto out;
1869                 }
1870                 if (srccli == dstcli &&
1871                     smbXcli_conn_protocol(srccli->conn) >= PROTOCOL_SMB2_02 &&
1872                     !retry_fallback)
1873                 {
1874                         req = cli_smb2_splice_send(frame, ev,
1875                                                    srccli, src_fnum, dst_fnum,
1876                                                    size, src_offset, dst_offset,
1877                                                    splice_cb, priv);
1878                 } else {
1879                         status = cli_splice_fallback(frame,
1880                                                      srccli, dstcli,
1881                                                      src_fnum, dst_fnum,
1882                                                      size,
1883                                                      src_offset, dst_offset,
1884                                                      written,
1885                                                      splice_cb, priv);
1886                         goto out;
1887                 }
1888                 if (req == NULL) {
1889                         goto out;
1890                 }
1891                 if (!tevent_req_poll(req, ev)) {
1892                         status = map_nt_error_from_unix(errno);
1893                         goto out;
1894                 }
1895                 status = cli_smb2_splice_recv(req, written);
1896
1897                 /*
1898                  * Older versions of Samba don't support
1899                  * FSCTL_SRV_COPYCHUNK_WRITE so use the fallback.
1900                  */
1901                 retry_fallback = NT_STATUS_EQUAL(status, NT_STATUS_INVALID_DEVICE_REQUEST);
1902         } while (retry_fallback);
1903
1904  out:
1905         TALLOC_FREE(frame);
1906         return status;
1907 }