s3:smb2cli: don't terminate the pathname 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         SIVAL(fixed, 48, blobs_offset + SMB2_HDR_BODY + 56);
118         SIVAL(fixed, 52, blob.length);
119
120         dyn_len = MAX(1, blobs_offset + blob.length);
121         dyn = talloc_zero_array(state, uint8_t, dyn_len);
122         if (tevent_req_nomem(dyn, req)) {
123                 return tevent_req_post(req, ev);
124         }
125
126         if (name_utf16) {
127                 memcpy(dyn, name_utf16, name_utf16_len);
128                 TALLOC_FREE(name_utf16);
129         }
130
131         if (blob.data != NULL) {
132                 memcpy(dyn + blobs_offset - (SMB2_HDR_BODY + 56),
133                        blob.data, blob.length);
134                 data_blob_free(&blob);
135         }
136
137         subreq = smb2cli_req_send(state, ev, cli, SMB2_OP_CREATE,
138                                   0, 0, /* flags */
139                                   cli->smb2.pid,
140                                   cli->smb2.tid,
141                                   cli->smb2.uid,
142                                   state->fixed, sizeof(state->fixed),
143                                   dyn, dyn_len);
144         if (tevent_req_nomem(subreq, req)) {
145                 return tevent_req_post(req, ev);
146         }
147         tevent_req_set_callback(subreq, smb2cli_create_done, req);
148         return req;
149 }
150
151 static void smb2cli_create_done(struct tevent_req *subreq)
152 {
153         struct tevent_req *req =
154                 tevent_req_callback_data(subreq,
155                 struct tevent_req);
156         struct smb2cli_create_state *state =
157                 tevent_req_data(req,
158                 struct smb2cli_create_state);
159         NTSTATUS status;
160         struct iovec *iov;
161         uint8_t *body;
162         uint32_t offset, length;
163
164         status = smb2cli_req_recv(subreq, talloc_tos(), &iov, 89);
165         if (tevent_req_nterror(req, status)) {
166                 return;
167         }
168
169         body = (uint8_t *)iov[1].iov_base;
170
171         state->oplock_level     = CVAL(body, 2);
172         state->create_action    = IVAL(body, 4);
173         state->creation_time    = interpret_long_date((char *)body + 8);
174         state->last_access_time = interpret_long_date((char *)body + 16);
175         state->last_write_time  = interpret_long_date((char *)body + 24);
176         state->change_time      = interpret_long_date((char *)body + 32);
177         state->allocation_size  = BVAL(body, 40);
178         state->end_of_file      = BVAL(body, 48);
179         state->file_attributes  = IVAL(body, 56);
180         state->fid_persistent   = BVAL(body, 64);
181         state->fid_volatile     = BVAL(body, 72);
182
183         offset = IVAL(body, 80);
184         length = IVAL(body, 84);
185
186         if ((offset != 0) && (length != 0)) {
187                 if ((offset != SMB2_HDR_BODY + 88) ||
188                     (length > iov[2].iov_len)) {
189                         tevent_req_nterror(
190                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
191                         return;
192                 }
193                 status = smb2_create_blob_parse(
194                         state, data_blob_const(iov[2].iov_base, length),
195                         &state->blobs);
196                 if (tevent_req_nterror(req, status)) {
197                         return;
198                 }
199         }
200         tevent_req_done(req);
201 }
202
203 NTSTATUS smb2cli_create_recv(struct tevent_req *req,
204                              uint64_t *fid_persistent,
205                              uint64_t *fid_volatile)
206 {
207         struct smb2cli_create_state *state =
208                 tevent_req_data(req,
209                 struct smb2cli_create_state);
210         NTSTATUS status;
211
212         if (tevent_req_is_nterror(req, &status)) {
213                 return status;
214         }
215         *fid_persistent = state->fid_persistent;
216         *fid_volatile = state->fid_volatile;
217         return NT_STATUS_OK;
218 }
219
220 NTSTATUS smb2cli_create(struct cli_state *cli,
221                         const char *filename,
222                         uint8_t  oplock_level,       /* SMB2_OPLOCK_LEVEL_* */
223                         uint32_t impersonation_level, /* SMB2_IMPERSONATION_* */
224                         uint32_t desired_access,
225                         uint32_t file_attributes,
226                         uint32_t share_access,
227                         uint32_t create_disposition,
228                         uint32_t create_options,
229                         struct smb2_create_blobs *blobs,
230                         uint64_t *fid_persistent,
231                         uint64_t *fid_volatile)
232 {
233         TALLOC_CTX *frame = talloc_stackframe();
234         struct event_context *ev;
235         struct tevent_req *req;
236         NTSTATUS status = NT_STATUS_NO_MEMORY;
237
238         if (cli_has_async_calls(cli)) {
239                 /*
240                  * Can't use sync call while an async call is in flight
241                  */
242                 status = NT_STATUS_INVALID_PARAMETER;
243                 goto fail;
244         }
245         ev = event_context_init(frame);
246         if (ev == NULL) {
247                 goto fail;
248         }
249         req = smb2cli_create_send(frame, ev, cli, filename, oplock_level,
250                                   impersonation_level, desired_access,
251                                   file_attributes, share_access,
252                                   create_disposition, create_options,
253                                   blobs);
254         if (req == NULL) {
255                 goto fail;
256         }
257         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
258                 goto fail;
259         }
260         status = smb2cli_create_recv(req, fid_persistent, fid_volatile);
261  fail:
262         TALLOC_FREE(frame);
263         return status;
264 }