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