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