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