Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : transaction2 handling
4 : Copyright (C) Andrew Tridgell 2003
5 : Copyright Matthieu Patou <mat@matws.net> 2010-2011
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 : This file handles the parsing of transact2 requests
22 : */
23 :
24 : #include "includes.h"
25 : #include "samba/service_stream.h"
26 : #include "smb_server/smb_server.h"
27 : #include "ntvfs/ntvfs.h"
28 : #include "libcli/raw/libcliraw.h"
29 : #include "libcli/raw/raw_proto.h"
30 : #include "librpc/gen_ndr/dfsblobs.h"
31 : #include "librpc/gen_ndr/ndr_dfsblobs.h"
32 : #include "dsdb/samdb/samdb.h"
33 : #include "auth/session.h"
34 : #include "param/param.h"
35 : #include "lib/tsocket/tsocket.h"
36 : #include "dfs_server/dfs_server_ad.h"
37 :
38 : #define MAX_DFS_RESPONSE 56*1024 /* 56 Kb */
39 :
40 : #define TRANS2_CHECK_ASYNC_STATUS_SIMPLE do { \
41 : if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) { \
42 : trans2_setup_reply(trans, 0, 0, 0);\
43 : return req->ntvfs->async_states->status; \
44 : } \
45 : } while (0)
46 : #define TRANS2_CHECK_ASYNC_STATUS(ptr, type) do { \
47 : TRANS2_CHECK_ASYNC_STATUS_SIMPLE; \
48 : ptr = talloc_get_type(op->op_info, type); \
49 : } while (0)
50 : #define TRANS2_CHECK(cmd) do { \
51 : NTSTATUS _status; \
52 : _status = cmd; \
53 : NT_STATUS_NOT_OK_RETURN(_status); \
54 : } while (0)
55 :
56 : /*
57 : hold the state of a nttrans op while in progress. Needed to allow for async backend
58 : functions.
59 : */
60 : struct trans_op {
61 : struct smbsrv_request *req;
62 : struct smb_trans2 *trans;
63 : uint8_t command;
64 : NTSTATUS (*send_fn)(struct trans_op *);
65 : void *op_info;
66 : };
67 :
68 : #define CHECK_MIN_BLOB_SIZE(blob, size) do { \
69 : if ((blob)->length < (size)) { \
70 : return NT_STATUS_INFO_LENGTH_MISMATCH; \
71 : }} while (0)
72 :
73 : /* setup a trans2 reply, given the data and params sizes */
74 13628 : static NTSTATUS trans2_setup_reply(struct smb_trans2 *trans,
75 : uint16_t param_size, uint16_t data_size,
76 : uint8_t setup_count)
77 : {
78 13628 : trans->out.setup_count = setup_count;
79 13628 : if (setup_count > 0) {
80 0 : trans->out.setup = talloc_zero_array(trans, uint16_t, setup_count);
81 0 : NT_STATUS_HAVE_NO_MEMORY(trans->out.setup);
82 : }
83 13628 : trans->out.params = data_blob_talloc(trans, NULL, param_size);
84 13628 : if (param_size > 0) NT_STATUS_HAVE_NO_MEMORY(trans->out.params.data);
85 :
86 13628 : trans->out.data = data_blob_talloc(trans, NULL, data_size);
87 13628 : if (data_size > 0) NT_STATUS_HAVE_NO_MEMORY(trans->out.data.data);
88 :
89 13628 : return NT_STATUS_OK;
90 : }
91 :
92 104 : static NTSTATUS trans2_push_fsinfo(struct smbsrv_connection *smb_conn,
93 : TALLOC_CTX *mem_ctx,
94 : DATA_BLOB *blob,
95 : union smb_fsinfo *fsinfo,
96 : int default_str_flags)
97 : {
98 0 : enum smb_fsinfo_level passthru_level;
99 :
100 104 : switch (fsinfo->generic.level) {
101 6 : case RAW_QFS_ALLOCATION:
102 6 : TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 18));
103 :
104 6 : SIVAL(blob->data, 0, fsinfo->allocation.out.fs_id);
105 6 : SIVAL(blob->data, 4, fsinfo->allocation.out.sectors_per_unit);
106 6 : SIVAL(blob->data, 8, fsinfo->allocation.out.total_alloc_units);
107 6 : SIVAL(blob->data, 12, fsinfo->allocation.out.avail_alloc_units);
108 6 : SSVAL(blob->data, 16, fsinfo->allocation.out.bytes_per_sector);
109 :
110 6 : return NT_STATUS_OK;
111 :
112 6 : case RAW_QFS_VOLUME:
113 6 : TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 5));
114 :
115 6 : SIVAL(blob->data, 0, fsinfo->volume.out.serial_number);
116 : /* w2k3 implements this incorrectly for unicode - it
117 : * leaves the last byte off the string */
118 6 : TRANS2_CHECK(smbsrv_blob_append_string(mem_ctx, blob,
119 : fsinfo->volume.out.volume_name.s,
120 : 4, default_str_flags,
121 : STR_LEN8BIT|STR_NOALIGN));
122 :
123 6 : return NT_STATUS_OK;
124 :
125 6 : case RAW_QFS_VOLUME_INFO:
126 6 : passthru_level = RAW_QFS_VOLUME_INFORMATION;
127 6 : break;
128 :
129 16 : case RAW_QFS_SIZE_INFO:
130 16 : passthru_level = RAW_QFS_SIZE_INFORMATION;
131 16 : break;
132 :
133 6 : case RAW_QFS_DEVICE_INFO:
134 6 : passthru_level = RAW_QFS_DEVICE_INFORMATION;
135 6 : break;
136 :
137 10 : case RAW_QFS_ATTRIBUTE_INFO:
138 10 : passthru_level = RAW_QFS_ATTRIBUTE_INFORMATION;
139 10 : break;
140 :
141 54 : default:
142 54 : passthru_level = fsinfo->generic.level;
143 54 : break;
144 : }
145 :
146 92 : return smbsrv_push_passthru_fsinfo(mem_ctx, blob,
147 : passthru_level, fsinfo,
148 : default_str_flags);
149 : }
150 :
151 : /*
152 : trans2 qfsinfo implementation send
153 : */
154 104 : static NTSTATUS trans2_qfsinfo_send(struct trans_op *op)
155 : {
156 104 : struct smbsrv_request *req = op->req;
157 104 : struct smb_trans2 *trans = op->trans;
158 0 : union smb_fsinfo *fsinfo;
159 :
160 104 : TRANS2_CHECK_ASYNC_STATUS(fsinfo, union smb_fsinfo);
161 :
162 104 : TRANS2_CHECK(trans2_setup_reply(trans, 0, 0, 0));
163 :
164 104 : TRANS2_CHECK(trans2_push_fsinfo(req->smb_conn, trans,
165 : &trans->out.data, fsinfo,
166 : SMBSRV_REQ_DEFAULT_STR_FLAGS(req)));
167 :
168 104 : return NT_STATUS_OK;
169 : }
170 :
171 : /*
172 : trans2 qfsinfo implementation
173 : */
174 6063 : static NTSTATUS trans2_qfsinfo(struct smbsrv_request *req, struct trans_op *op)
175 : {
176 6063 : struct smb_trans2 *trans = op->trans;
177 0 : union smb_fsinfo *fsinfo;
178 0 : uint16_t level;
179 :
180 : /* make sure we got enough parameters */
181 6063 : if (trans->in.params.length != 2) {
182 0 : return NT_STATUS_FOOBAR;
183 : }
184 :
185 6063 : fsinfo = talloc(op, union smb_fsinfo);
186 6063 : NT_STATUS_HAVE_NO_MEMORY(fsinfo);
187 :
188 6063 : level = SVAL(trans->in.params.data, 0);
189 :
190 : /* work out the backend level - we make it 1-1 in the header */
191 6063 : fsinfo->generic.level = (enum smb_fsinfo_level)level;
192 6063 : if (fsinfo->generic.level >= RAW_QFS_GENERIC) {
193 0 : return NT_STATUS_INVALID_LEVEL;
194 : }
195 :
196 6063 : op->op_info = fsinfo;
197 6063 : op->send_fn = trans2_qfsinfo_send;
198 :
199 6063 : return ntvfs_fsinfo(req->ntvfs, fsinfo);
200 : }
201 :
202 :
203 : /*
204 : trans2 open implementation send
205 : */
206 11 : static NTSTATUS trans2_open_send(struct trans_op *op)
207 : {
208 11 : struct smbsrv_request *req = op->req;
209 11 : struct smb_trans2 *trans = op->trans;
210 0 : union smb_open *io;
211 :
212 11 : TRANS2_CHECK_ASYNC_STATUS(io, union smb_open);
213 :
214 11 : TRANS2_CHECK(trans2_setup_reply(trans, 30, 0, 0));
215 :
216 11 : smbsrv_push_fnum(trans->out.params.data, VWV(0), io->t2open.out.file.ntvfs);
217 11 : SSVAL(trans->out.params.data, VWV(1), io->t2open.out.attrib);
218 11 : srv_push_dos_date3(req->smb_conn, trans->out.params.data,
219 : VWV(2), io->t2open.out.write_time);
220 11 : SIVAL(trans->out.params.data, VWV(4), io->t2open.out.size);
221 11 : SSVAL(trans->out.params.data, VWV(6), io->t2open.out.access);
222 11 : SSVAL(trans->out.params.data, VWV(7), io->t2open.out.ftype);
223 11 : SSVAL(trans->out.params.data, VWV(8), io->t2open.out.devstate);
224 11 : SSVAL(trans->out.params.data, VWV(9), io->t2open.out.action);
225 11 : SIVAL(trans->out.params.data, VWV(10), 0); /* reserved */
226 11 : SSVAL(trans->out.params.data, VWV(12), 0); /* EaErrorOffset */
227 11 : SIVAL(trans->out.params.data, VWV(13), 0); /* EaLength */
228 :
229 11 : return NT_STATUS_OK;
230 : }
231 :
232 : /*
233 : trans2 open implementation
234 : */
235 17 : static NTSTATUS trans2_open(struct smbsrv_request *req, struct trans_op *op)
236 : {
237 17 : struct smb_trans2 *trans = op->trans;
238 0 : union smb_open *io;
239 :
240 : /* make sure we got enough parameters */
241 17 : if (trans->in.params.length < 29) {
242 0 : return NT_STATUS_FOOBAR;
243 : }
244 :
245 17 : io = talloc(op, union smb_open);
246 17 : NT_STATUS_HAVE_NO_MEMORY(io);
247 :
248 17 : io->t2open.level = RAW_OPEN_T2OPEN;
249 17 : io->t2open.in.flags = SVAL(trans->in.params.data, VWV(0));
250 17 : io->t2open.in.open_mode = SVAL(trans->in.params.data, VWV(1));
251 17 : io->t2open.in.search_attrs = SVAL(trans->in.params.data, VWV(2));
252 17 : io->t2open.in.file_attrs = SVAL(trans->in.params.data, VWV(3));
253 34 : io->t2open.in.write_time = srv_pull_dos_date(req->smb_conn,
254 17 : trans->in.params.data + VWV(4));
255 17 : io->t2open.in.open_func = SVAL(trans->in.params.data, VWV(6));
256 17 : io->t2open.in.size = IVAL(trans->in.params.data, VWV(7));
257 17 : io->t2open.in.timeout = IVAL(trans->in.params.data, VWV(9));
258 17 : io->t2open.in.num_eas = 0;
259 17 : io->t2open.in.eas = NULL;
260 :
261 17 : smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 28, &io->t2open.in.fname, 0);
262 17 : if (io->t2open.in.fname == NULL) {
263 0 : return NT_STATUS_FOOBAR;
264 : }
265 :
266 17 : TRANS2_CHECK(ea_pull_list(&trans->in.data, io, &io->t2open.in.num_eas, &io->t2open.in.eas));
267 :
268 17 : op->op_info = io;
269 17 : op->send_fn = trans2_open_send;
270 :
271 17 : return ntvfs_open(req->ntvfs, io);
272 : }
273 :
274 :
275 : /*
276 : trans2 simple send
277 : */
278 1226 : static NTSTATUS trans2_simple_send(struct trans_op *op)
279 : {
280 1226 : struct smbsrv_request *req = op->req;
281 1226 : struct smb_trans2 *trans = op->trans;
282 :
283 1226 : TRANS2_CHECK_ASYNC_STATUS_SIMPLE;
284 :
285 1226 : TRANS2_CHECK(trans2_setup_reply(trans, 2, 0, 0));
286 :
287 1226 : SSVAL(trans->out.params.data, VWV(0), 0);
288 :
289 1226 : return NT_STATUS_OK;
290 : }
291 :
292 : /*
293 : trans2 mkdir implementation
294 : */
295 3 : static NTSTATUS trans2_mkdir(struct smbsrv_request *req, struct trans_op *op)
296 : {
297 3 : struct smb_trans2 *trans = op->trans;
298 0 : union smb_mkdir *io;
299 :
300 : /* make sure we got enough parameters */
301 3 : if (trans->in.params.length < 5) {
302 0 : return NT_STATUS_FOOBAR;
303 : }
304 :
305 3 : io = talloc(op, union smb_mkdir);
306 3 : NT_STATUS_HAVE_NO_MEMORY(io);
307 :
308 3 : io->t2mkdir.level = RAW_MKDIR_T2MKDIR;
309 3 : smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 4, &io->t2mkdir.in.path, 0);
310 3 : if (io->t2mkdir.in.path == NULL) {
311 0 : return NT_STATUS_FOOBAR;
312 : }
313 :
314 3 : TRANS2_CHECK(ea_pull_list(&trans->in.data, io,
315 : &io->t2mkdir.in.num_eas,
316 : &io->t2mkdir.in.eas));
317 :
318 3 : op->op_info = io;
319 3 : op->send_fn = trans2_simple_send;
320 :
321 3 : return ntvfs_mkdir(req->ntvfs, io);
322 : }
323 :
324 1729 : static NTSTATUS trans2_push_fileinfo(struct smbsrv_connection *smb_conn,
325 : TALLOC_CTX *mem_ctx,
326 : DATA_BLOB *blob,
327 : union smb_fileinfo *st,
328 : int default_str_flags)
329 : {
330 0 : uint32_t list_size;
331 0 : enum smb_fileinfo_level passthru_level;
332 :
333 1729 : switch (st->generic.level) {
334 0 : case RAW_FILEINFO_GENERIC:
335 : case RAW_FILEINFO_GETATTR:
336 : case RAW_FILEINFO_GETATTRE:
337 : case RAW_FILEINFO_SEC_DESC:
338 : case RAW_FILEINFO_SMB2_ALL_EAS:
339 : case RAW_FILEINFO_SMB2_ALL_INFORMATION:
340 : /* handled elsewhere */
341 249 : return NT_STATUS_INVALID_LEVEL;
342 :
343 0 : case RAW_FILEINFO_UNIX_BASIC:
344 : case RAW_FILEINFO_UNIX_LINK:
345 : /* not implemented yet */
346 0 : return NT_STATUS_INVALID_LEVEL;
347 :
348 213 : case RAW_FILEINFO_STANDARD:
349 213 : TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 22));
350 :
351 213 : srv_push_dos_date2(smb_conn, blob->data, 0, st->standard.out.create_time);
352 213 : srv_push_dos_date2(smb_conn, blob->data, 4, st->standard.out.access_time);
353 213 : srv_push_dos_date2(smb_conn, blob->data, 8, st->standard.out.write_time);
354 213 : SIVAL(blob->data, 12, st->standard.out.size);
355 213 : SIVAL(blob->data, 16, st->standard.out.alloc_size);
356 213 : SSVAL(blob->data, 20, st->standard.out.attrib);
357 213 : return NT_STATUS_OK;
358 :
359 9 : case RAW_FILEINFO_EA_SIZE:
360 9 : TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 26));
361 :
362 9 : srv_push_dos_date2(smb_conn, blob->data, 0, st->ea_size.out.create_time);
363 9 : srv_push_dos_date2(smb_conn, blob->data, 4, st->ea_size.out.access_time);
364 9 : srv_push_dos_date2(smb_conn, blob->data, 8, st->ea_size.out.write_time);
365 9 : SIVAL(blob->data, 12, st->ea_size.out.size);
366 9 : SIVAL(blob->data, 16, st->ea_size.out.alloc_size);
367 9 : SSVAL(blob->data, 20, st->ea_size.out.attrib);
368 9 : SIVAL(blob->data, 22, st->ea_size.out.ea_size);
369 9 : return NT_STATUS_OK;
370 :
371 6 : case RAW_FILEINFO_EA_LIST:
372 6 : list_size = ea_list_size(st->ea_list.out.num_eas,
373 : st->ea_list.out.eas);
374 6 : TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, list_size));
375 :
376 6 : ea_put_list(blob->data,
377 : st->ea_list.out.num_eas, st->ea_list.out.eas);
378 6 : return NT_STATUS_OK;
379 :
380 12 : case RAW_FILEINFO_ALL_EAS:
381 12 : list_size = ea_list_size(st->all_eas.out.num_eas,
382 : st->all_eas.out.eas);
383 12 : TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, list_size));
384 :
385 12 : ea_put_list(blob->data,
386 : st->all_eas.out.num_eas, st->all_eas.out.eas);
387 12 : return NT_STATUS_OK;
388 :
389 9 : case RAW_FILEINFO_IS_NAME_VALID:
390 9 : return NT_STATUS_OK;
391 :
392 297 : case RAW_FILEINFO_BASIC_INFO:
393 297 : passthru_level = RAW_FILEINFO_BASIC_INFORMATION;
394 297 : break;
395 :
396 220 : case RAW_FILEINFO_STANDARD_INFO:
397 220 : passthru_level = RAW_FILEINFO_STANDARD_INFORMATION;
398 220 : break;
399 :
400 9 : case RAW_FILEINFO_EA_INFO:
401 9 : passthru_level = RAW_FILEINFO_EA_INFORMATION;
402 9 : break;
403 :
404 10 : case RAW_FILEINFO_COMPRESSION_INFO:
405 10 : passthru_level = RAW_FILEINFO_COMPRESSION_INFORMATION;
406 10 : break;
407 :
408 586 : case RAW_FILEINFO_ALL_INFO:
409 586 : passthru_level = RAW_FILEINFO_ALL_INFORMATION;
410 586 : break;
411 :
412 55 : case RAW_FILEINFO_NAME_INFO:
413 55 : passthru_level = RAW_FILEINFO_NAME_INFORMATION;
414 55 : break;
415 :
416 45 : case RAW_FILEINFO_ALT_NAME_INFO:
417 45 : passthru_level = RAW_FILEINFO_ALT_NAME_INFORMATION;
418 45 : break;
419 :
420 26 : case RAW_FILEINFO_STREAM_INFO:
421 26 : passthru_level = RAW_FILEINFO_STREAM_INFORMATION;
422 26 : break;
423 :
424 232 : default:
425 232 : passthru_level = st->generic.level;
426 232 : break;
427 : }
428 :
429 1480 : return smbsrv_push_passthru_fileinfo(mem_ctx, blob,
430 : passthru_level, st,
431 : default_str_flags);
432 : }
433 :
434 : /*
435 : fill in the reply from a qpathinfo or qfileinfo call
436 : */
437 1729 : static NTSTATUS trans2_fileinfo_send(struct trans_op *op)
438 : {
439 1729 : struct smbsrv_request *req = op->req;
440 1729 : struct smb_trans2 *trans = op->trans;
441 0 : union smb_fileinfo *st;
442 :
443 1729 : TRANS2_CHECK_ASYNC_STATUS(st, union smb_fileinfo);
444 :
445 1729 : TRANS2_CHECK(trans2_setup_reply(trans, 2, 0, 0));
446 1729 : SSVAL(trans->out.params.data, 0, 0);
447 :
448 1729 : TRANS2_CHECK(trans2_push_fileinfo(req->smb_conn, trans,
449 : &trans->out.data, st,
450 : SMBSRV_REQ_DEFAULT_STR_FLAGS(req)));
451 :
452 1729 : return NT_STATUS_OK;
453 : }
454 :
455 : /*
456 : trans2 qpathinfo implementation
457 : */
458 6833 : static NTSTATUS trans2_qpathinfo(struct smbsrv_request *req, struct trans_op *op)
459 : {
460 6833 : struct smb_trans2 *trans = op->trans;
461 0 : union smb_fileinfo *st;
462 0 : uint16_t level;
463 :
464 : /* make sure we got enough parameters */
465 6833 : if (trans->in.params.length < 2) {
466 0 : return NT_STATUS_FOOBAR;
467 : }
468 :
469 6833 : st = talloc(op, union smb_fileinfo);
470 6833 : NT_STATUS_HAVE_NO_MEMORY(st);
471 :
472 6833 : level = SVAL(trans->in.params.data, 0);
473 :
474 6833 : smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 6, &st->generic.in.file.path, 0);
475 6833 : if (st->generic.in.file.path == NULL) {
476 0 : return NT_STATUS_FOOBAR;
477 : }
478 :
479 : /* work out the backend level - we make it 1-1 in the header */
480 6833 : st->generic.level = (enum smb_fileinfo_level)level;
481 6833 : if (st->generic.level >= RAW_FILEINFO_GENERIC) {
482 0 : return NT_STATUS_INVALID_LEVEL;
483 : }
484 :
485 6833 : if (st->generic.level == RAW_FILEINFO_EA_LIST) {
486 9 : TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
487 : &st->ea_list.in.num_names,
488 : &st->ea_list.in.ea_names));
489 : }
490 :
491 6831 : op->op_info = st;
492 6831 : op->send_fn = trans2_fileinfo_send;
493 :
494 6831 : return ntvfs_qpathinfo(req->ntvfs, st);
495 : }
496 :
497 :
498 : /*
499 : trans2 qpathinfo implementation
500 : */
501 7046 : static NTSTATUS trans2_qfileinfo(struct smbsrv_request *req, struct trans_op *op)
502 : {
503 7046 : struct smb_trans2 *trans = op->trans;
504 0 : union smb_fileinfo *st;
505 0 : uint16_t level;
506 0 : struct ntvfs_handle *h;
507 :
508 : /* make sure we got enough parameters */
509 7046 : if (trans->in.params.length < 4) {
510 0 : return NT_STATUS_FOOBAR;
511 : }
512 :
513 7046 : st = talloc(op, union smb_fileinfo);
514 7046 : NT_STATUS_HAVE_NO_MEMORY(st);
515 :
516 7046 : h = smbsrv_pull_fnum(req, trans->in.params.data, 0);
517 7046 : level = SVAL(trans->in.params.data, 2);
518 :
519 7046 : st->generic.in.file.ntvfs = h;
520 : /* work out the backend level - we make it 1-1 in the header */
521 7046 : st->generic.level = (enum smb_fileinfo_level)level;
522 7046 : if (st->generic.level >= RAW_FILEINFO_GENERIC) {
523 0 : return NT_STATUS_INVALID_LEVEL;
524 : }
525 :
526 7046 : if (st->generic.level == RAW_FILEINFO_EA_LIST) {
527 2 : TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
528 : &st->ea_list.in.num_names,
529 : &st->ea_list.in.ea_names));
530 : }
531 :
532 7044 : op->op_info = st;
533 7044 : op->send_fn = trans2_fileinfo_send;
534 :
535 7044 : SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st->generic.in.file.ntvfs);
536 7006 : return ntvfs_qfileinfo(req->ntvfs, st);
537 : }
538 :
539 :
540 : /*
541 : parse a trans2 setfileinfo/setpathinfo data blob
542 : */
543 5928 : static NTSTATUS trans2_parse_sfileinfo(struct smbsrv_request *req,
544 : union smb_setfileinfo *st,
545 : const DATA_BLOB *blob)
546 : {
547 0 : enum smb_setfileinfo_level passthru_level;
548 :
549 5928 : switch (st->generic.level) {
550 0 : case RAW_SFILEINFO_GENERIC:
551 : case RAW_SFILEINFO_SETATTR:
552 : case RAW_SFILEINFO_SETATTRE:
553 : case RAW_SFILEINFO_SEC_DESC:
554 : /* handled elsewhere */
555 4673 : return NT_STATUS_INVALID_LEVEL;
556 :
557 27 : case RAW_SFILEINFO_STANDARD:
558 27 : CHECK_MIN_BLOB_SIZE(blob, 12);
559 :
560 7 : st->standard.in.create_time = srv_pull_dos_date2(req->smb_conn, blob->data + 0);
561 7 : st->standard.in.access_time = srv_pull_dos_date2(req->smb_conn, blob->data + 4);
562 7 : st->standard.in.write_time = srv_pull_dos_date2(req->smb_conn, blob->data + 8);
563 :
564 7 : return NT_STATUS_OK;
565 :
566 300 : case RAW_SFILEINFO_EA_SET:
567 300 : return ea_pull_list(blob, req,
568 : &st->ea_set.in.num_eas,
569 : &st->ea_set.in.eas);
570 :
571 487 : case SMB_SFILEINFO_BASIC_INFO:
572 : case SMB_SFILEINFO_BASIC_INFORMATION:
573 487 : passthru_level = SMB_SFILEINFO_BASIC_INFORMATION;
574 487 : break;
575 :
576 107 : case SMB_SFILEINFO_DISPOSITION_INFO:
577 : case SMB_SFILEINFO_DISPOSITION_INFORMATION:
578 107 : passthru_level = SMB_SFILEINFO_DISPOSITION_INFORMATION;
579 107 : break;
580 :
581 19 : case SMB_SFILEINFO_ALLOCATION_INFO:
582 : case SMB_SFILEINFO_ALLOCATION_INFORMATION:
583 19 : passthru_level = SMB_SFILEINFO_ALLOCATION_INFORMATION;
584 19 : break;
585 :
586 567 : case RAW_SFILEINFO_END_OF_FILE_INFO:
587 : case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
588 567 : passthru_level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
589 567 : break;
590 :
591 75 : case RAW_SFILEINFO_RENAME_INFORMATION:
592 : case RAW_SFILEINFO_POSITION_INFORMATION:
593 : case RAW_SFILEINFO_MODE_INFORMATION:
594 75 : passthru_level = st->generic.level;
595 75 : break;
596 :
597 68 : case RAW_SFILEINFO_UNIX_BASIC:
598 : case RAW_SFILEINFO_UNIX_LINK:
599 : case RAW_SFILEINFO_UNIX_HLINK:
600 : case RAW_SFILEINFO_PIPE_INFORMATION:
601 : case RAW_SFILEINFO_VALID_DATA_INFORMATION:
602 : case RAW_SFILEINFO_SHORT_NAME_INFORMATION:
603 : case RAW_SFILEINFO_1025:
604 : case RAW_SFILEINFO_1027:
605 : case RAW_SFILEINFO_1029:
606 : case RAW_SFILEINFO_1030:
607 : case RAW_SFILEINFO_1031:
608 : case RAW_SFILEINFO_1032:
609 : case RAW_SFILEINFO_1036:
610 : case RAW_SFILEINFO_1041:
611 : case RAW_SFILEINFO_1042:
612 : case RAW_SFILEINFO_1043:
613 : case RAW_SFILEINFO_1044:
614 68 : return NT_STATUS_INVALID_LEVEL;
615 :
616 4278 : default:
617 : /* we need a default here to cope with invalid values on the wire */
618 4278 : return NT_STATUS_INVALID_LEVEL;
619 : }
620 :
621 1255 : return smbsrv_pull_passthru_sfileinfo(st, passthru_level, st,
622 1255 : blob, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
623 : &req->in.bufinfo);
624 : }
625 :
626 : /*
627 : trans2 setfileinfo implementation
628 : */
629 3656 : static NTSTATUS trans2_setfileinfo(struct smbsrv_request *req, struct trans_op *op)
630 : {
631 3656 : struct smb_trans2 *trans = op->trans;
632 0 : union smb_setfileinfo *st;
633 0 : uint16_t level;
634 0 : struct ntvfs_handle *h;
635 :
636 : /* make sure we got enough parameters */
637 3656 : if (trans->in.params.length < 4) {
638 0 : return NT_STATUS_FOOBAR;
639 : }
640 :
641 3656 : st = talloc(op, union smb_setfileinfo);
642 3656 : NT_STATUS_HAVE_NO_MEMORY(st);
643 :
644 3656 : h = smbsrv_pull_fnum(req, trans->in.params.data, 0);
645 3656 : level = SVAL(trans->in.params.data, 2);
646 :
647 3656 : st->generic.in.file.ntvfs = h;
648 : /* work out the backend level - we make it 1-1 in the header */
649 3656 : st->generic.level = (enum smb_setfileinfo_level)level;
650 3656 : if (st->generic.level >= RAW_SFILEINFO_GENERIC) {
651 0 : return NT_STATUS_INVALID_LEVEL;
652 : }
653 :
654 3656 : TRANS2_CHECK(trans2_parse_sfileinfo(req, st, &trans->in.data));
655 :
656 1452 : op->op_info = st;
657 1452 : op->send_fn = trans2_simple_send;
658 :
659 1452 : SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st->generic.in.file.ntvfs);
660 1452 : return ntvfs_setfileinfo(req->ntvfs, st);
661 : }
662 :
663 : /*
664 : trans2 setpathinfo implementation
665 : */
666 2272 : static NTSTATUS trans2_setpathinfo(struct smbsrv_request *req, struct trans_op *op)
667 : {
668 2272 : struct smb_trans2 *trans = op->trans;
669 0 : union smb_setfileinfo *st;
670 0 : uint16_t level;
671 :
672 : /* make sure we got enough parameters */
673 2272 : if (trans->in.params.length < 4) {
674 0 : return NT_STATUS_FOOBAR;
675 : }
676 :
677 2272 : st = talloc(op, union smb_setfileinfo);
678 2272 : NT_STATUS_HAVE_NO_MEMORY(st);
679 :
680 2272 : level = SVAL(trans->in.params.data, 0);
681 :
682 2272 : smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 6, &st->generic.in.file.path, 0);
683 2272 : if (st->generic.in.file.path == NULL) {
684 0 : return NT_STATUS_FOOBAR;
685 : }
686 :
687 : /* work out the backend level - we make it 1-1 in the header */
688 2272 : st->generic.level = (enum smb_setfileinfo_level)level;
689 2272 : if (st->generic.level >= RAW_SFILEINFO_GENERIC) {
690 0 : return NT_STATUS_INVALID_LEVEL;
691 : }
692 :
693 2272 : TRANS2_CHECK(trans2_parse_sfileinfo(req, st, &trans->in.data));
694 :
695 70 : op->op_info = st;
696 70 : op->send_fn = trans2_simple_send;
697 :
698 70 : return ntvfs_setpathinfo(req->ntvfs, st);
699 : }
700 :
701 :
702 : /* a structure to encapsulate the state information about an in-progress ffirst/fnext operation */
703 : struct find_state {
704 : struct trans_op *op;
705 : void *search;
706 : enum smb_search_data_level data_level;
707 : uint16_t last_entry_offset;
708 : uint16_t flags;
709 : };
710 :
711 : /*
712 : fill a single entry in a trans2 find reply
713 : */
714 47139 : static NTSTATUS find_fill_info(struct find_state *state,
715 : const union smb_search_data *file)
716 : {
717 47139 : struct smbsrv_request *req = state->op->req;
718 47139 : struct smb_trans2 *trans = state->op->trans;
719 0 : uint8_t *data;
720 47139 : unsigned int ofs = trans->out.data.length;
721 0 : uint32_t ea_size;
722 :
723 47139 : switch (state->data_level) {
724 0 : case RAW_SEARCH_DATA_GENERIC:
725 : case RAW_SEARCH_DATA_SEARCH:
726 : /* handled elsewhere */
727 26628 : return NT_STATUS_INVALID_LEVEL;
728 :
729 2104 : case RAW_SEARCH_DATA_STANDARD:
730 2104 : if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
731 700 : TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 27));
732 700 : SIVAL(trans->out.data.data, ofs, file->standard.resume_key);
733 700 : ofs += 4;
734 : } else {
735 1404 : TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 23));
736 : }
737 2104 : data = trans->out.data.data + ofs;
738 2104 : srv_push_dos_date2(req->smb_conn, data, 0, file->standard.create_time);
739 2104 : srv_push_dos_date2(req->smb_conn, data, 4, file->standard.access_time);
740 2104 : srv_push_dos_date2(req->smb_conn, data, 8, file->standard.write_time);
741 2104 : SIVAL(data, 12, file->standard.size);
742 2104 : SIVAL(data, 16, file->standard.alloc_size);
743 2104 : SSVAL(data, 20, file->standard.attrib);
744 2104 : TRANS2_CHECK(smbsrv_blob_append_string(trans, &trans->out.data, file->standard.name.s,
745 : ofs + 22, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
746 : STR_LEN8BIT | STR_TERMINATE | STR_LEN_NOTERM));
747 20511 : break;
748 :
749 18404 : case RAW_SEARCH_DATA_EA_SIZE:
750 18404 : if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
751 17000 : TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 31));
752 17000 : SIVAL(trans->out.data.data, ofs, file->ea_size.resume_key);
753 17000 : ofs += 4;
754 : } else {
755 1404 : TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 27));
756 : }
757 18404 : data = trans->out.data.data + ofs;
758 18404 : srv_push_dos_date2(req->smb_conn, data, 0, file->ea_size.create_time);
759 18404 : srv_push_dos_date2(req->smb_conn, data, 4, file->ea_size.access_time);
760 18404 : srv_push_dos_date2(req->smb_conn, data, 8, file->ea_size.write_time);
761 18404 : SIVAL(data, 12, file->ea_size.size);
762 18404 : SIVAL(data, 16, file->ea_size.alloc_size);
763 18404 : SSVAL(data, 20, file->ea_size.attrib);
764 18404 : SIVAL(data, 22, file->ea_size.ea_size);
765 18404 : TRANS2_CHECK(smbsrv_blob_append_string(trans, &trans->out.data, file->ea_size.name.s,
766 : ofs + 26, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
767 : STR_LEN8BIT | STR_NOALIGN));
768 18404 : TRANS2_CHECK(smbsrv_blob_fill_data(trans, &trans->out.data, trans->out.data.length + 1));
769 18404 : break;
770 :
771 3 : case RAW_SEARCH_DATA_EA_LIST:
772 3 : ea_size = ea_list_size(file->ea_list.eas.num_eas, file->ea_list.eas.eas);
773 3 : if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
774 3 : TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 27 + ea_size));
775 3 : SIVAL(trans->out.data.data, ofs, file->ea_list.resume_key);
776 3 : ofs += 4;
777 : } else {
778 0 : TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 23 + ea_size));
779 : }
780 3 : data = trans->out.data.data + ofs;
781 3 : srv_push_dos_date2(req->smb_conn, data, 0, file->ea_list.create_time);
782 3 : srv_push_dos_date2(req->smb_conn, data, 4, file->ea_list.access_time);
783 3 : srv_push_dos_date2(req->smb_conn, data, 8, file->ea_list.write_time);
784 3 : SIVAL(data, 12, file->ea_list.size);
785 3 : SIVAL(data, 16, file->ea_list.alloc_size);
786 3 : SSVAL(data, 20, file->ea_list.attrib);
787 3 : ea_put_list(data+22, file->ea_list.eas.num_eas, file->ea_list.eas.eas);
788 3 : TRANS2_CHECK(smbsrv_blob_append_string(trans, &trans->out.data, file->ea_list.name.s,
789 : ofs + 22 + ea_size, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
790 : STR_LEN8BIT | STR_NOALIGN));
791 3 : TRANS2_CHECK(smbsrv_blob_fill_data(trans, &trans->out.data, trans->out.data.length + 1));
792 3 : break;
793 :
794 26628 : case RAW_SEARCH_DATA_DIRECTORY_INFO:
795 : case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO:
796 : case RAW_SEARCH_DATA_NAME_INFO:
797 : case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO:
798 : case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO:
799 : case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO:
800 26628 : return smbsrv_push_passthru_search(trans, &trans->out.data, state->data_level, file,
801 26628 : SMBSRV_REQ_DEFAULT_STR_FLAGS(req));
802 :
803 0 : case RAW_SEARCH_DATA_UNIX_INFO:
804 : case RAW_SEARCH_DATA_UNIX_INFO2:
805 0 : return NT_STATUS_INVALID_LEVEL;
806 : }
807 :
808 20511 : return NT_STATUS_OK;
809 : }
810 :
811 : /* callback function for trans2 findfirst/findnext */
812 47139 : static bool find_callback(void *private_data, const union smb_search_data *file)
813 : {
814 47139 : struct find_state *state = talloc_get_type(private_data, struct find_state);
815 47139 : struct smb_trans2 *trans = state->op->trans;
816 0 : unsigned int old_length;
817 :
818 47139 : old_length = trans->out.data.length;
819 :
820 47139 : if (!NT_STATUS_IS_OK(find_fill_info(state, file)) ||
821 47139 : trans->out.data.length > trans->in.max_data) {
822 : /* restore the old length and tell the backend to stop */
823 1 : smbsrv_blob_grow_data(trans, &trans->out.data, old_length);
824 1 : return false;
825 : }
826 :
827 47138 : state->last_entry_offset = old_length;
828 47138 : return true;
829 : }
830 :
831 : /*
832 : trans2 findfirst send
833 : */
834 3942 : static NTSTATUS trans2_findfirst_send(struct trans_op *op)
835 : {
836 3942 : struct smbsrv_request *req = op->req;
837 3942 : struct smb_trans2 *trans = op->trans;
838 0 : union smb_search_first *search;
839 0 : struct find_state *state;
840 0 : uint8_t *param;
841 :
842 3942 : TRANS2_CHECK_ASYNC_STATUS(state, struct find_state);
843 3942 : search = talloc_get_type(state->search, union smb_search_first);
844 :
845 : /* fill in the findfirst reply header */
846 3942 : param = trans->out.params.data;
847 3942 : SSVAL(param, VWV(0), search->t2ffirst.out.handle);
848 3942 : SSVAL(param, VWV(1), search->t2ffirst.out.count);
849 3942 : SSVAL(param, VWV(2), search->t2ffirst.out.end_of_search);
850 3942 : SSVAL(param, VWV(3), 0);
851 3942 : SSVAL(param, VWV(4), state->last_entry_offset);
852 :
853 3942 : return NT_STATUS_OK;
854 : }
855 :
856 : /*
857 : trans2 getdfsreferral implementation
858 : */
859 17 : static NTSTATUS trans2_getdfsreferral(struct smbsrv_request *req,
860 : struct trans_op *op)
861 : {
862 0 : enum ndr_err_code ndr_err;
863 17 : struct smb_trans2 *trans = op->trans;
864 0 : struct ldb_context *ldb;
865 0 : struct loadparm_context *lp_ctx;
866 0 : NTSTATUS status;
867 0 : struct dfs_GetDFSReferral *r;
868 17 : DATA_BLOB outblob = data_blob_null;
869 17 : uint16_t nb_referrals = 0;
870 :
871 17 : lp_ctx = req->tcon->ntvfs->lp_ctx;
872 17 : if (!lpcfg_host_msdfs(lp_ctx)) {
873 0 : return NT_STATUS_NOT_IMPLEMENTED;
874 : }
875 :
876 17 : r = talloc_zero(req, struct dfs_GetDFSReferral);
877 17 : NT_STATUS_HAVE_NO_MEMORY(r);
878 :
879 17 : ldb = samdb_connect(r,
880 17 : req->tcon->ntvfs->event_ctx,
881 : lp_ctx,
882 : system_session(lp_ctx),
883 : NULL,
884 : 0);
885 17 : if (ldb == NULL) {
886 0 : DEBUG(2,(__location__ ": Failed to open samdb\n"));
887 0 : talloc_free(r);
888 0 : return NT_STATUS_INTERNAL_ERROR;
889 : }
890 :
891 17 : ndr_err = ndr_pull_struct_blob(&trans->in.params, r,
892 17 : &r->in.req,
893 : (ndr_pull_flags_fn_t)ndr_pull_dfs_GetDFSReferral_in);
894 17 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
895 0 : status = ndr_map_error2ntstatus(ndr_err);
896 0 : DEBUG(2,(__location__ ": Failed to parse GetDFSReferral_in - %s\n",
897 : nt_errstr(status)));
898 0 : talloc_free(r);
899 0 : return status;
900 : }
901 :
902 17 : DEBUG(8, ("Requested DFS name: %s length: %u\n",
903 : r->in.req.servername,
904 : (unsigned int)strlen_m(r->in.req.servername)*2));
905 :
906 17 : status = dfs_server_ad_get_referrals(lp_ctx, ldb,
907 17 : req->smb_conn->connection->remote_address, r);
908 17 : if (!NT_STATUS_IS_OK(status)) {
909 3 : talloc_free(r);
910 3 : return status;
911 : }
912 :
913 14 : ndr_err = ndr_push_struct_blob(&outblob, trans,
914 14 : r->out.resp,
915 : (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
916 14 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
917 0 : DEBUG(2,(__location__ ":NDR marshalling of domain referral response failed\n"));
918 0 : talloc_free(r);
919 0 : return NT_STATUS_INTERNAL_ERROR;
920 : }
921 :
922 14 : nb_referrals = r->out.resp->nb_referrals;
923 :
924 14 : if (outblob.length > trans->in.max_data) {
925 0 : bool ok = false;
926 :
927 0 : DEBUG(3, ("Blob is too big for the output buffer "
928 : "size %u max %u\n",
929 : (unsigned int)outblob.length, trans->in.max_data));
930 :
931 0 : if (trans->in.max_data != MAX_DFS_RESPONSE) {
932 : /* As specified in MS-DFSC.pdf 3.3.5.2 */
933 0 : talloc_free(r);
934 0 : return STATUS_BUFFER_OVERFLOW;
935 : }
936 :
937 : /*
938 : * The answer is too big, so let's remove some answers
939 : */
940 0 : while (!ok && r->out.resp->nb_referrals > 2) {
941 0 : data_blob_free(&outblob);
942 :
943 : /*
944 : * Let's scrap the last referral (for now)
945 : */
946 0 : r->out.resp->nb_referrals -= 1;
947 :
948 0 : ndr_err = ndr_push_struct_blob(&outblob, trans,
949 0 : r->out.resp,
950 : (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
951 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
952 0 : talloc_free(r);
953 0 : return NT_STATUS_INTERNAL_ERROR;
954 : }
955 :
956 0 : if (outblob.length <= MAX_DFS_RESPONSE) {
957 0 : DEBUG(10,("DFS: managed to reduce the size of referral initial "
958 : "number of referral %d, actual count: %d\n",
959 : nb_referrals, r->out.resp->nb_referrals));
960 0 : ok = true;
961 0 : break;
962 : }
963 : }
964 :
965 0 : if (!ok && r->out.resp->nb_referrals <= 2) {
966 0 : DEBUG(8, (__location__ "; Not able to fit the domain and realm in DFS a "
967 : " 56K buffer, something must be broken\n"));
968 0 : talloc_free(r);
969 0 : return NT_STATUS_INTERNAL_ERROR;
970 : }
971 : }
972 :
973 14 : TRANS2_CHECK(trans2_setup_reply(trans, 0, outblob.length, 0));
974 :
975 14 : trans->out.data = outblob;
976 14 : talloc_free(r);
977 14 : return NT_STATUS_OK;
978 : }
979 :
980 : /*
981 : trans2 findfirst implementation
982 : */
983 10205 : static NTSTATUS trans2_findfirst(struct smbsrv_request *req, struct trans_op *op)
984 : {
985 10205 : struct smb_trans2 *trans = op->trans;
986 0 : union smb_search_first *search;
987 0 : uint16_t level;
988 0 : struct find_state *state;
989 :
990 : /* make sure we got all the parameters */
991 10205 : if (trans->in.params.length < 14) {
992 0 : return NT_STATUS_FOOBAR;
993 : }
994 :
995 10205 : search = talloc(op, union smb_search_first);
996 10205 : NT_STATUS_HAVE_NO_MEMORY(search);
997 :
998 10205 : search->t2ffirst.in.search_attrib = SVAL(trans->in.params.data, 0);
999 10205 : search->t2ffirst.in.max_count = SVAL(trans->in.params.data, 2);
1000 10205 : search->t2ffirst.in.flags = SVAL(trans->in.params.data, 4);
1001 10205 : level = SVAL(trans->in.params.data, 6);
1002 10205 : search->t2ffirst.in.storage_type = IVAL(trans->in.params.data, 8);
1003 :
1004 10205 : smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 12, &search->t2ffirst.in.pattern, 0);
1005 10205 : if (search->t2ffirst.in.pattern == NULL) {
1006 0 : return NT_STATUS_FOOBAR;
1007 : }
1008 :
1009 10205 : search->t2ffirst.level = RAW_SEARCH_TRANS2;
1010 10205 : search->t2ffirst.data_level = (enum smb_search_data_level)level;
1011 10205 : if (search->t2ffirst.data_level >= RAW_SEARCH_DATA_GENERIC) {
1012 0 : return NT_STATUS_INVALID_LEVEL;
1013 : }
1014 :
1015 10205 : if (search->t2ffirst.data_level == RAW_SEARCH_DATA_EA_LIST) {
1016 3 : TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
1017 : &search->t2ffirst.in.num_names,
1018 : &search->t2ffirst.in.ea_names));
1019 : }
1020 :
1021 : /* setup the private state structure that the backend will
1022 : give us in the callback */
1023 10203 : state = talloc(op, struct find_state);
1024 10203 : NT_STATUS_HAVE_NO_MEMORY(state);
1025 10203 : state->op = op;
1026 10203 : state->search = search;
1027 10203 : state->data_level = search->t2ffirst.data_level;
1028 10203 : state->last_entry_offset= 0;
1029 10203 : state->flags = search->t2ffirst.in.flags;
1030 :
1031 : /* setup for just a header in the reply */
1032 10203 : TRANS2_CHECK(trans2_setup_reply(trans, 10, 0, 0));
1033 :
1034 10203 : op->op_info = state;
1035 10203 : op->send_fn = trans2_findfirst_send;
1036 :
1037 10203 : return ntvfs_search_first(req->ntvfs, search, state, find_callback);
1038 : }
1039 :
1040 :
1041 : /*
1042 : trans2 findnext send
1043 : */
1044 341 : static NTSTATUS trans2_findnext_send(struct trans_op *op)
1045 : {
1046 341 : struct smbsrv_request *req = op->req;
1047 341 : struct smb_trans2 *trans = op->trans;
1048 0 : union smb_search_next *search;
1049 0 : struct find_state *state;
1050 0 : uint8_t *param;
1051 :
1052 341 : TRANS2_CHECK_ASYNC_STATUS(state, struct find_state);
1053 341 : search = talloc_get_type(state->search, union smb_search_next);
1054 :
1055 : /* fill in the findfirst reply header */
1056 341 : param = trans->out.params.data;
1057 341 : SSVAL(param, VWV(0), search->t2fnext.out.count);
1058 341 : SSVAL(param, VWV(1), search->t2fnext.out.end_of_search);
1059 341 : SSVAL(param, VWV(2), 0);
1060 341 : SSVAL(param, VWV(3), state->last_entry_offset);
1061 :
1062 341 : return NT_STATUS_OK;
1063 : }
1064 :
1065 :
1066 : /*
1067 : trans2 findnext implementation
1068 : */
1069 341 : static NTSTATUS trans2_findnext(struct smbsrv_request *req, struct trans_op *op)
1070 : {
1071 341 : struct smb_trans2 *trans = op->trans;
1072 0 : union smb_search_next *search;
1073 0 : uint16_t level;
1074 0 : struct find_state *state;
1075 :
1076 : /* make sure we got all the parameters */
1077 341 : if (trans->in.params.length < 12) {
1078 0 : return NT_STATUS_FOOBAR;
1079 : }
1080 :
1081 341 : search = talloc(op, union smb_search_next);
1082 341 : NT_STATUS_HAVE_NO_MEMORY(search);
1083 :
1084 341 : search->t2fnext.in.handle = SVAL(trans->in.params.data, 0);
1085 341 : search->t2fnext.in.max_count = SVAL(trans->in.params.data, 2);
1086 341 : level = SVAL(trans->in.params.data, 4);
1087 341 : search->t2fnext.in.resume_key = IVAL(trans->in.params.data, 6);
1088 341 : search->t2fnext.in.flags = SVAL(trans->in.params.data, 10);
1089 :
1090 341 : smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 12, &search->t2fnext.in.last_name, 0);
1091 341 : if (search->t2fnext.in.last_name == NULL) {
1092 0 : return NT_STATUS_FOOBAR;
1093 : }
1094 :
1095 341 : search->t2fnext.level = RAW_SEARCH_TRANS2;
1096 341 : search->t2fnext.data_level = (enum smb_search_data_level)level;
1097 341 : if (search->t2fnext.data_level >= RAW_SEARCH_DATA_GENERIC) {
1098 0 : return NT_STATUS_INVALID_LEVEL;
1099 : }
1100 :
1101 341 : if (search->t2fnext.data_level == RAW_SEARCH_DATA_EA_LIST) {
1102 1 : TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
1103 : &search->t2fnext.in.num_names,
1104 : &search->t2fnext.in.ea_names));
1105 : }
1106 :
1107 : /* setup the private state structure that the backend will give us in the callback */
1108 341 : state = talloc(op, struct find_state);
1109 341 : NT_STATUS_HAVE_NO_MEMORY(state);
1110 341 : state->op = op;
1111 341 : state->search = search;
1112 341 : state->data_level = search->t2fnext.data_level;
1113 341 : state->last_entry_offset= 0;
1114 341 : state->flags = search->t2fnext.in.flags;
1115 :
1116 : /* setup for just a header in the reply */
1117 341 : TRANS2_CHECK(trans2_setup_reply(trans, 8, 0, 0));
1118 :
1119 341 : op->op_info = state;
1120 341 : op->send_fn = trans2_findnext_send;
1121 :
1122 341 : return ntvfs_search_next(req->ntvfs, search, state, find_callback);
1123 : }
1124 :
1125 :
1126 : /*
1127 : backend for trans2 requests
1128 : */
1129 36453 : static NTSTATUS trans2_backend(struct smbsrv_request *req, struct trans_op *op)
1130 : {
1131 36453 : struct smb_trans2 *trans = op->trans;
1132 0 : NTSTATUS status;
1133 :
1134 : /* direct trans2 pass thru */
1135 36453 : status = ntvfs_trans2(req->ntvfs, trans);
1136 36453 : if (!NT_STATUS_EQUAL(NT_STATUS_NOT_IMPLEMENTED, status)) {
1137 0 : return status;
1138 : }
1139 :
1140 : /* must have at least one setup word */
1141 36453 : if (trans->in.setup_count < 1) {
1142 0 : return NT_STATUS_FOOBAR;
1143 : }
1144 :
1145 : /* the trans2 command is in setup[0] */
1146 36453 : switch (trans->in.setup[0]) {
1147 17 : case TRANSACT2_GET_DFS_REFERRAL:
1148 17 : return trans2_getdfsreferral(req, op);
1149 10205 : case TRANSACT2_FINDFIRST:
1150 10205 : return trans2_findfirst(req, op);
1151 341 : case TRANSACT2_FINDNEXT:
1152 341 : return trans2_findnext(req, op);
1153 6833 : case TRANSACT2_QPATHINFO:
1154 6833 : return trans2_qpathinfo(req, op);
1155 7046 : case TRANSACT2_QFILEINFO:
1156 7046 : return trans2_qfileinfo(req, op);
1157 3656 : case TRANSACT2_SETFILEINFO:
1158 3656 : return trans2_setfileinfo(req, op);
1159 2272 : case TRANSACT2_SETPATHINFO:
1160 2272 : return trans2_setpathinfo(req, op);
1161 6063 : case TRANSACT2_QFSINFO:
1162 6063 : return trans2_qfsinfo(req, op);
1163 17 : case TRANSACT2_OPEN:
1164 17 : return trans2_open(req, op);
1165 3 : case TRANSACT2_MKDIR:
1166 3 : return trans2_mkdir(req, op);
1167 : }
1168 :
1169 : /* an unknown trans2 command */
1170 0 : return NT_STATUS_FOOBAR;
1171 : }
1172 :
1173 0 : int smbsrv_trans_partial_destructor(struct smbsrv_trans_partial *tp)
1174 : {
1175 0 : DLIST_REMOVE(tp->req->smb_conn->trans_partial, tp);
1176 0 : return 0;
1177 : }
1178 :
1179 :
1180 : /*
1181 : send a continue request
1182 : */
1183 0 : static void reply_trans_continue(struct smbsrv_request *req, uint8_t command,
1184 : struct smb_trans2 *trans)
1185 : {
1186 0 : struct smbsrv_request *req2;
1187 0 : struct smbsrv_trans_partial *tp;
1188 0 : int count;
1189 :
1190 : /* make sure they don't flood us */
1191 0 : for (count=0,tp=req->smb_conn->trans_partial;tp;tp=tp->next) count++;
1192 0 : if (count > 100) {
1193 0 : smbsrv_send_error(req, NT_STATUS_INSUFFICIENT_RESOURCES);
1194 0 : return;
1195 : }
1196 :
1197 0 : tp = talloc(req, struct smbsrv_trans_partial);
1198 :
1199 0 : tp->req = req;
1200 0 : tp->u.trans = trans;
1201 0 : tp->command = command;
1202 :
1203 0 : DLIST_ADD(req->smb_conn->trans_partial, tp);
1204 0 : talloc_set_destructor(tp, smbsrv_trans_partial_destructor);
1205 :
1206 0 : req2 = smbsrv_setup_secondary_request(req);
1207 :
1208 : /* send a 'please continue' reply */
1209 0 : smbsrv_setup_reply(req2, 0, 0);
1210 0 : smbsrv_send_reply(req2);
1211 : }
1212 :
1213 :
1214 : /*
1215 : answer a reconstructed trans request
1216 : */
1217 36497 : static void reply_trans_send(struct ntvfs_request *ntvfs)
1218 : {
1219 0 : struct smbsrv_request *req;
1220 0 : struct trans_op *op;
1221 0 : struct smb_trans2 *trans;
1222 0 : uint16_t params_left, data_left;
1223 0 : uint8_t *params, *data;
1224 0 : int i;
1225 :
1226 36497 : SMBSRV_CHECK_ASYNC_STATUS_ERR(op, struct trans_op);
1227 7400 : trans = op->trans;
1228 :
1229 : /* if this function needs work to form the nttrans reply buffer, then
1230 : call that now */
1231 7400 : if (op->send_fn != NULL) {
1232 0 : NTSTATUS status;
1233 7353 : status = op->send_fn(op);
1234 7353 : if (!NT_STATUS_IS_OK(status)) {
1235 0 : smbsrv_send_error(req, status);
1236 0 : return;
1237 : }
1238 : }
1239 :
1240 7400 : params_left = trans->out.params.length;
1241 7400 : data_left = trans->out.data.length;
1242 7400 : params = trans->out.params.data;
1243 7400 : data = trans->out.data.data;
1244 :
1245 7400 : smbsrv_setup_reply(req, 10 + trans->out.setup_count, 0);
1246 :
1247 7400 : if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) {
1248 0 : smbsrv_setup_error(req, req->ntvfs->async_states->status);
1249 : }
1250 :
1251 : /* we need to divide up the reply into chunks that fit into
1252 : the negotiated buffer size */
1253 0 : do {
1254 0 : uint16_t this_data, this_param, max_bytes;
1255 7414 : unsigned int align1 = 1, align2 = (params_left ? 2 : 0);
1256 0 : struct smbsrv_request *this_req;
1257 :
1258 7414 : max_bytes = req_max_data(req) - (align1 + align2);
1259 :
1260 7414 : this_param = params_left;
1261 7414 : if (this_param > max_bytes) {
1262 0 : this_param = max_bytes;
1263 : }
1264 7414 : max_bytes -= this_param;
1265 :
1266 7414 : this_data = data_left;
1267 7414 : if (this_data > max_bytes) {
1268 14 : this_data = max_bytes;
1269 : }
1270 :
1271 : /* don't destroy unless this is the last chunk */
1272 7414 : if (params_left - this_param != 0 ||
1273 0 : data_left - this_data != 0) {
1274 14 : this_req = smbsrv_setup_secondary_request(req);
1275 : } else {
1276 7400 : this_req = req;
1277 : }
1278 :
1279 7414 : req_grow_data(this_req, this_param + this_data + (align1 + align2));
1280 :
1281 7414 : SSVAL(this_req->out.vwv, VWV(0), trans->out.params.length);
1282 7414 : SSVAL(this_req->out.vwv, VWV(1), trans->out.data.length);
1283 7414 : SSVAL(this_req->out.vwv, VWV(2), 0);
1284 :
1285 7414 : SSVAL(this_req->out.vwv, VWV(3), this_param);
1286 7414 : SSVAL(this_req->out.vwv, VWV(4), align1 + PTR_DIFF(this_req->out.data, this_req->out.hdr));
1287 7414 : SSVAL(this_req->out.vwv, VWV(5), PTR_DIFF(params, trans->out.params.data));
1288 :
1289 7414 : SSVAL(this_req->out.vwv, VWV(6), this_data);
1290 7414 : SSVAL(this_req->out.vwv, VWV(7), align1 + align2 +
1291 : PTR_DIFF(this_req->out.data + this_param, this_req->out.hdr));
1292 7414 : SSVAL(this_req->out.vwv, VWV(8), PTR_DIFF(data, trans->out.data.data));
1293 :
1294 7414 : SCVAL(this_req->out.vwv, VWV(9), trans->out.setup_count);
1295 7414 : SCVAL(this_req->out.vwv, VWV(9)+1, 0); /* reserved */
1296 7414 : for (i=0;i<trans->out.setup_count;i++) {
1297 0 : SSVAL(this_req->out.vwv, VWV(10+i), trans->out.setup[i]);
1298 : }
1299 :
1300 7414 : memset(this_req->out.data, 0, align1);
1301 7414 : if (this_param != 0) {
1302 7249 : memcpy(this_req->out.data + align1, params, this_param);
1303 : }
1304 7414 : memset(this_req->out.data+this_param+align1, 0, align2);
1305 7414 : if (this_data != 0) {
1306 6144 : memcpy(this_req->out.data+this_param+align1+align2, data, this_data);
1307 : }
1308 :
1309 7414 : params_left -= this_param;
1310 7414 : data_left -= this_data;
1311 7414 : params += this_param;
1312 7414 : data += this_data;
1313 :
1314 7414 : smbsrv_send_reply(this_req);
1315 7414 : } while (params_left != 0 || data_left != 0);
1316 : }
1317 :
1318 :
1319 : /*
1320 : answer a reconstructed trans request
1321 : */
1322 36497 : static void reply_trans_complete(struct smbsrv_request *req, uint8_t command,
1323 : struct smb_trans2 *trans)
1324 : {
1325 0 : struct trans_op *op;
1326 :
1327 36497 : SMBSRV_TALLOC_IO_PTR(op, struct trans_op);
1328 36497 : SMBSRV_SETUP_NTVFS_REQUEST(reply_trans_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1329 :
1330 36497 : op->req = req;
1331 36497 : op->trans = trans;
1332 36497 : op->command = command;
1333 36497 : op->op_info = NULL;
1334 36497 : op->send_fn = NULL;
1335 :
1336 : /* its a full request, give it to the backend */
1337 36497 : if (command == SMBtrans) {
1338 44 : SMBSRV_CALL_NTVFS_BACKEND(ntvfs_trans(req->ntvfs, trans));
1339 44 : return;
1340 : } else {
1341 36453 : SMBSRV_CALL_NTVFS_BACKEND(trans2_backend(req, op));
1342 36453 : return;
1343 : }
1344 : }
1345 :
1346 : /*
1347 : Reply to an SMBtrans or SMBtrans2 request
1348 : */
1349 36497 : static void reply_trans_generic(struct smbsrv_request *req, uint8_t command)
1350 : {
1351 0 : struct smb_trans2 *trans;
1352 0 : int i;
1353 0 : uint16_t param_ofs, data_ofs;
1354 0 : uint16_t param_count, data_count;
1355 0 : uint16_t param_total, data_total;
1356 :
1357 : /* parse request */
1358 36497 : if (req->in.wct < 14) {
1359 0 : smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1360 0 : return;
1361 : }
1362 :
1363 36497 : trans = talloc(req, struct smb_trans2);
1364 36497 : if (trans == NULL) {
1365 0 : smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
1366 0 : return;
1367 : }
1368 :
1369 36497 : param_total = SVAL(req->in.vwv, VWV(0));
1370 36497 : data_total = SVAL(req->in.vwv, VWV(1));
1371 36497 : trans->in.max_param = SVAL(req->in.vwv, VWV(2));
1372 36497 : trans->in.max_data = SVAL(req->in.vwv, VWV(3));
1373 36497 : trans->in.max_setup = CVAL(req->in.vwv, VWV(4));
1374 36497 : trans->in.flags = SVAL(req->in.vwv, VWV(5));
1375 36497 : trans->in.timeout = IVAL(req->in.vwv, VWV(6));
1376 36497 : param_count = SVAL(req->in.vwv, VWV(9));
1377 36497 : param_ofs = SVAL(req->in.vwv, VWV(10));
1378 36497 : data_count = SVAL(req->in.vwv, VWV(11));
1379 36497 : data_ofs = SVAL(req->in.vwv, VWV(12));
1380 36497 : trans->in.setup_count = CVAL(req->in.vwv, VWV(13));
1381 :
1382 36497 : if (req->in.wct != 14 + trans->in.setup_count) {
1383 0 : smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
1384 0 : return;
1385 : }
1386 :
1387 : /* parse out the setup words */
1388 36497 : trans->in.setup = talloc_array(trans, uint16_t, trans->in.setup_count);
1389 36497 : if (trans->in.setup_count && !trans->in.setup) {
1390 0 : smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
1391 0 : return;
1392 : }
1393 73034 : for (i=0;i<trans->in.setup_count;i++) {
1394 36537 : trans->in.setup[i] = SVAL(req->in.vwv, VWV(14+i));
1395 : }
1396 :
1397 36497 : if (command == SMBtrans) {
1398 44 : req_pull_string(&req->in.bufinfo, &trans->in.trans_name, req->in.data, -1, STR_TERMINATE);
1399 : }
1400 :
1401 36497 : if (!req_pull_blob(&req->in.bufinfo, req->in.hdr + param_ofs, param_count, &trans->in.params) ||
1402 36497 : !req_pull_blob(&req->in.bufinfo, req->in.hdr + data_ofs, data_count, &trans->in.data)) {
1403 0 : smbsrv_send_error(req, NT_STATUS_FOOBAR);
1404 0 : return;
1405 : }
1406 :
1407 : /* is it a partial request? if so, then send a 'send more' message */
1408 36497 : if (param_total > param_count || data_total > data_count) {
1409 0 : reply_trans_continue(req, command, trans);
1410 0 : return;
1411 : }
1412 :
1413 36497 : reply_trans_complete(req, command, trans);
1414 : }
1415 :
1416 :
1417 : /*
1418 : Reply to an SMBtranss2 request
1419 : */
1420 0 : static void reply_transs_generic(struct smbsrv_request *req, uint8_t command)
1421 : {
1422 0 : struct smbsrv_trans_partial *tp;
1423 0 : struct smb_trans2 *trans = NULL;
1424 0 : uint16_t param_ofs, data_ofs;
1425 0 : uint16_t param_count, data_count;
1426 0 : uint16_t param_disp, data_disp;
1427 0 : uint16_t param_total, data_total;
1428 0 : DATA_BLOB params, data;
1429 0 : uint8_t wct;
1430 :
1431 0 : if (command == SMBtrans2) {
1432 0 : wct = 9;
1433 : } else {
1434 0 : wct = 8;
1435 : }
1436 :
1437 : /* parse request */
1438 0 : if (req->in.wct != wct) {
1439 : /*
1440 : * TODO: add some error code tests
1441 : * w2k3 returns NT_STATUS_DOS(ERRSRV, ERRerror) here
1442 : */
1443 0 : smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1444 0 : return;
1445 : }
1446 :
1447 0 : for (tp=req->smb_conn->trans_partial;tp;tp=tp->next) {
1448 0 : if (tp->command == command &&
1449 0 : SVAL(tp->req->in.hdr, HDR_MID) == SVAL(req->in.hdr, HDR_MID)) {
1450 : /* TODO: check the VUID, PID and TID too? */
1451 0 : break;
1452 : }
1453 : }
1454 :
1455 0 : if (tp == NULL) {
1456 0 : smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1457 0 : return;
1458 : }
1459 :
1460 0 : trans = tp->u.trans;
1461 :
1462 0 : param_total = SVAL(req->in.vwv, VWV(0));
1463 0 : data_total = SVAL(req->in.vwv, VWV(1));
1464 0 : param_count = SVAL(req->in.vwv, VWV(2));
1465 0 : param_ofs = SVAL(req->in.vwv, VWV(3));
1466 0 : param_disp = SVAL(req->in.vwv, VWV(4));
1467 0 : data_count = SVAL(req->in.vwv, VWV(5));
1468 0 : data_ofs = SVAL(req->in.vwv, VWV(6));
1469 0 : data_disp = SVAL(req->in.vwv, VWV(7));
1470 :
1471 0 : if (!req_pull_blob(&req->in.bufinfo, req->in.hdr + param_ofs, param_count, ¶ms) ||
1472 0 : !req_pull_blob(&req->in.bufinfo, req->in.hdr + data_ofs, data_count, &data)) {
1473 0 : smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1474 0 : return;
1475 : }
1476 :
1477 : /* only allow contiguous requests */
1478 0 : if ((param_count != 0 &&
1479 0 : param_disp != trans->in.params.length) ||
1480 0 : (data_count != 0 &&
1481 0 : data_disp != trans->in.data.length)) {
1482 0 : smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1483 0 : return;
1484 : }
1485 :
1486 : /* add to the existing request */
1487 0 : if (param_count != 0) {
1488 0 : trans->in.params.data = talloc_realloc(trans,
1489 : trans->in.params.data,
1490 : uint8_t,
1491 : param_disp + param_count);
1492 0 : if (trans->in.params.data == NULL) {
1493 0 : smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
1494 0 : return;
1495 : }
1496 0 : trans->in.params.length = param_disp + param_count;
1497 : }
1498 :
1499 0 : if (data_count != 0) {
1500 0 : trans->in.data.data = talloc_realloc(trans,
1501 : trans->in.data.data,
1502 : uint8_t,
1503 : data_disp + data_count);
1504 0 : if (trans->in.data.data == NULL) {
1505 0 : smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
1506 0 : return;
1507 : }
1508 0 : trans->in.data.length = data_disp + data_count;
1509 : }
1510 :
1511 0 : memcpy(trans->in.params.data + param_disp, params.data, params.length);
1512 0 : memcpy(trans->in.data.data + data_disp, data.data, data.length);
1513 :
1514 : /* the sequence number of the reply is taken from the last secondary
1515 : response */
1516 0 : tp->req->seq_num = req->seq_num;
1517 :
1518 : /* we don't reply to Transs2 requests */
1519 0 : talloc_free(req);
1520 :
1521 0 : if (trans->in.params.length == param_total &&
1522 0 : trans->in.data.length == data_total) {
1523 : /* its now complete */
1524 0 : req = tp->req;
1525 0 : talloc_free(tp);
1526 0 : reply_trans_complete(req, command, trans);
1527 : }
1528 0 : return;
1529 : }
1530 :
1531 :
1532 : /*
1533 : Reply to an SMBtrans2
1534 : */
1535 36453 : void smbsrv_reply_trans2(struct smbsrv_request *req)
1536 : {
1537 36453 : reply_trans_generic(req, SMBtrans2);
1538 36453 : }
1539 :
1540 : /*
1541 : Reply to an SMBtrans
1542 : */
1543 44 : void smbsrv_reply_trans(struct smbsrv_request *req)
1544 : {
1545 44 : reply_trans_generic(req, SMBtrans);
1546 44 : }
1547 :
1548 : /*
1549 : Reply to an SMBtranss request
1550 : */
1551 0 : void smbsrv_reply_transs(struct smbsrv_request *req)
1552 : {
1553 0 : reply_transs_generic(req, SMBtrans);
1554 0 : }
1555 :
1556 : /*
1557 : Reply to an SMBtranss2 request
1558 : */
1559 0 : void smbsrv_reply_transs2(struct smbsrv_request *req)
1560 : {
1561 0 : reply_transs_generic(req, SMBtrans2);
1562 0 : }
|