libcli/smb: add smb1cli_ntcreatex*
[kai/samba-autobuild/.git] / libcli / smb / smb1cli_create.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Gregor Beck 2013
5    Copyright (C) Stefan Metzmacher 2013
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "system/network.h"
23 #include "lib/util/tevent_ntstatus.h"
24 #include "smb_common.h"
25 #include "smbXcli_base.h"
26
27 static uint8_t *internal_bytes_push_str(uint8_t *buf, bool ucs2,
28                                         const char *str, size_t str_len,
29                                         bool align_odd,
30                                         size_t *pconverted_size)
31 {
32         TALLOC_CTX *frame = talloc_stackframe();
33         size_t buflen;
34         char *converted;
35         size_t converted_size;
36
37         /*
38          * This check prevents us from
39          * (re)alloc buf on a NULL TALLOC_CTX.
40          */
41         if (buf == NULL) {
42                 TALLOC_FREE(frame);
43                 return NULL;
44         }
45
46         buflen = talloc_get_size(buf);
47
48         if (ucs2 &&
49             ((align_odd && (buflen % 2 == 0)) ||
50              (!align_odd && (buflen % 2 == 1)))) {
51                 /*
52                  * We're pushing into an SMB buffer, align odd
53                  */
54                 buf = talloc_realloc(NULL, buf, uint8_t, buflen + 1);
55                 if (buf == NULL) {
56                         TALLOC_FREE(frame);
57                         return NULL;
58                 }
59                 buf[buflen] = '\0';
60                 buflen += 1;
61         }
62
63         if (!convert_string_talloc(frame, CH_UNIX,
64                                    ucs2 ? CH_UTF16LE : CH_DOS,
65                                    str, str_len, &converted,
66                                    &converted_size)) {
67                 TALLOC_FREE(frame);
68                 return NULL;
69         }
70
71         buf = talloc_realloc(NULL, buf, uint8_t,
72                              buflen + converted_size);
73         if (buf == NULL) {
74                 TALLOC_FREE(frame);
75                 return NULL;
76         }
77
78         memcpy(buf + buflen, converted, converted_size);
79
80         TALLOC_FREE(converted);
81
82         if (pconverted_size) {
83                 *pconverted_size = converted_size;
84         }
85
86         TALLOC_FREE(frame);
87         return buf;
88 }
89
90 static uint8_t *smb_bytes_push_str(uint8_t *buf, bool ucs2,
91                                    const char *str, size_t str_len,
92                                    size_t *pconverted_size)
93 {
94         return internal_bytes_push_str(buf, ucs2, str, str_len,
95                                        true, pconverted_size);
96 }
97
98 struct smb1cli_ntcreatex_state {
99         uint16_t vwv[24];
100         uint16_t fnum;
101 };
102
103 static void smb1cli_ntcreatex_done(struct tevent_req *subreq);
104
105 /**
106  * Send an asynchronous SMB_COM_NT_CREATE_ANDX request.
107  * <a href="http://msdn.microsoft.com/en-us/library/ee442175.aspx">MS-CIFS 2.2.4.64.1</a>
108  * @see smb1cli_ntcreatex_recv(), smb1cli_ntcreatex()
109  *
110  * @param[in] mem_ctx The memory context for the result.
111  * @param[in] ev The event context to work on.
112  * @param[in] conn The smb connection.
113  * @param[in] timeout_msec If positiv a timeout for the request.
114  * @param[in] pid The process identifier
115  * @param[in] tcon The smb tree connect.
116  * @param[in] session The smb session.
117  * @param[in] fname The name of the file or directory to be opened or created.
118  * @param[in] CreatFlags
119  * @param[in] RootDirectoryFid The file id of an opened root directory fname is based on. 0 means root of the share.
120  * @param[in] DesiredAccess A field of flags that indicate standard, specific, and generic access rights to be requested.
121  * @param[in] AllocationSize Number of Bytes to allocate if the file is to be created or overwritten.
122  * @param[in] FileAttributes <a href="http://msdn.microsoft.com/en-us/library/ee878573.aspx">Extended file attributes</a>
123  * @param[in] ShareAccess A field that specifies how the file should be shared with other processes.
124  * @param[in] CreateDisposition A value that represents the action to take if the file already exists or if the file is a new file and does not already exist.
125  * @param[in] CreateOptions  A field of flag options to use if creating a file or directory.
126  * @param[in] ImpersonationLevel
127  * @param[in] SecurityFlags
128  *
129  * @return a tevent_req or NULL
130  */
131 struct tevent_req *smb1cli_ntcreatex_send(TALLOC_CTX *mem_ctx,
132                                           struct tevent_context *ev,
133                                           struct smbXcli_conn *conn,
134                                           uint32_t timeout_msec,
135                                           uint32_t pid,
136                                           struct smbXcli_tcon *tcon,
137                                           struct smbXcli_session *session,
138                                           const char *fname,
139                                           uint32_t CreatFlags,
140                                           uint32_t RootDirectoryFid,
141                                           uint32_t DesiredAccess,
142                                           uint64_t AllocationSize,
143                                           uint32_t FileAttributes,
144                                           uint32_t ShareAccess,
145                                           uint32_t CreateDisposition,
146                                           uint32_t CreateOptions,
147                                           uint32_t ImpersonationLevel,
148                                           uint8_t SecurityFlags)
149 {
150         struct tevent_req *req, *subreq;
151         struct smb1cli_ntcreatex_state *state;
152         uint8_t *bytes;
153         size_t converted_len;
154
155         req = tevent_req_create(mem_ctx, &state, struct smb1cli_ntcreatex_state);
156         if (req == NULL) {
157                 return NULL;
158         }
159
160         SCVAL(state->vwv+0, 0, 0xFF);
161         SCVAL(state->vwv+0, 1, 0);
162         SSVAL(state->vwv+1, 0, 0);
163         SCVAL(state->vwv+2, 0, 0);
164         SIVAL(state->vwv+3, 1, CreatFlags);
165         SIVAL(state->vwv+5, 1, RootDirectoryFid);
166         SIVAL(state->vwv+7, 1, DesiredAccess);
167         SBVAL(state->vwv+9, 1, AllocationSize);
168         SIVAL(state->vwv+13, 1, FileAttributes);
169         SIVAL(state->vwv+15, 1, ShareAccess);
170         SIVAL(state->vwv+17, 1, CreateDisposition);
171         SIVAL(state->vwv+19, 1, CreateOptions);
172         SIVAL(state->vwv+21, 1, ImpersonationLevel);
173         SCVAL(state->vwv+23, 1, SecurityFlags);
174
175         bytes = talloc_array(state, uint8_t, 0);
176         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(conn),
177                                    fname, strlen(fname)+1,
178                                    &converted_len);
179
180         /* sigh. this copes with broken netapp filer behaviour */
181         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(conn), "", 1, NULL);
182
183         if (tevent_req_nomem(bytes, req)) {
184                 return tevent_req_post(req, ev);
185         }
186
187         SSVAL(state->vwv+2, 1, converted_len);
188
189         subreq = smb1cli_req_send(state, ev, conn, SMBntcreateX,
190                                   0, 0, /* *_flags */
191                                   0, 0, /* *_flags2 */
192                                   timeout_msec, pid, tcon, session,
193                                   ARRAY_SIZE(state->vwv), state->vwv,
194                                   talloc_get_size(bytes), bytes);
195         if (tevent_req_nomem(subreq, req)) {
196                 return tevent_req_post(req, ev);
197         }
198         tevent_req_set_callback(subreq, smb1cli_ntcreatex_done, req);
199
200         return req;
201 }
202
203 static void smb1cli_ntcreatex_done(struct tevent_req *subreq)
204 {
205         struct tevent_req *req = tevent_req_callback_data(
206                 subreq, struct tevent_req);
207         struct smb1cli_ntcreatex_state *state = tevent_req_data(
208                 req, struct smb1cli_ntcreatex_state);
209         struct iovec *recv_iov = NULL;
210         uint8_t wct;
211         uint16_t *vwv;
212         NTSTATUS status;
213         static const struct smb1cli_req_expected_response expected[] = {
214         {
215                 .status = NT_STATUS_OK,
216                 .wct = 0x22
217         },
218         {
219                 /*
220                  * This is the broken version see from
221                  * [MS-SMB]:
222                  * Windows-based SMB servers send 50 (0x32) words in the extended
223                  * response although they set the WordCount field to 0x2A.
224                  *
225                  * And Samba does the same...
226                  */
227                 .status = NT_STATUS_OK,
228                 .wct = 0x2a
229         },
230         {
231                 .status = NT_STATUS_OK,
232                 .wct = 0x32
233         },
234         };
235
236         status = smb1cli_req_recv(subreq, state,
237                                   &recv_iov,
238                                   NULL, /* phdr */
239                                   &wct,
240                                   &vwv,
241                                   NULL, /* pvwv_offset */
242                                   NULL, /* num_bytes */
243                                   NULL, /* bytes */
244                                   NULL, /* pbytes_offset */
245                                   NULL, /* inbuf */
246                                   expected, ARRAY_SIZE(expected));
247         TALLOC_FREE(subreq);
248         if (tevent_req_nterror(req, status)) {
249                 return;
250         }
251
252         state->fnum = SVAL(vwv+2, 1);
253         tevent_req_done(req);
254 }
255
256 /**
257  * Receive the response to an asynchronous SMB_COM_NT_CREATE_ANDX request.
258  * <a href="http://msdn.microsoft.com/en-us/library/ee441612.aspx">MS-CIFS 2.2.4.64.2</a>
259  *
260  * @param[in] req A tevent request created with smb1cli_ntcreatex_send()
261  * @param[out] pfnum The file id of the opened file or directory.
262  *
263  * @return NT_STATUS_OK on succsess
264  */
265 NTSTATUS smb1cli_ntcreatex_recv(struct tevent_req *req, uint16_t *pfnum)
266 {
267         struct smb1cli_ntcreatex_state *state = tevent_req_data(
268                 req, struct smb1cli_ntcreatex_state);
269         NTSTATUS status;
270
271         if (tevent_req_is_nterror(req, &status)) {
272                 tevent_req_received(req);
273                 return status;
274         }
275
276         *pfnum = state->fnum;
277         tevent_req_received(req);
278         return NT_STATUS_OK;
279 }
280
281
282 /**
283  * Send a synchronous SMB_COM_NT_CREATE_ANDX request.
284  * <a href="http://msdn.microsoft.com/en-us/library/ee442091.aspx">MS-CIFS 2.2.4.64</a>
285  * @see smb1cli_ntcreatex_send() smb1cli_ntcreatex_recv()
286  *
287  * @param[in] conn The smb connection.
288  * @param[in] timeout_msec If positiv a timeout for the request.
289  * @param[in] pid The process identifier
290  * @param[in] tcon The smb tree connect.
291  * @param[in] session The smb session.
292  * @param[in] fname The name of the file or directory to be opened or created.
293  * @param[in] CreatFlags
294  * @param[in] RootDirectoryFid The file id of an opened root directory fname is based on. 0 means root of the share.
295  * @param[in] DesiredAccess A field of flags that indicate standard, specific, and generic access rights to be requested.
296  * @param[in] AllocationSize Number of Bytes to allocate if the file is to be created or overwritten.
297  * @param[in] FileAttributes <a href="http://msdn.microsoft.com/en-us/library/ee878573.aspx">Extended file attributes</a>
298  * @param[in] ShareAccess A field that specifies how the file should be shared with other processes.
299  * @param[in] CreateDisposition A value that represents the action to take if the file already exists or if the file is a new file and does not already exist.
300  * @param[in] CreateOptions  A field of flag options to use if creating a file or directory.
301  * @param[in] ImpersonationLevel
302  * @param[in] SecurityFlags
303  * @param[out] pfnum The file id representing the file or directory created or opened.
304  *
305  * @return  NT_STATUS_OK on succsess
306  */
307 NTSTATUS smb1cli_ntcreatex(struct smbXcli_conn *conn,
308                            uint32_t timeout_msec,
309                            uint32_t pid,
310                            struct smbXcli_tcon *tcon,
311                            struct smbXcli_session *session,
312                            const char *fname,
313                            uint32_t CreatFlags,
314                            uint32_t RootDirectoryFid,
315                            uint32_t DesiredAccess,
316                            uint64_t AllocationSize,
317                            uint32_t FileAttributes,
318                            uint32_t ShareAccess,
319                            uint32_t CreateDisposition,
320                            uint32_t CreateOptions,
321                            uint32_t ImpersonationLevel,
322                            uint8_t SecurityFlags,
323                            uint16_t *pfnum)
324 {
325         TALLOC_CTX *frame = NULL;
326         struct tevent_context *ev;
327         struct tevent_req *req;
328         NTSTATUS status = NT_STATUS_OK;
329
330         frame = talloc_stackframe();
331
332         if (smbXcli_conn_has_async_calls(conn)) {
333                 /*
334                  * Can't use sync call while an async call is in flight
335                  */
336                 status = NT_STATUS_INVALID_PARAMETER;
337                 goto fail;
338         }
339
340         ev = samba_tevent_context_init(frame);
341         if (ev == NULL) {
342                 status = NT_STATUS_NO_MEMORY;
343                 goto fail;
344         }
345
346         req = smb1cli_ntcreatex_send(frame, ev, conn,
347                                      timeout_msec,
348                                      pid, tcon, session,
349                                      fname, CreatFlags, RootDirectoryFid,
350                                      DesiredAccess, AllocationSize,
351                                      FileAttributes, ShareAccess,
352                                      CreateDisposition, CreateOptions,
353                                      ImpersonationLevel, SecurityFlags);
354         if (req == NULL) {
355                 status = NT_STATUS_NO_MEMORY;
356                 goto fail;
357         }
358
359         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
360                 goto fail;
361         }
362
363         status = smb1cli_ntcreatex_recv(req, pfnum);
364 fail:
365         TALLOC_FREE(frame);
366         return status;
367 }