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