s3:smb2cli: fix marshalling of smb2_create_blobs in smb2cli_create()
[metze/samba/wip.git] / source3 / libsmb / 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 "client.h"
22 #include "async_smb.h"
23 #include "smb2cli_base.h"
24 #include "smb2cli.h"
25 #include "libsmb/proto.h"
26 #include "lib/util/tevent_ntstatus.h"
27 #include "libcli/smb/smb2_create_blob.h"
28
29 struct smb2cli_create_state {
30         uint8_t fixed[56];
31
32         uint8_t oplock_level;
33         uint32_t create_action;
34         struct timespec creation_time;
35         struct timespec last_access_time;
36         struct timespec last_write_time;
37         struct timespec change_time;
38         uint64_t allocation_size;
39         uint64_t end_of_file;
40         uint32_t file_attributes;
41         uint64_t fid_persistent;
42         uint64_t fid_volatile;
43         struct smb2_create_blobs blobs;
44 };
45
46 static void smb2cli_create_done(struct tevent_req *subreq);
47
48 struct tevent_req *smb2cli_create_send(
49         TALLOC_CTX *mem_ctx,
50         struct tevent_context *ev,
51         struct cli_state *cli,
52         const char *filename,
53         uint8_t  oplock_level,          /* SMB2_OPLOCK_LEVEL_* */
54         uint32_t impersonation_level,   /* SMB2_IMPERSONATION_* */
55         uint32_t desired_access,
56         uint32_t file_attributes,
57         uint32_t share_access,
58         uint32_t create_disposition,
59         uint32_t create_options,
60         struct smb2_create_blobs *blobs)
61 {
62         struct tevent_req *req, *subreq;
63         struct smb2cli_create_state *state;
64         uint8_t *fixed;
65         uint8_t *name_utf16;
66         size_t name_utf16_len;
67         DATA_BLOB blob;
68         NTSTATUS status;
69         size_t blobs_offset;
70         uint8_t *dyn;
71         size_t dyn_len;
72
73         req = tevent_req_create(mem_ctx, &state,
74                                 struct smb2cli_create_state);
75         if (req == NULL) {
76                 return NULL;
77         }
78
79         if (!convert_string_talloc(state, CH_UNIX, CH_UTF16,
80                                    filename, strlen(filename),
81                                    &name_utf16, &name_utf16_len)) {
82                 tevent_req_oom(req);
83                 return tevent_req_post(req, ev);
84         }
85
86         if (strlen(filename) == 0) {
87                 TALLOC_FREE(name_utf16);
88                 name_utf16_len = 0;
89         }
90
91         fixed = state->fixed;
92
93         SSVAL(fixed, 0, 57);
94         SCVAL(fixed, 3, oplock_level);
95         SIVAL(fixed, 4, impersonation_level);
96         SIVAL(fixed, 24, desired_access);
97         SIVAL(fixed, 28, file_attributes);
98         SIVAL(fixed, 32, share_access);
99         SIVAL(fixed, 36, create_disposition);
100         SIVAL(fixed, 40, create_options);
101
102         SSVAL(fixed, 44, SMB2_HDR_BODY + 56);
103         SSVAL(fixed, 46, name_utf16_len);
104
105         blob = data_blob_null;
106
107         if (blobs != NULL) {
108                 status = smb2_create_blob_push(talloc_tos(), &blob, *blobs);
109                 if (tevent_req_nterror(req, status)) {
110                         return tevent_req_post(req, ev);
111                 }
112         }
113
114         blobs_offset = name_utf16_len;
115         blobs_offset = ((blobs_offset + 3) & ~3);
116
117         if (blob.length > 0) {
118                 SIVAL(fixed, 48, blobs_offset + SMB2_HDR_BODY + 56);
119                 SIVAL(fixed, 52, blob.length);
120         }
121
122         dyn_len = MAX(1, blobs_offset + blob.length);
123         dyn = talloc_zero_array(state, uint8_t, dyn_len);
124         if (tevent_req_nomem(dyn, req)) {
125                 return tevent_req_post(req, ev);
126         }
127
128         if (name_utf16) {
129                 memcpy(dyn, name_utf16, name_utf16_len);
130                 TALLOC_FREE(name_utf16);
131         }
132
133         if (blob.data != NULL) {
134                 memcpy(dyn + blobs_offset,
135                        blob.data, blob.length);
136                 data_blob_free(&blob);
137         }
138
139         subreq = smb2cli_req_send(state, ev, cli, SMB2_OP_CREATE,
140                                   0, 0, /* flags */
141                                   cli->smb2.pid,
142                                   cli->smb2.tid,
143                                   cli->smb2.uid,
144                                   state->fixed, sizeof(state->fixed),
145                                   dyn, dyn_len);
146         if (tevent_req_nomem(subreq, req)) {
147                 return tevent_req_post(req, ev);
148         }
149         tevent_req_set_callback(subreq, smb2cli_create_done, req);
150         return req;
151 }
152
153 static void smb2cli_create_done(struct tevent_req *subreq)
154 {
155         struct tevent_req *req =
156                 tevent_req_callback_data(subreq,
157                 struct tevent_req);
158         struct smb2cli_create_state *state =
159                 tevent_req_data(req,
160                 struct smb2cli_create_state);
161         NTSTATUS status;
162         struct iovec *iov;
163         uint8_t *body;
164         uint32_t offset, length;
165
166         status = smb2cli_req_recv(subreq, talloc_tos(), &iov, 89);
167         if (tevent_req_nterror(req, status)) {
168                 return;
169         }
170
171         body = (uint8_t *)iov[1].iov_base;
172
173         state->oplock_level     = CVAL(body, 2);
174         state->create_action    = IVAL(body, 4);
175         state->creation_time    = interpret_long_date((char *)body + 8);
176         state->last_access_time = interpret_long_date((char *)body + 16);
177         state->last_write_time  = interpret_long_date((char *)body + 24);
178         state->change_time      = interpret_long_date((char *)body + 32);
179         state->allocation_size  = BVAL(body, 40);
180         state->end_of_file      = BVAL(body, 48);
181         state->file_attributes  = IVAL(body, 56);
182         state->fid_persistent   = BVAL(body, 64);
183         state->fid_volatile     = BVAL(body, 72);
184
185         offset = IVAL(body, 80);
186         length = IVAL(body, 84);
187
188         if ((offset != 0) && (length != 0)) {
189                 if ((offset != SMB2_HDR_BODY + 88) ||
190                     (length > iov[2].iov_len)) {
191                         tevent_req_nterror(
192                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
193                         return;
194                 }
195                 status = smb2_create_blob_parse(
196                         state, data_blob_const(iov[2].iov_base, length),
197                         &state->blobs);
198                 if (tevent_req_nterror(req, status)) {
199                         return;
200                 }
201         }
202         tevent_req_done(req);
203 }
204
205 NTSTATUS smb2cli_create_recv(struct tevent_req *req,
206                              uint64_t *fid_persistent,
207                              uint64_t *fid_volatile)
208 {
209         struct smb2cli_create_state *state =
210                 tevent_req_data(req,
211                 struct smb2cli_create_state);
212         NTSTATUS status;
213
214         if (tevent_req_is_nterror(req, &status)) {
215                 return status;
216         }
217         *fid_persistent = state->fid_persistent;
218         *fid_volatile = state->fid_volatile;
219         return NT_STATUS_OK;
220 }
221
222 NTSTATUS smb2cli_create(struct cli_state *cli,
223                         const char *filename,
224                         uint8_t  oplock_level,       /* SMB2_OPLOCK_LEVEL_* */
225                         uint32_t impersonation_level, /* SMB2_IMPERSONATION_* */
226                         uint32_t desired_access,
227                         uint32_t file_attributes,
228                         uint32_t share_access,
229                         uint32_t create_disposition,
230                         uint32_t create_options,
231                         struct smb2_create_blobs *blobs,
232                         uint64_t *fid_persistent,
233                         uint64_t *fid_volatile)
234 {
235         TALLOC_CTX *frame = talloc_stackframe();
236         struct event_context *ev;
237         struct tevent_req *req;
238         NTSTATUS status = NT_STATUS_NO_MEMORY;
239
240         if (cli_has_async_calls(cli)) {
241                 /*
242                  * Can't use sync call while an async call is in flight
243                  */
244                 status = NT_STATUS_INVALID_PARAMETER;
245                 goto fail;
246         }
247         ev = event_context_init(frame);
248         if (ev == NULL) {
249                 goto fail;
250         }
251         req = smb2cli_create_send(frame, ev, cli, filename, oplock_level,
252                                   impersonation_level, desired_access,
253                                   file_attributes, share_access,
254                                   create_disposition, create_options,
255                                   blobs);
256         if (req == NULL) {
257                 goto fail;
258         }
259         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
260                 goto fail;
261         }
262         status = smb2cli_create_recv(req, fid_persistent, fid_volatile);
263  fail:
264         TALLOC_FREE(frame);
265         return status;
266 }