libcli/smb: pass max_dyn_len to smb2cli_req_send()
[mat/samba.git] / libcli / smb / smb2cli_create.c
1 /*
2    Unix SMB/CIFS implementation.
3    smb2 lib
4    Copyright (C) Volker Lendecke 2011
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "system/network.h"
22 #include "lib/util/tevent_ntstatus.h"
23 #include "smb_common.h"
24 #include "smbXcli_base.h"
25 #include "smb2_create_blob.h"
26
27 struct smb2cli_create_state {
28         uint8_t fixed[56];
29
30         uint64_t fid_persistent;
31         uint64_t fid_volatile;
32         struct smb2_create_returns cr;
33         struct smb2_create_blobs blobs;
34 };
35
36 static void smb2cli_create_done(struct tevent_req *subreq);
37
38 struct tevent_req *smb2cli_create_send(
39         TALLOC_CTX *mem_ctx,
40         struct tevent_context *ev,
41         struct smbXcli_conn *conn,
42         uint32_t timeout_msec,
43         struct smbXcli_session *session,
44         struct smbXcli_tcon *tcon,
45         const char *filename,
46         uint8_t  oplock_level,          /* SMB2_OPLOCK_LEVEL_* */
47         uint32_t impersonation_level,   /* SMB2_IMPERSONATION_* */
48         uint32_t desired_access,
49         uint32_t file_attributes,
50         uint32_t share_access,
51         uint32_t create_disposition,
52         uint32_t create_options,
53         struct smb2_create_blobs *blobs)
54 {
55         struct tevent_req *req, *subreq;
56         struct smb2cli_create_state *state;
57         uint8_t *fixed;
58         uint8_t *name_utf16;
59         size_t name_utf16_len;
60         DATA_BLOB blob;
61         NTSTATUS status;
62         size_t blobs_offset;
63         uint8_t *dyn;
64         size_t dyn_len;
65         size_t max_dyn_len;
66
67         req = tevent_req_create(mem_ctx, &state,
68                                 struct smb2cli_create_state);
69         if (req == NULL) {
70                 return NULL;
71         }
72
73         if (!convert_string_talloc(state, CH_UNIX, CH_UTF16,
74                                    filename, strlen(filename),
75                                    &name_utf16, &name_utf16_len)) {
76                 tevent_req_oom(req);
77                 return tevent_req_post(req, ev);
78         }
79
80         if (strlen(filename) == 0) {
81                 TALLOC_FREE(name_utf16);
82                 name_utf16_len = 0;
83         }
84
85         fixed = state->fixed;
86
87         SSVAL(fixed, 0, 57);
88         SCVAL(fixed, 3, oplock_level);
89         SIVAL(fixed, 4, impersonation_level);
90         SIVAL(fixed, 24, desired_access);
91         SIVAL(fixed, 28, file_attributes);
92         SIVAL(fixed, 32, share_access);
93         SIVAL(fixed, 36, create_disposition);
94         SIVAL(fixed, 40, create_options);
95
96         SSVAL(fixed, 44, SMB2_HDR_BODY + 56);
97         SSVAL(fixed, 46, name_utf16_len);
98
99         blob = data_blob_null;
100
101         if (blobs != NULL) {
102                 status = smb2_create_blob_push(state, &blob, *blobs);
103                 if (tevent_req_nterror(req, status)) {
104                         return tevent_req_post(req, ev);
105                 }
106         }
107
108         blobs_offset = name_utf16_len;
109         blobs_offset = ((blobs_offset + 3) & ~3);
110
111         if (blob.length > 0) {
112                 SIVAL(fixed, 48, blobs_offset + SMB2_HDR_BODY + 56);
113                 SIVAL(fixed, 52, blob.length);
114         }
115
116         dyn_len = MAX(1, blobs_offset + blob.length);
117         dyn = talloc_zero_array(state, uint8_t, dyn_len);
118         if (tevent_req_nomem(dyn, req)) {
119                 return tevent_req_post(req, ev);
120         }
121
122         if (name_utf16) {
123                 memcpy(dyn, name_utf16, name_utf16_len);
124                 TALLOC_FREE(name_utf16);
125         }
126
127         if (blob.data != NULL) {
128                 memcpy(dyn + blobs_offset,
129                        blob.data, blob.length);
130                 data_blob_free(&blob);
131         }
132
133         /*
134          * We use max_dyn_len = 0
135          * as we don't explicitly ask for any output length.
136          *
137          * But it's still possible for the server to return
138          * large create blobs.
139          */
140         max_dyn_len = 0;
141
142         subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_CREATE,
143                                   0, 0, /* flags */
144                                   timeout_msec,
145                                   tcon,
146                                   session,
147                                   state->fixed, sizeof(state->fixed),
148                                   dyn, dyn_len,
149                                   max_dyn_len);
150         if (tevent_req_nomem(subreq, req)) {
151                 return tevent_req_post(req, ev);
152         }
153         tevent_req_set_callback(subreq, smb2cli_create_done, req);
154         return req;
155 }
156
157 static void smb2cli_create_done(struct tevent_req *subreq)
158 {
159         struct tevent_req *req =
160                 tevent_req_callback_data(subreq,
161                 struct tevent_req);
162         struct smb2cli_create_state *state =
163                 tevent_req_data(req,
164                 struct smb2cli_create_state);
165         NTSTATUS status;
166         struct iovec *iov;
167         uint8_t *body;
168         uint32_t offset, length;
169         static const struct smb2cli_req_expected_response expected[] = {
170         {
171                 .status = NT_STATUS_OK,
172                 .body_size = 0x59
173         }
174         };
175
176         status = smb2cli_req_recv(subreq, state, &iov,
177                                   expected, ARRAY_SIZE(expected));
178         TALLOC_FREE(subreq);
179         if (tevent_req_nterror(req, status)) {
180                 return;
181         }
182
183         body = (uint8_t *)iov[1].iov_base;
184
185         state->cr.oplock_level  = CVAL(body, 2);
186         state->cr.create_action = IVAL(body, 4);
187         state->cr.creation_time = BVAL(body, 8);
188         state->cr.last_access_time = BVAL(body, 16);
189         state->cr.last_write_time = BVAL(body, 24);
190         state->cr.change_time   = BVAL(body, 32);
191         state->cr.allocation_size = BVAL(body, 40);
192         state->cr.end_of_file   = BVAL(body, 48);
193         state->cr.file_attributes = IVAL(body, 56);
194         state->fid_persistent   = BVAL(body, 64);
195         state->fid_volatile     = BVAL(body, 72);
196
197         offset = IVAL(body, 80);
198         length = IVAL(body, 84);
199
200         if ((offset != 0) && (length != 0)) {
201                 if ((offset != SMB2_HDR_BODY + 88) ||
202                     (length > iov[2].iov_len)) {
203                         tevent_req_nterror(
204                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
205                         return;
206                 }
207                 status = smb2_create_blob_parse(
208                         state, data_blob_const(iov[2].iov_base, length),
209                         &state->blobs);
210                 if (tevent_req_nterror(req, status)) {
211                         return;
212                 }
213         }
214         tevent_req_done(req);
215 }
216
217 NTSTATUS smb2cli_create_recv(struct tevent_req *req,
218                              uint64_t *fid_persistent,
219                              uint64_t *fid_volatile,
220                              struct smb2_create_returns *cr)
221 {
222         struct smb2cli_create_state *state =
223                 tevent_req_data(req,
224                 struct smb2cli_create_state);
225         NTSTATUS status;
226
227         if (tevent_req_is_nterror(req, &status)) {
228                 return status;
229         }
230         *fid_persistent = state->fid_persistent;
231         *fid_volatile = state->fid_volatile;
232         if (cr) {
233                 *cr = state->cr;
234         }
235         return NT_STATUS_OK;
236 }
237
238 NTSTATUS smb2cli_create(struct smbXcli_conn *conn,
239                         uint32_t timeout_msec,
240                         struct smbXcli_session *session,
241                         struct smbXcli_tcon *tcon,
242                         const char *filename,
243                         uint8_t  oplock_level,       /* SMB2_OPLOCK_LEVEL_* */
244                         uint32_t impersonation_level, /* SMB2_IMPERSONATION_* */
245                         uint32_t desired_access,
246                         uint32_t file_attributes,
247                         uint32_t share_access,
248                         uint32_t create_disposition,
249                         uint32_t create_options,
250                         struct smb2_create_blobs *blobs,
251                         uint64_t *fid_persistent,
252                         uint64_t *fid_volatile,
253                         struct smb2_create_returns *cr)
254 {
255         TALLOC_CTX *frame = talloc_stackframe();
256         struct tevent_context *ev;
257         struct tevent_req *req;
258         NTSTATUS status = NT_STATUS_NO_MEMORY;
259
260         if (smbXcli_conn_has_async_calls(conn)) {
261                 /*
262                  * Can't use sync call while an async call is in flight
263                  */
264                 status = NT_STATUS_INVALID_PARAMETER;
265                 goto fail;
266         }
267         ev = samba_tevent_context_init(frame);
268         if (ev == NULL) {
269                 goto fail;
270         }
271         req = smb2cli_create_send(frame, ev, conn, timeout_msec,
272                                   session, tcon,
273                                   filename, oplock_level,
274                                   impersonation_level, desired_access,
275                                   file_attributes, share_access,
276                                   create_disposition, create_options,
277                                   blobs);
278         if (req == NULL) {
279                 goto fail;
280         }
281         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
282                 goto fail;
283         }
284         status = smb2cli_create_recv(req, fid_persistent, fid_volatile, cr);
285  fail:
286         TALLOC_FREE(frame);
287         return status;
288 }