2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 2003
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 2 of the License, or
9 (at your option) any later version.
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.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 This file handles the parsing of transact2 requests
25 #include "dlinklist.h"
26 #include "smb_server/smb_server.h"
27 #include "librpc/gen_ndr/ndr_misc.h"
28 #include "ntvfs/ntvfs.h"
29 #include "libcli/raw/libcliraw.h"
31 #define TRANS2_CHECK_ASYNC_STATUS_SIMPLE do { \
32 if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) { \
33 trans2_setup_reply(trans, 0, 0, 0);\
34 return req->ntvfs->async_states->status; \
37 #define TRANS2_CHECK_ASYNC_STATUS(ptr, type) do { \
38 TRANS2_CHECK_ASYNC_STATUS_SIMPLE; \
39 ptr = talloc_get_type(op->op_info, type); \
41 #define TRANS2_CHECK(cmd) do { \
44 NT_STATUS_NOT_OK_RETURN(_status); \
48 hold the state of a nttrans op while in progress. Needed to allow for async backend
52 struct smbsrv_request *req;
53 struct smb_trans2 *trans;
55 NTSTATUS (*send_fn)(struct trans_op *);
59 #define CHECK_MIN_BLOB_SIZE(blob, size) do { \
60 if ((blob)->length < (size)) { \
61 return NT_STATUS_INFO_LENGTH_MISMATCH; \
64 /* grow the data size of a trans2 reply */
65 static NTSTATUS trans2_grow_data(TALLOC_CTX *mem_ctx,
69 if (new_size > blob->length) {
70 blob->data = talloc_realloc(mem_ctx, blob->data, uint8_t, new_size);
71 NT_STATUS_HAVE_NO_MEMORY(blob->data);
73 blob->length = new_size;
77 /* grow the data, zero filling any new bytes */
78 static NTSTATUS trans2_grow_data_fill(TALLOC_CTX *mem_ctx,
82 uint32_t old_size = blob->length;
83 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, new_size));
84 if (new_size > old_size) {
85 memset(blob->data + old_size, 0, new_size - old_size);
91 /* setup a trans2 reply, given the data and params sizes */
92 static NTSTATUS trans2_setup_reply(struct smb_trans2 *trans,
93 uint16_t param_size, uint16_t data_size,
96 trans->out.setup_count = setup_count;
97 if (setup_count > 0) {
98 trans->out.setup = talloc_zero_array(trans, uint16_t, setup_count);
99 NT_STATUS_HAVE_NO_MEMORY(trans->out.setup);
101 trans->out.params = data_blob_talloc(trans, NULL, param_size);
102 if (param_size > 0) NT_STATUS_HAVE_NO_MEMORY(trans->out.params.data);
104 trans->out.data = data_blob_talloc(trans, NULL, data_size);
105 if (data_size > 0) NT_STATUS_HAVE_NO_MEMORY(trans->out.data.data);
112 pull a string from a blob in a trans2 request
114 static size_t trans2_pull_blob_string(struct smbsrv_request *req,
115 const DATA_BLOB *blob,
120 /* we use STR_NO_RANGE_CHECK because the params are allocated
121 separately in a DATA_BLOB, so we need to do our own range
123 if (offset >= blob->length) {
128 return req_pull_string(req, str,
130 blob->length - offset,
131 STR_NO_RANGE_CHECK | flags);
135 push a string into the data section of a trans2 request
136 return the number of bytes consumed in the output
138 static size_t trans2_push_data_string(struct smbsrv_request *req,
143 const struct smb_wire_string *str,
147 int alignment = 0, ret = 0, pkt_len;
149 /* we use STR_NO_RANGE_CHECK because the params are allocated
150 separately in a DATA_BLOB, so we need to do our own range
152 if (!str->s || offset >= blob->length) {
153 if (flags & STR_LEN8BIT) {
154 SCVAL(blob->data, len_offset, 0);
156 SIVAL(blob->data, len_offset, 0);
161 flags |= STR_NO_RANGE_CHECK;
163 if (dest_len == -1 || (dest_len > blob->length - offset)) {
164 dest_len = blob->length - offset;
167 if (!(flags & (STR_ASCII|STR_UNICODE))) {
168 flags |= (req->flags2 & FLAGS2_UNICODE_STRINGS) ? STR_UNICODE : STR_ASCII;
171 if ((offset&1) && (flags & STR_UNICODE) && !(flags & STR_NOALIGN)) {
174 SCVAL(blob->data + offset, 0, 0);
175 ret = push_string(blob->data + offset + 1, str->s, dest_len-1, flags);
178 ret = push_string(blob->data + offset, str->s, dest_len, flags);
181 /* sometimes the string needs to be terminated, but the length
182 on the wire must not include the termination! */
185 if ((flags & STR_LEN_NOTERM) && (flags & STR_TERMINATE)) {
186 if ((flags & STR_UNICODE) && ret >= 2) {
189 if ((flags & STR_ASCII) && ret >= 1) {
194 if (flags & STR_LEN8BIT) {
195 SCVAL(blob->data, len_offset, pkt_len);
197 SIVAL(blob->data, len_offset, pkt_len);
200 return ret + alignment;
204 append a string to the data section of a trans2 reply
205 len_offset points to the place in the packet where the length field
208 static NTSTATUS trans2_append_data_string(struct smbsrv_request *req,
211 const struct smb_wire_string *str,
217 const int max_bytes_per_char = 3;
219 offset = blob->length;
220 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, offset + (2+strlen_m(str->s))*max_bytes_per_char));
221 ret = trans2_push_data_string(req, mem_ctx, blob, len_offset, offset, str, -1, flags);
223 return NT_STATUS_FOOBAR;
225 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, offset + ret));
230 align the end of the data section of a trans reply on an even boundary
232 static NTSTATUS trans2_align_data(struct smb_trans2 *trans)
234 if (trans->out.data.length & 1) {
235 TRANS2_CHECK(trans2_grow_data_fill(trans, &trans->out.data, trans->out.data.length+1));
240 static NTSTATUS trans2_push_fsinfo(struct smbsrv_request *req,
241 union smb_fsinfo *fsinfo,
248 switch (fsinfo->generic.level) {
249 case SMB_QFS_ALLOCATION:
250 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 18));
252 SIVAL(blob->data, 0, fsinfo->allocation.out.fs_id);
253 SIVAL(blob->data, 4, fsinfo->allocation.out.sectors_per_unit);
254 SIVAL(blob->data, 8, fsinfo->allocation.out.total_alloc_units);
255 SIVAL(blob->data, 12, fsinfo->allocation.out.avail_alloc_units);
256 SSVAL(blob->data, 16, fsinfo->allocation.out.bytes_per_sector);
261 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 5));
263 SIVAL(blob->data, 0, fsinfo->volume.out.serial_number);
264 /* w2k3 implements this incorrectly for unicode - it
265 * leaves the last byte off the string */
266 TRANS2_CHECK(trans2_append_data_string(req, mem_ctx, blob,
267 &fsinfo->volume.out.volume_name,
268 4, STR_LEN8BIT|STR_NOALIGN));
272 case SMB_QFS_VOLUME_INFO:
273 case SMB_QFS_VOLUME_INFORMATION:
274 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 18));
276 push_nttime(blob->data, 0, fsinfo->volume_info.out.create_time);
277 SIVAL(blob->data, 8, fsinfo->volume_info.out.serial_number);
278 SSVAL(blob->data, 16, 0); /* padding */
279 TRANS2_CHECK(trans2_append_data_string(req, mem_ctx, blob,
280 &fsinfo->volume_info.out.volume_name,
285 case SMB_QFS_SIZE_INFO:
286 case SMB_QFS_SIZE_INFORMATION:
287 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 24));
289 SBVAL(blob->data, 0, fsinfo->size_info.out.total_alloc_units);
290 SBVAL(blob->data, 8, fsinfo->size_info.out.avail_alloc_units);
291 SIVAL(blob->data, 16, fsinfo->size_info.out.sectors_per_unit);
292 SIVAL(blob->data, 20, fsinfo->size_info.out.bytes_per_sector);
296 case SMB_QFS_DEVICE_INFO:
297 case SMB_QFS_DEVICE_INFORMATION:
298 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 8));
300 SIVAL(blob->data, 0, fsinfo->device_info.out.device_type);
301 SIVAL(blob->data, 4, fsinfo->device_info.out.characteristics);
305 case SMB_QFS_ATTRIBUTE_INFO:
306 case SMB_QFS_ATTRIBUTE_INFORMATION:
307 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 12));
309 SIVAL(blob->data, 0, fsinfo->attribute_info.out.fs_attr);
310 SIVAL(blob->data, 4, fsinfo->attribute_info.out.max_file_component_length);
311 /* this must not be null terminated or win98 gets
312 confused! also note that w2k3 returns this as
313 unicode even when ascii is negotiated */
314 TRANS2_CHECK(trans2_append_data_string(req, mem_ctx, blob,
315 &fsinfo->attribute_info.out.fs_type,
320 case SMB_QFS_QUOTA_INFORMATION:
321 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 48));
323 SBVAL(blob->data, 0, fsinfo->quota_information.out.unknown[0]);
324 SBVAL(blob->data, 8, fsinfo->quota_information.out.unknown[1]);
325 SBVAL(blob->data, 16, fsinfo->quota_information.out.unknown[2]);
326 SBVAL(blob->data, 24, fsinfo->quota_information.out.quota_soft);
327 SBVAL(blob->data, 32, fsinfo->quota_information.out.quota_hard);
328 SBVAL(blob->data, 40, fsinfo->quota_information.out.quota_flags);
333 case SMB_QFS_FULL_SIZE_INFORMATION:
334 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 32));
336 SBVAL(blob->data, 0, fsinfo->full_size_information.out.total_alloc_units);
337 SBVAL(blob->data, 8, fsinfo->full_size_information.out.call_avail_alloc_units);
338 SBVAL(blob->data, 16, fsinfo->full_size_information.out.actual_avail_alloc_units);
339 SIVAL(blob->data, 24, fsinfo->full_size_information.out.sectors_per_unit);
340 SIVAL(blob->data, 28, fsinfo->full_size_information.out.bytes_per_sector);
344 case SMB_QFS_OBJECTID_INFORMATION:
345 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 64));
347 TRANS2_CHECK(ndr_push_struct_blob(&guid_blob, mem_ctx,
348 &fsinfo->objectid_information.out.guid,
349 (ndr_push_flags_fn_t)ndr_push_GUID));
350 memcpy(blob->data, guid_blob.data, guid_blob.length);
353 SBVAL(blob->data, 16 + 8*i, fsinfo->objectid_information.out.unknown[i]);
359 return NT_STATUS_INVALID_LEVEL;
363 trans2 qfsinfo implementation send
365 static NTSTATUS trans2_qfsinfo_send(struct trans_op *op)
367 struct smbsrv_request *req = op->req;
368 struct smb_trans2 *trans = op->trans;
369 union smb_fsinfo *fsinfo;
371 TRANS2_CHECK_ASYNC_STATUS(fsinfo, union smb_fsinfo);
373 TRANS2_CHECK(trans2_setup_reply(trans, 0, 0, 0));
375 TRANS2_CHECK(trans2_push_fsinfo(req, fsinfo, trans, &trans->out.data));
381 trans2 qfsinfo implementation
383 static NTSTATUS trans2_qfsinfo(struct smbsrv_request *req, struct trans_op *op)
385 struct smb_trans2 *trans = op->trans;
386 union smb_fsinfo *fsinfo;
389 /* make sure we got enough parameters */
390 if (trans->in.params.length != 2) {
391 return NT_STATUS_FOOBAR;
394 fsinfo = talloc(op, union smb_fsinfo);
395 NT_STATUS_HAVE_NO_MEMORY(fsinfo);
397 op->op_info = fsinfo;
398 op->send_fn = trans2_qfsinfo_send;
400 level = SVAL(trans->in.params.data, 0);
403 case SMB_QFS_ALLOCATION:
404 fsinfo->allocation.level = RAW_QFS_ALLOCATION;
405 return ntvfs_fsinfo(req->ntvfs, fsinfo);
408 fsinfo->volume.level = RAW_QFS_VOLUME;
409 return ntvfs_fsinfo(req->ntvfs, fsinfo);
411 case SMB_QFS_VOLUME_INFO:
412 case SMB_QFS_VOLUME_INFORMATION:
413 fsinfo->volume_info.level = RAW_QFS_VOLUME_INFO;
414 return ntvfs_fsinfo(req->ntvfs, fsinfo);
416 case SMB_QFS_SIZE_INFO:
417 case SMB_QFS_SIZE_INFORMATION:
418 fsinfo->size_info.level = RAW_QFS_SIZE_INFO;
419 return ntvfs_fsinfo(req->ntvfs, fsinfo);
421 case SMB_QFS_DEVICE_INFO:
422 case SMB_QFS_DEVICE_INFORMATION:
423 fsinfo->device_info.level = RAW_QFS_DEVICE_INFO;
424 return ntvfs_fsinfo(req->ntvfs, fsinfo);
426 case SMB_QFS_ATTRIBUTE_INFO:
427 case SMB_QFS_ATTRIBUTE_INFORMATION:
428 fsinfo->attribute_info.level = RAW_QFS_ATTRIBUTE_INFO;
429 return ntvfs_fsinfo(req->ntvfs, fsinfo);
431 case SMB_QFS_QUOTA_INFORMATION:
432 fsinfo->quota_information.level = RAW_QFS_QUOTA_INFORMATION;
433 return ntvfs_fsinfo(req->ntvfs, fsinfo);
435 case SMB_QFS_FULL_SIZE_INFORMATION:
436 fsinfo->full_size_information.level = RAW_QFS_FULL_SIZE_INFORMATION;
437 return ntvfs_fsinfo(req->ntvfs, fsinfo);
439 case SMB_QFS_OBJECTID_INFORMATION:
440 fsinfo->objectid_information.level = RAW_QFS_OBJECTID_INFORMATION;
441 return ntvfs_fsinfo(req->ntvfs, fsinfo);
444 return NT_STATUS_INVALID_LEVEL;
449 trans2 open implementation send
451 static NTSTATUS trans2_open_send(struct trans_op *op)
453 struct smbsrv_request *req = op->req;
454 struct smb_trans2 *trans = op->trans;
457 TRANS2_CHECK_ASYNC_STATUS(io, union smb_open);
459 trans2_setup_reply(trans, 30, 0, 0);
461 smbsrv_push_fnum(trans->out.params.data, VWV(0), io->t2open.out.file.ntvfs);
462 SSVAL(trans->out.params.data, VWV(1), io->t2open.out.attrib);
463 srv_push_dos_date3(req->smb_conn, trans->out.params.data,
464 VWV(2), io->t2open.out.write_time);
465 SIVAL(trans->out.params.data, VWV(4), io->t2open.out.size);
466 SSVAL(trans->out.params.data, VWV(6), io->t2open.out.access);
467 SSVAL(trans->out.params.data, VWV(7), io->t2open.out.ftype);
468 SSVAL(trans->out.params.data, VWV(8), io->t2open.out.devstate);
469 SSVAL(trans->out.params.data, VWV(9), io->t2open.out.action);
470 SIVAL(trans->out.params.data, VWV(10), 0); /* reserved */
471 SSVAL(trans->out.params.data, VWV(12), 0); /* EaErrorOffset */
472 SIVAL(trans->out.params.data, VWV(13), 0); /* EaLength */
478 trans2 open implementation
480 static NTSTATUS trans2_open(struct smbsrv_request *req, struct trans_op *op)
482 struct smb_trans2 *trans = op->trans;
486 /* make sure we got enough parameters */
487 if (trans->in.params.length < 29) {
488 return NT_STATUS_FOOBAR;
491 io = talloc(op, union smb_open);
492 NT_STATUS_HAVE_NO_MEMORY(io);
494 io->t2open.level = RAW_OPEN_T2OPEN;
495 io->t2open.in.flags = SVAL(trans->in.params.data, VWV(0));
496 io->t2open.in.open_mode = SVAL(trans->in.params.data, VWV(1));
497 io->t2open.in.search_attrs = SVAL(trans->in.params.data, VWV(2));
498 io->t2open.in.file_attrs = SVAL(trans->in.params.data, VWV(3));
499 io->t2open.in.write_time = srv_pull_dos_date(req->smb_conn,
500 trans->in.params.data + VWV(4));;
501 io->t2open.in.open_func = SVAL(trans->in.params.data, VWV(6));
502 io->t2open.in.size = IVAL(trans->in.params.data, VWV(7));
503 io->t2open.in.timeout = IVAL(trans->in.params.data, VWV(9));
504 io->t2open.in.num_eas = 0;
505 io->t2open.in.eas = NULL;
507 trans2_pull_blob_string(req, &trans->in.params, 28, &io->t2open.in.fname, 0);
509 status = ea_pull_list(&trans->in.data, io, &io->t2open.in.num_eas, &io->t2open.in.eas);
510 NT_STATUS_NOT_OK_RETURN(status);
513 op->send_fn = trans2_open_send;
515 return ntvfs_open(req->ntvfs, io);
522 static NTSTATUS trans2_simple_send(struct trans_op *op)
524 struct smbsrv_request *req = op->req;
525 struct smb_trans2 *trans = op->trans;
527 TRANS2_CHECK_ASYNC_STATUS_SIMPLE;
529 trans2_setup_reply(trans, 2, 0, 0);
531 SSVAL(trans->out.params.data, VWV(0), 0);
537 trans2 mkdir implementation
539 static NTSTATUS trans2_mkdir(struct smbsrv_request *req, struct trans_op *op)
541 struct smb_trans2 *trans = op->trans;
545 /* make sure we got enough parameters */
546 if (trans->in.params.length < 5) {
547 return NT_STATUS_FOOBAR;
550 io = talloc(op, union smb_mkdir);
551 NT_STATUS_HAVE_NO_MEMORY(io);
553 io->t2mkdir.level = RAW_MKDIR_T2MKDIR;
554 trans2_pull_blob_string(req, &trans->in.params, 4, &io->t2mkdir.in.path, 0);
556 status = ea_pull_list(&trans->in.data, io,
557 &io->t2mkdir.in.num_eas,
558 &io->t2mkdir.in.eas);
559 NT_STATUS_NOT_OK_RETURN(status);
562 op->send_fn = trans2_simple_send;
564 return ntvfs_mkdir(req->ntvfs, io);
567 static NTSTATUS trans2_push_fileinfo(struct smbsrv_request *req,
568 union smb_fileinfo *st,
575 switch (st->generic.level) {
576 case RAW_FILEINFO_GENERIC:
577 case RAW_FILEINFO_GETATTR:
578 case RAW_FILEINFO_GETATTRE:
579 case RAW_FILEINFO_SEC_DESC:
580 /* handled elsewhere */
581 return NT_STATUS_INVALID_LEVEL;
583 case RAW_FILEINFO_BASIC_INFO:
584 case RAW_FILEINFO_BASIC_INFORMATION:
585 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 40));
587 push_nttime(blob->data, 0, st->basic_info.out.create_time);
588 push_nttime(blob->data, 8, st->basic_info.out.access_time);
589 push_nttime(blob->data, 16, st->basic_info.out.write_time);
590 push_nttime(blob->data, 24, st->basic_info.out.change_time);
591 SIVAL(blob->data, 32, st->basic_info.out.attrib);
592 SIVAL(blob->data, 36, 0); /* padding */
595 case RAW_FILEINFO_STANDARD:
596 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 22));
598 srv_push_dos_date2(req->smb_conn, blob->data, 0, st->standard.out.create_time);
599 srv_push_dos_date2(req->smb_conn, blob->data, 4, st->standard.out.access_time);
600 srv_push_dos_date2(req->smb_conn, blob->data, 8, st->standard.out.write_time);
601 SIVAL(blob->data, 12, st->standard.out.size);
602 SIVAL(blob->data, 16, st->standard.out.alloc_size);
603 SSVAL(blob->data, 20, st->standard.out.attrib);
606 case RAW_FILEINFO_EA_SIZE:
607 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 26));
609 srv_push_dos_date2(req->smb_conn, blob->data, 0, st->ea_size.out.create_time);
610 srv_push_dos_date2(req->smb_conn, blob->data, 4, st->ea_size.out.access_time);
611 srv_push_dos_date2(req->smb_conn, blob->data, 8, st->ea_size.out.write_time);
612 SIVAL(blob->data, 12, st->ea_size.out.size);
613 SIVAL(blob->data, 16, st->ea_size.out.alloc_size);
614 SSVAL(blob->data, 20, st->ea_size.out.attrib);
615 SIVAL(blob->data, 22, st->ea_size.out.ea_size);
618 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
619 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 56));
621 push_nttime(blob->data, 0, st->network_open_information.out.create_time);
622 push_nttime(blob->data, 8, st->network_open_information.out.access_time);
623 push_nttime(blob->data, 16, st->network_open_information.out.write_time);
624 push_nttime(blob->data, 24, st->network_open_information.out.change_time);
625 SBVAL(blob->data, 32, st->network_open_information.out.alloc_size);
626 SBVAL(blob->data, 40, st->network_open_information.out.size);
627 SIVAL(blob->data, 48, st->network_open_information.out.attrib);
628 SIVAL(blob->data, 52, 0); /* padding */
631 case RAW_FILEINFO_STANDARD_INFO:
632 case RAW_FILEINFO_STANDARD_INFORMATION:
633 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 24));
635 SBVAL(blob->data, 0, st->standard_info.out.alloc_size);
636 SBVAL(blob->data, 8, st->standard_info.out.size);
637 SIVAL(blob->data, 16, st->standard_info.out.nlink);
638 SCVAL(blob->data, 20, st->standard_info.out.delete_pending);
639 SCVAL(blob->data, 21, st->standard_info.out.directory);
640 SSVAL(blob->data, 22, 0); /* padding */
643 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
644 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 8));
646 SIVAL(blob->data, 0, st->attribute_tag_information.out.attrib);
647 SIVAL(blob->data, 4, st->attribute_tag_information.out.reparse_tag);
650 case RAW_FILEINFO_EA_INFO:
651 case RAW_FILEINFO_EA_INFORMATION:
652 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 4));
654 SIVAL(blob->data, 0, st->ea_info.out.ea_size);
657 case RAW_FILEINFO_MODE_INFORMATION:
658 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 4));
660 SIVAL(blob->data, 0, st->mode_information.out.mode);
663 case RAW_FILEINFO_ALIGNMENT_INFORMATION:
664 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 4));
667 st->alignment_information.out.alignment_requirement);
670 case RAW_FILEINFO_EA_LIST:
671 list_size = ea_list_size(st->ea_list.out.num_eas,
672 st->ea_list.out.eas);
673 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, list_size));
675 ea_put_list(blob->data,
676 st->ea_list.out.num_eas, st->ea_list.out.eas);
679 case RAW_FILEINFO_ALL_EAS:
680 list_size = ea_list_size(st->all_eas.out.num_eas,
681 st->all_eas.out.eas);
682 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, list_size));
684 ea_put_list(blob->data,
685 st->all_eas.out.num_eas, st->all_eas.out.eas);
688 case RAW_FILEINFO_ACCESS_INFORMATION:
689 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 4));
691 SIVAL(blob->data, 0, st->access_information.out.access_flags);
694 case RAW_FILEINFO_POSITION_INFORMATION:
695 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 8));
697 SBVAL(blob->data, 0, st->position_information.out.position);
700 case RAW_FILEINFO_COMPRESSION_INFO:
701 case RAW_FILEINFO_COMPRESSION_INFORMATION:
702 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 16));
704 SBVAL(blob->data, 0, st->compression_info.out.compressed_size);
705 SSVAL(blob->data, 8, st->compression_info.out.format);
706 SCVAL(blob->data, 10, st->compression_info.out.unit_shift);
707 SCVAL(blob->data, 11, st->compression_info.out.chunk_shift);
708 SCVAL(blob->data, 12, st->compression_info.out.cluster_shift);
709 SSVAL(blob->data, 13, 0); /* 3 bytes padding */
710 SCVAL(blob->data, 15, 0);
713 case RAW_FILEINFO_IS_NAME_VALID:
716 case RAW_FILEINFO_INTERNAL_INFORMATION:
717 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 8));
719 SBVAL(blob->data, 0, st->internal_information.out.file_id);
722 case RAW_FILEINFO_ALL_INFO:
723 case RAW_FILEINFO_ALL_INFORMATION:
724 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 72));
726 push_nttime(blob->data, 0, st->all_info.out.create_time);
727 push_nttime(blob->data, 8, st->all_info.out.access_time);
728 push_nttime(blob->data, 16, st->all_info.out.write_time);
729 push_nttime(blob->data, 24, st->all_info.out.change_time);
730 SIVAL(blob->data, 32, st->all_info.out.attrib);
731 SIVAL(blob->data, 36, 0);
732 SBVAL(blob->data, 40, st->all_info.out.alloc_size);
733 SBVAL(blob->data, 48, st->all_info.out.size);
734 SIVAL(blob->data, 56, st->all_info.out.nlink);
735 SCVAL(blob->data, 60, st->all_info.out.delete_pending);
736 SCVAL(blob->data, 61, st->all_info.out.directory);
737 SSVAL(blob->data, 62, 0); /* padding */
738 SIVAL(blob->data, 64, st->all_info.out.ea_size);
739 TRANS2_CHECK(trans2_append_data_string(req, mem_ctx, blob,
740 &st->all_info.out.fname,
744 case RAW_FILEINFO_NAME_INFO:
745 case RAW_FILEINFO_NAME_INFORMATION:
746 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 4));
748 TRANS2_CHECK(trans2_append_data_string(req, mem_ctx, blob,
749 &st->name_info.out.fname,
753 case RAW_FILEINFO_ALT_NAME_INFO:
754 case RAW_FILEINFO_ALT_NAME_INFORMATION:
755 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 4));
757 TRANS2_CHECK(trans2_append_data_string(req, mem_ctx, blob,
758 &st->alt_name_info.out.fname,
762 case RAW_FILEINFO_STREAM_INFO:
763 case RAW_FILEINFO_STREAM_INFORMATION:
764 for (i=0;i<st->stream_info.out.num_streams;i++) {
765 uint32_t data_size = blob->length;
768 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, data_size + 24));
769 data = blob->data + data_size;
770 SBVAL(data, 8, st->stream_info.out.streams[i].size);
771 SBVAL(data, 16, st->stream_info.out.streams[i].alloc_size);
772 TRANS2_CHECK(trans2_append_data_string(req, mem_ctx, blob,
773 &st->stream_info.out.streams[i].stream_name,
774 data_size + 4, STR_UNICODE));
775 if (i == st->stream_info.out.num_streams - 1) {
776 SIVAL(blob->data, data_size, 0);
778 TRANS2_CHECK(trans2_grow_data_fill(mem_ctx, blob, (blob->length+7)&~7));
779 SIVAL(blob->data, data_size,
780 blob->length - data_size);
785 case RAW_FILEINFO_UNIX_BASIC:
786 case RAW_FILEINFO_UNIX_LINK:
787 return NT_STATUS_INVALID_LEVEL;
789 case RAW_FILEINFO_SMB2_ALL_EAS:
790 case RAW_FILEINFO_SMB2_ALL_INFORMATION:
791 return NT_STATUS_INVALID_LEVEL;
794 return NT_STATUS_INVALID_LEVEL;
798 fill in the reply from a qpathinfo or qfileinfo call
800 static NTSTATUS trans2_fileinfo_send(struct trans_op *op)
802 struct smbsrv_request *req = op->req;
803 struct smb_trans2 *trans = op->trans;
804 union smb_fileinfo *st;
806 TRANS2_CHECK_ASYNC_STATUS(st, union smb_fileinfo);
808 TRANS2_CHECK(trans2_setup_reply(trans, 2, 0, 0));
809 SSVAL(trans->out.params.data, 0, 0);
811 TRANS2_CHECK(trans2_push_fileinfo(req, st, trans, &trans->out.data));
817 trans2 qpathinfo implementation
819 static NTSTATUS trans2_qpathinfo(struct smbsrv_request *req, struct trans_op *op)
821 struct smb_trans2 *trans = op->trans;
822 union smb_fileinfo *st;
826 /* make sure we got enough parameters */
827 if (trans->in.params.length < 2) {
828 return NT_STATUS_FOOBAR;
831 st = talloc(op, union smb_fileinfo);
832 NT_STATUS_HAVE_NO_MEMORY(st);
834 level = SVAL(trans->in.params.data, 0);
836 trans2_pull_blob_string(req, &trans->in.params, 6, &st->generic.in.file.path, 0);
837 if (st->generic.in.file.path == NULL) {
838 return NT_STATUS_FOOBAR;
841 /* work out the backend level - we make it 1-1 in the header */
842 st->generic.level = (enum smb_fileinfo_level)level;
843 if (st->generic.level >= RAW_FILEINFO_GENERIC) {
844 return NT_STATUS_INVALID_LEVEL;
847 if (st->generic.level == RAW_FILEINFO_EA_LIST) {
848 status = ea_pull_name_list(&trans->in.data, req,
849 &st->ea_list.in.num_names,
850 &st->ea_list.in.ea_names);
851 NT_STATUS_NOT_OK_RETURN(status);
855 op->send_fn = trans2_fileinfo_send;
857 return ntvfs_qpathinfo(req->ntvfs, st);
862 trans2 qpathinfo implementation
864 static NTSTATUS trans2_qfileinfo(struct smbsrv_request *req, struct trans_op *op)
866 struct smb_trans2 *trans = op->trans;
867 union smb_fileinfo *st;
870 struct ntvfs_handle *h;
872 /* make sure we got enough parameters */
873 if (trans->in.params.length < 4) {
874 return NT_STATUS_FOOBAR;
877 st = talloc(op, union smb_fileinfo);
878 NT_STATUS_HAVE_NO_MEMORY(st);
880 h = smbsrv_pull_fnum(req, trans->in.params.data, 0);
881 level = SVAL(trans->in.params.data, 2);
883 st->generic.in.file.ntvfs = h;
884 /* work out the backend level - we make it 1-1 in the header */
885 st->generic.level = (enum smb_fileinfo_level)level;
886 if (st->generic.level >= RAW_FILEINFO_GENERIC) {
887 return NT_STATUS_INVALID_LEVEL;
890 if (st->generic.level == RAW_FILEINFO_EA_LIST) {
891 status = ea_pull_name_list(&trans->in.data, req,
892 &st->ea_list.in.num_names,
893 &st->ea_list.in.ea_names);
894 NT_STATUS_NOT_OK_RETURN(status);
898 op->send_fn = trans2_fileinfo_send;
900 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st->generic.in.file.ntvfs);
901 return ntvfs_qfileinfo(req->ntvfs, st);
906 parse a trans2 setfileinfo/setpathinfo data blob
908 static NTSTATUS trans2_parse_sfileinfo(struct smbsrv_request *req,
909 union smb_setfileinfo *st,
910 const DATA_BLOB *blob)
914 switch (st->generic.level) {
915 case RAW_SFILEINFO_GENERIC:
916 case RAW_SFILEINFO_SETATTR:
917 case RAW_SFILEINFO_SETATTRE:
918 case RAW_SFILEINFO_SEC_DESC:
919 /* handled elsewhere */
920 return NT_STATUS_INVALID_LEVEL;
922 case RAW_SFILEINFO_STANDARD:
923 CHECK_MIN_BLOB_SIZE(blob, 12);
924 st->standard.in.create_time = srv_pull_dos_date2(req->smb_conn, blob->data + 0);
925 st->standard.in.access_time = srv_pull_dos_date2(req->smb_conn, blob->data + 4);
926 st->standard.in.write_time = srv_pull_dos_date2(req->smb_conn, blob->data + 8);
929 case RAW_SFILEINFO_EA_SET:
930 return ea_pull_list(blob, req,
931 &st->ea_set.in.num_eas,
934 case SMB_SFILEINFO_BASIC_INFO:
935 case SMB_SFILEINFO_BASIC_INFORMATION:
936 CHECK_MIN_BLOB_SIZE(blob, 36);
937 st->basic_info.in.create_time = pull_nttime(blob->data, 0);
938 st->basic_info.in.access_time = pull_nttime(blob->data, 8);
939 st->basic_info.in.write_time = pull_nttime(blob->data, 16);
940 st->basic_info.in.change_time = pull_nttime(blob->data, 24);
941 st->basic_info.in.attrib = IVAL(blob->data, 32);
944 case SMB_SFILEINFO_DISPOSITION_INFO:
945 case SMB_SFILEINFO_DISPOSITION_INFORMATION:
946 CHECK_MIN_BLOB_SIZE(blob, 1);
947 st->disposition_info.in.delete_on_close = CVAL(blob->data, 0);
950 case SMB_SFILEINFO_ALLOCATION_INFO:
951 case SMB_SFILEINFO_ALLOCATION_INFORMATION:
952 CHECK_MIN_BLOB_SIZE(blob, 8);
953 st->allocation_info.in.alloc_size = BVAL(blob->data, 0);
956 case RAW_SFILEINFO_END_OF_FILE_INFO:
957 case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
958 CHECK_MIN_BLOB_SIZE(blob, 8);
959 st->end_of_file_info.in.size = BVAL(blob->data, 0);
962 case RAW_SFILEINFO_RENAME_INFORMATION: {
965 CHECK_MIN_BLOB_SIZE(blob, 12);
966 st->rename_information.in.overwrite = CVAL(blob->data, 0);
967 st->rename_information.in.root_fid = IVAL(blob->data, 4);
968 len = IVAL(blob->data, 8);
969 blob2.data = blob->data+12;
970 blob2.length = MIN(blob->length, len);
971 trans2_pull_blob_string(req, &blob2, 0,
972 &st->rename_information.in.new_name, STR_UNICODE);
976 case RAW_SFILEINFO_POSITION_INFORMATION:
977 CHECK_MIN_BLOB_SIZE(blob, 8);
978 st->position_information.in.position = BVAL(blob->data, 0);
981 case RAW_SFILEINFO_MODE_INFORMATION:
982 CHECK_MIN_BLOB_SIZE(blob, 4);
983 st->mode_information.in.mode = IVAL(blob->data, 0);
986 case RAW_SFILEINFO_UNIX_BASIC:
987 case RAW_SFILEINFO_UNIX_LINK:
988 case RAW_SFILEINFO_UNIX_HLINK:
989 case RAW_SFILEINFO_1023:
990 case RAW_SFILEINFO_1025:
991 case RAW_SFILEINFO_1029:
992 case RAW_SFILEINFO_1032:
993 case RAW_SFILEINFO_1039:
994 case RAW_SFILEINFO_1040:
995 return NT_STATUS_INVALID_LEVEL;
998 return NT_STATUS_INVALID_LEVEL;
1002 trans2 setfileinfo implementation
1004 static NTSTATUS trans2_setfileinfo(struct smbsrv_request *req, struct trans_op *op)
1006 struct smb_trans2 *trans = op->trans;
1007 union smb_setfileinfo *st;
1010 struct ntvfs_handle *h;
1012 /* make sure we got enough parameters */
1013 if (trans->in.params.length < 4) {
1014 return NT_STATUS_FOOBAR;
1017 st = talloc(op, union smb_setfileinfo);
1018 NT_STATUS_HAVE_NO_MEMORY(st);
1020 h = smbsrv_pull_fnum(req, trans->in.params.data, 0);
1021 level = SVAL(trans->in.params.data, 2);
1023 st->generic.in.file.ntvfs = h;
1024 /* work out the backend level - we make it 1-1 in the header */
1025 st->generic.level = (enum smb_setfileinfo_level)level;
1026 if (st->generic.level >= RAW_SFILEINFO_GENERIC) {
1027 return NT_STATUS_INVALID_LEVEL;
1030 status = trans2_parse_sfileinfo(req, st, &trans->in.data);
1031 NT_STATUS_NOT_OK_RETURN(status);
1034 op->send_fn = trans2_simple_send;
1036 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st->generic.in.file.ntvfs);
1037 return ntvfs_setfileinfo(req->ntvfs, st);
1041 trans2 setpathinfo implementation
1043 static NTSTATUS trans2_setpathinfo(struct smbsrv_request *req, struct trans_op *op)
1045 struct smb_trans2 *trans = op->trans;
1046 union smb_setfileinfo *st;
1050 /* make sure we got enough parameters */
1051 if (trans->in.params.length < 4) {
1052 return NT_STATUS_FOOBAR;
1055 st = talloc(op, union smb_setfileinfo);
1056 NT_STATUS_HAVE_NO_MEMORY(st);
1058 level = SVAL(trans->in.params.data, 0);
1060 trans2_pull_blob_string(req, &trans->in.params, 6, &st->generic.in.file.path, 0);
1061 if (st->generic.in.file.path == NULL) {
1062 return NT_STATUS_FOOBAR;
1065 /* work out the backend level - we make it 1-1 in the header */
1066 st->generic.level = (enum smb_setfileinfo_level)level;
1067 if (st->generic.level >= RAW_SFILEINFO_GENERIC) {
1068 return NT_STATUS_INVALID_LEVEL;
1071 status = trans2_parse_sfileinfo(req, st, &trans->in.data);
1072 NT_STATUS_NOT_OK_RETURN(status);
1075 op->send_fn = trans2_simple_send;
1077 return ntvfs_setpathinfo(req->ntvfs, st);
1081 /* a structure to encapsulate the state information about an in-progress ffirst/fnext operation */
1083 struct trans_op *op;
1085 enum smb_search_level level;
1086 uint16_t last_entry_offset;
1091 fill a single entry in a trans2 find reply
1093 static BOOL find_fill_info(struct find_state *state,
1094 union smb_search_data *file)
1096 struct smbsrv_request *req = state->op->req;
1097 struct smb_trans2 *trans = state->op->trans;
1099 uint_t ofs = trans->out.data.length;
1102 switch (state->level) {
1103 case RAW_SEARCH_SEARCH:
1104 case RAW_SEARCH_FFIRST:
1105 case RAW_SEARCH_FUNIQUE:
1106 case RAW_SEARCH_GENERIC:
1107 case RAW_SEARCH_SMB2:
1108 /* handled elsewhere */
1111 case RAW_SEARCH_STANDARD:
1112 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
1113 trans2_grow_data(trans, &trans->out.data, ofs + 27);
1114 SIVAL(trans->out.data.data, ofs, file->standard.resume_key);
1117 trans2_grow_data(trans, &trans->out.data, ofs + 23);
1119 data = trans->out.data.data + ofs;
1120 srv_push_dos_date2(req->smb_conn, data, 0, file->standard.create_time);
1121 srv_push_dos_date2(req->smb_conn, data, 4, file->standard.access_time);
1122 srv_push_dos_date2(req->smb_conn, data, 8, file->standard.write_time);
1123 SIVAL(data, 12, file->standard.size);
1124 SIVAL(data, 16, file->standard.alloc_size);
1125 SSVAL(data, 20, file->standard.attrib);
1126 trans2_append_data_string(req, trans, &trans->out.data, &file->standard.name,
1127 ofs + 22, STR_LEN8BIT | STR_TERMINATE | STR_LEN_NOTERM);
1130 case RAW_SEARCH_EA_SIZE:
1131 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
1132 trans2_grow_data(trans, &trans->out.data, ofs + 31);
1133 SIVAL(trans->out.data.data, ofs, file->ea_size.resume_key);
1136 trans2_grow_data(trans, &trans->out.data, ofs + 27);
1138 data = trans->out.data.data + ofs;
1139 srv_push_dos_date2(req->smb_conn, data, 0, file->ea_size.create_time);
1140 srv_push_dos_date2(req->smb_conn, data, 4, file->ea_size.access_time);
1141 srv_push_dos_date2(req->smb_conn, data, 8, file->ea_size.write_time);
1142 SIVAL(data, 12, file->ea_size.size);
1143 SIVAL(data, 16, file->ea_size.alloc_size);
1144 SSVAL(data, 20, file->ea_size.attrib);
1145 SIVAL(data, 22, file->ea_size.ea_size);
1146 trans2_append_data_string(req, trans, &trans->out.data, &file->ea_size.name,
1147 ofs + 26, STR_LEN8BIT | STR_NOALIGN);
1148 trans2_grow_data(trans, &trans->out.data, trans->out.data.length + 1);
1149 trans->out.data.data[trans->out.data.length-1] = 0;
1152 case RAW_SEARCH_EA_LIST:
1153 ea_size = ea_list_size(file->ea_list.eas.num_eas, file->ea_list.eas.eas);
1154 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
1155 if (!NT_STATUS_IS_OK(trans2_grow_data(trans, &trans->out.data, ofs + 27 + ea_size))) {
1158 SIVAL(trans->out.data.data, ofs, file->ea_list.resume_key);
1161 if (!NT_STATUS_IS_OK(trans2_grow_data(trans, &trans->out.data, ofs + 23 + ea_size))) {
1165 data = trans->out.data.data + ofs;
1166 srv_push_dos_date2(req->smb_conn, data, 0, file->ea_list.create_time);
1167 srv_push_dos_date2(req->smb_conn, data, 4, file->ea_list.access_time);
1168 srv_push_dos_date2(req->smb_conn, data, 8, file->ea_list.write_time);
1169 SIVAL(data, 12, file->ea_list.size);
1170 SIVAL(data, 16, file->ea_list.alloc_size);
1171 SSVAL(data, 20, file->ea_list.attrib);
1172 ea_put_list(data+22, file->ea_list.eas.num_eas, file->ea_list.eas.eas);
1173 trans2_append_data_string(req, trans, &trans->out.data, &file->ea_list.name,
1174 ofs + 22 + ea_size, STR_LEN8BIT | STR_NOALIGN);
1175 trans2_grow_data(trans, &trans->out.data, trans->out.data.length + 1);
1176 trans->out.data.data[trans->out.data.length-1] = 0;
1179 case RAW_SEARCH_DIRECTORY_INFO:
1180 trans2_grow_data(trans, &trans->out.data, ofs + 64);
1181 data = trans->out.data.data + ofs;
1182 SIVAL(data, 4, file->directory_info.file_index);
1183 push_nttime(data, 8, file->directory_info.create_time);
1184 push_nttime(data, 16, file->directory_info.access_time);
1185 push_nttime(data, 24, file->directory_info.write_time);
1186 push_nttime(data, 32, file->directory_info.change_time);
1187 SBVAL(data, 40, file->directory_info.size);
1188 SBVAL(data, 48, file->directory_info.alloc_size);
1189 SIVAL(data, 56, file->directory_info.attrib);
1190 trans2_append_data_string(req, trans, &trans->out.data, &file->directory_info.name,
1191 ofs + 60, STR_TERMINATE_ASCII);
1192 data = trans->out.data.data + ofs;
1193 SIVAL(data, 0, trans->out.data.length - ofs);
1196 case RAW_SEARCH_FULL_DIRECTORY_INFO:
1197 trans2_grow_data(trans, &trans->out.data, ofs + 68);
1198 data = trans->out.data.data + ofs;
1199 SIVAL(data, 4, file->full_directory_info.file_index);
1200 push_nttime(data, 8, file->full_directory_info.create_time);
1201 push_nttime(data, 16, file->full_directory_info.access_time);
1202 push_nttime(data, 24, file->full_directory_info.write_time);
1203 push_nttime(data, 32, file->full_directory_info.change_time);
1204 SBVAL(data, 40, file->full_directory_info.size);
1205 SBVAL(data, 48, file->full_directory_info.alloc_size);
1206 SIVAL(data, 56, file->full_directory_info.attrib);
1207 SIVAL(data, 64, file->full_directory_info.ea_size);
1208 trans2_append_data_string(req, trans, &trans->out.data, &file->full_directory_info.name,
1209 ofs + 60, STR_TERMINATE_ASCII);
1210 data = trans->out.data.data + ofs;
1211 SIVAL(data, 0, trans->out.data.length - ofs);
1214 case RAW_SEARCH_NAME_INFO:
1215 trans2_grow_data(trans, &trans->out.data, ofs + 12);
1216 data = trans->out.data.data + ofs;
1217 SIVAL(data, 4, file->name_info.file_index);
1218 trans2_append_data_string(req, trans, &trans->out.data, &file->name_info.name,
1219 ofs + 8, STR_TERMINATE_ASCII);
1220 data = trans->out.data.data + ofs;
1221 SIVAL(data, 0, trans->out.data.length - ofs);
1224 case RAW_SEARCH_BOTH_DIRECTORY_INFO:
1225 trans2_grow_data(trans, &trans->out.data, ofs + 94);
1226 data = trans->out.data.data + ofs;
1227 SIVAL(data, 4, file->both_directory_info.file_index);
1228 push_nttime(data, 8, file->both_directory_info.create_time);
1229 push_nttime(data, 16, file->both_directory_info.access_time);
1230 push_nttime(data, 24, file->both_directory_info.write_time);
1231 push_nttime(data, 32, file->both_directory_info.change_time);
1232 SBVAL(data, 40, file->both_directory_info.size);
1233 SBVAL(data, 48, file->both_directory_info.alloc_size);
1234 SIVAL(data, 56, file->both_directory_info.attrib);
1235 SIVAL(data, 64, file->both_directory_info.ea_size);
1236 SCVAL(data, 69, 0); /* reserved */
1237 memset(data+70,0,24);
1238 trans2_push_data_string(req, trans, &trans->out.data,
1240 &file->both_directory_info.short_name,
1241 24, STR_UNICODE | STR_LEN8BIT);
1242 trans2_append_data_string(req, trans, &trans->out.data, &file->both_directory_info.name,
1243 ofs + 60, STR_TERMINATE_ASCII);
1244 trans2_align_data(trans);
1245 data = trans->out.data.data + ofs;
1246 SIVAL(data, 0, trans->out.data.length - ofs);
1249 case RAW_SEARCH_ID_FULL_DIRECTORY_INFO:
1250 trans2_grow_data(trans, &trans->out.data, ofs + 80);
1251 data = trans->out.data.data + ofs;
1252 SIVAL(data, 4, file->id_full_directory_info.file_index);
1253 push_nttime(data, 8, file->id_full_directory_info.create_time);
1254 push_nttime(data, 16, file->id_full_directory_info.access_time);
1255 push_nttime(data, 24, file->id_full_directory_info.write_time);
1256 push_nttime(data, 32, file->id_full_directory_info.change_time);
1257 SBVAL(data, 40, file->id_full_directory_info.size);
1258 SBVAL(data, 48, file->id_full_directory_info.alloc_size);
1259 SIVAL(data, 56, file->id_full_directory_info.attrib);
1260 SIVAL(data, 64, file->id_full_directory_info.ea_size);
1261 SIVAL(data, 68, 0); /* padding */
1262 SBVAL(data, 72, file->id_full_directory_info.file_id);
1263 trans2_append_data_string(req, trans, &trans->out.data, &file->id_full_directory_info.name,
1264 ofs + 60, STR_TERMINATE_ASCII);
1265 data = trans->out.data.data + ofs;
1266 SIVAL(data, 0, trans->out.data.length - ofs);
1269 case RAW_SEARCH_ID_BOTH_DIRECTORY_INFO:
1270 trans2_grow_data(trans, &trans->out.data, ofs + 104);
1271 data = trans->out.data.data + ofs;
1272 SIVAL(data, 4, file->id_both_directory_info.file_index);
1273 push_nttime(data, 8, file->id_both_directory_info.create_time);
1274 push_nttime(data, 16, file->id_both_directory_info.access_time);
1275 push_nttime(data, 24, file->id_both_directory_info.write_time);
1276 push_nttime(data, 32, file->id_both_directory_info.change_time);
1277 SBVAL(data, 40, file->id_both_directory_info.size);
1278 SBVAL(data, 48, file->id_both_directory_info.alloc_size);
1279 SIVAL(data, 56, file->id_both_directory_info.attrib);
1280 SIVAL(data, 64, file->id_both_directory_info.ea_size);
1281 SCVAL(data, 69, 0); /* reserved */
1282 memset(data+70,0,26);
1283 trans2_push_data_string(req, trans, &trans->out.data,
1285 &file->id_both_directory_info.short_name,
1286 24, STR_UNICODE | STR_LEN8BIT);
1287 SBVAL(data, 96, file->id_both_directory_info.file_id);
1288 trans2_append_data_string(req, trans, &trans->out.data, &file->id_both_directory_info.name,
1289 ofs + 60, STR_TERMINATE_ASCII);
1290 data = trans->out.data.data + ofs;
1291 SIVAL(data, 0, trans->out.data.length - ofs);
1298 /* callback function for trans2 findfirst/findnext */
1299 static BOOL find_callback(void *private, union smb_search_data *file)
1301 struct find_state *state = talloc_get_type(private, struct find_state);
1302 struct smb_trans2 *trans = state->op->trans;
1305 old_length = trans->out.data.length;
1307 if (!find_fill_info(state, file) ||
1308 trans->out.data.length > trans->in.max_data) {
1309 /* restore the old length and tell the backend to stop */
1310 trans2_grow_data(trans, &trans->out.data, old_length);
1314 state->last_entry_offset = old_length;
1319 trans2 findfirst send
1321 static NTSTATUS trans2_findfirst_send(struct trans_op *op)
1323 struct smbsrv_request *req = op->req;
1324 struct smb_trans2 *trans = op->trans;
1325 union smb_search_first *search;
1326 struct find_state *state;
1329 TRANS2_CHECK_ASYNC_STATUS(state, struct find_state);
1330 search = talloc_get_type(state->search, union smb_search_first);
1332 /* fill in the findfirst reply header */
1333 param = trans->out.params.data;
1334 SSVAL(param, VWV(0), search->t2ffirst.out.handle);
1335 SSVAL(param, VWV(1), search->t2ffirst.out.count);
1336 SSVAL(param, VWV(2), search->t2ffirst.out.end_of_search);
1337 SSVAL(param, VWV(3), 0);
1338 SSVAL(param, VWV(4), state->last_entry_offset);
1340 return NT_STATUS_OK;
1345 trans2 findfirst implementation
1347 static NTSTATUS trans2_findfirst(struct smbsrv_request *req, struct trans_op *op)
1349 struct smb_trans2 *trans = op->trans;
1350 union smb_search_first *search;
1353 struct find_state *state;
1355 /* make sure we got all the parameters */
1356 if (trans->in.params.length < 14) {
1357 return NT_STATUS_FOOBAR;
1360 search = talloc(op, union smb_search_first);
1361 NT_STATUS_HAVE_NO_MEMORY(search);
1363 search->t2ffirst.in.search_attrib = SVAL(trans->in.params.data, 0);
1364 search->t2ffirst.in.max_count = SVAL(trans->in.params.data, 2);
1365 search->t2ffirst.in.flags = SVAL(trans->in.params.data, 4);
1366 level = SVAL(trans->in.params.data, 6);
1367 search->t2ffirst.in.storage_type = IVAL(trans->in.params.data, 8);
1369 trans2_pull_blob_string(req, &trans->in.params, 12, &search->t2ffirst.in.pattern, 0);
1370 if (search->t2ffirst.in.pattern == NULL) {
1371 return NT_STATUS_FOOBAR;
1374 search->t2ffirst.level = (enum smb_search_level)level;
1375 if (search->t2ffirst.level >= RAW_SEARCH_GENERIC) {
1376 return NT_STATUS_INVALID_LEVEL;
1379 if (search->t2ffirst.level == RAW_SEARCH_EA_LIST) {
1380 status = ea_pull_name_list(&trans->in.data, req,
1381 &search->t2ffirst.in.num_names,
1382 &search->t2ffirst.in.ea_names);
1383 NT_STATUS_NOT_OK_RETURN(status);
1386 /* setup the private state structure that the backend will
1387 give us in the callback */
1388 state = talloc(op, struct find_state);
1389 NT_STATUS_HAVE_NO_MEMORY(state);
1391 state->search = search;
1392 state->level = search->t2ffirst.level;
1393 state->last_entry_offset= 0;
1394 state->flags = search->t2ffirst.in.flags;
1396 /* setup for just a header in the reply */
1397 trans2_setup_reply(trans, 10, 0, 0);
1399 op->op_info = state;
1400 op->send_fn = trans2_findfirst_send;
1402 return ntvfs_search_first(req->ntvfs, search, state, find_callback);
1407 trans2 findnext send
1409 static NTSTATUS trans2_findnext_send(struct trans_op *op)
1411 struct smbsrv_request *req = op->req;
1412 struct smb_trans2 *trans = op->trans;
1413 union smb_search_next *search;
1414 struct find_state *state;
1417 TRANS2_CHECK_ASYNC_STATUS(state, struct find_state);
1418 search = talloc_get_type(state->search, union smb_search_next);
1420 /* fill in the findfirst reply header */
1421 param = trans->out.params.data;
1422 SSVAL(param, VWV(0), search->t2fnext.out.count);
1423 SSVAL(param, VWV(1), search->t2fnext.out.end_of_search);
1424 SSVAL(param, VWV(2), 0);
1425 SSVAL(param, VWV(3), state->last_entry_offset);
1427 return NT_STATUS_OK;
1432 trans2 findnext implementation
1434 static NTSTATUS trans2_findnext(struct smbsrv_request *req, struct trans_op *op)
1436 struct smb_trans2 *trans = op->trans;
1437 union smb_search_next *search;
1440 struct find_state *state;
1442 /* make sure we got all the parameters */
1443 if (trans->in.params.length < 12) {
1444 return NT_STATUS_FOOBAR;
1447 search = talloc(op, union smb_search_next);
1448 NT_STATUS_HAVE_NO_MEMORY(search);
1450 search->t2fnext.in.handle = SVAL(trans->in.params.data, 0);
1451 search->t2fnext.in.max_count = SVAL(trans->in.params.data, 2);
1452 level = SVAL(trans->in.params.data, 4);
1453 search->t2fnext.in.resume_key = IVAL(trans->in.params.data, 6);
1454 search->t2fnext.in.flags = SVAL(trans->in.params.data, 10);
1456 trans2_pull_blob_string(req, &trans->in.params, 12, &search->t2fnext.in.last_name, 0);
1457 if (search->t2fnext.in.last_name == NULL) {
1458 return NT_STATUS_FOOBAR;
1461 search->t2fnext.level = (enum smb_search_level)level;
1462 if (search->t2fnext.level >= RAW_SEARCH_GENERIC) {
1463 return NT_STATUS_INVALID_LEVEL;
1466 if (search->t2fnext.level == RAW_SEARCH_EA_LIST) {
1467 status = ea_pull_name_list(&trans->in.data, req,
1468 &search->t2fnext.in.num_names,
1469 &search->t2fnext.in.ea_names);
1470 NT_STATUS_NOT_OK_RETURN(status);
1473 /* setup the private state structure that the backend will give us in the callback */
1474 state = talloc(op, struct find_state);
1475 NT_STATUS_HAVE_NO_MEMORY(state);
1477 state->search = search;
1478 state->level = search->t2fnext.level;
1479 state->last_entry_offset= 0;
1480 state->flags = search->t2fnext.in.flags;
1482 /* setup for just a header in the reply */
1483 trans2_setup_reply(trans, 8, 0, 0);
1485 op->op_info = state;
1486 op->send_fn = trans2_findnext_send;
1488 return ntvfs_search_next(req->ntvfs, search, state, find_callback);
1493 backend for trans2 requests
1495 static NTSTATUS trans2_backend(struct smbsrv_request *req, struct trans_op *op)
1497 struct smb_trans2 *trans = op->trans;
1500 /* direct trans2 pass thru */
1501 status = ntvfs_trans2(req->ntvfs, trans);
1502 if (!NT_STATUS_EQUAL(NT_STATUS_NOT_IMPLEMENTED, status)) {
1506 /* must have at least one setup word */
1507 if (trans->in.setup_count < 1) {
1508 return NT_STATUS_FOOBAR;
1511 /* the trans2 command is in setup[0] */
1512 switch (trans->in.setup[0]) {
1513 case TRANSACT2_FINDFIRST:
1514 return trans2_findfirst(req, op);
1515 case TRANSACT2_FINDNEXT:
1516 return trans2_findnext(req, op);
1517 case TRANSACT2_QPATHINFO:
1518 return trans2_qpathinfo(req, op);
1519 case TRANSACT2_QFILEINFO:
1520 return trans2_qfileinfo(req, op);
1521 case TRANSACT2_SETFILEINFO:
1522 return trans2_setfileinfo(req, op);
1523 case TRANSACT2_SETPATHINFO:
1524 return trans2_setpathinfo(req, op);
1525 case TRANSACT2_QFSINFO:
1526 return trans2_qfsinfo(req, op);
1527 case TRANSACT2_OPEN:
1528 return trans2_open(req, op);
1529 case TRANSACT2_MKDIR:
1530 return trans2_mkdir(req, op);
1533 /* an unknown trans2 command */
1534 return NT_STATUS_FOOBAR;
1539 send a continue request
1541 static void reply_trans_continue(struct smbsrv_request *req, uint8_t command,
1542 struct smb_trans2 *trans)
1544 struct smbsrv_trans_partial *tp;
1547 /* make sure they don't flood us */
1548 for (count=0,tp=req->smb_conn->trans_partial;tp;tp=tp->next) count++;
1550 smbsrv_send_error(req, NT_STATUS_INSUFFICIENT_RESOURCES);
1554 tp = talloc(req, struct smbsrv_trans_partial);
1556 tp->req = talloc_reference(tp, req);
1558 tp->command = command;
1560 DLIST_ADD(req->smb_conn->trans_partial, tp);
1562 /* send a 'please continue' reply */
1563 smbsrv_setup_reply(req, 0, 0);
1564 smbsrv_send_reply(req);
1569 answer a reconstructed trans request
1571 static void reply_trans_send(struct ntvfs_request *ntvfs)
1573 struct smbsrv_request *req;
1574 struct trans_op *op;
1575 struct smb_trans2 *trans;
1576 uint16_t params_left, data_left;
1577 uint8_t *params, *data;
1580 SMBSRV_CHECK_ASYNC_STATUS_ERR(op, struct trans_op);
1583 /* if this function needs work to form the nttrans reply buffer, then
1585 if (op->send_fn != NULL) {
1587 status = op->send_fn(op);
1588 if (!NT_STATUS_IS_OK(status)) {
1589 smbsrv_send_error(req, status);
1594 params_left = trans->out.params.length;
1595 data_left = trans->out.data.length;
1596 params = trans->out.params.data;
1597 data = trans->out.data.data;
1599 smbsrv_setup_reply(req, 10 + trans->out.setup_count, 0);
1601 if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) {
1602 smbsrv_setup_error(req, req->ntvfs->async_states->status);
1605 /* we need to divide up the reply into chunks that fit into
1606 the negotiated buffer size */
1608 uint16_t this_data, this_param, max_bytes;
1609 uint_t align1 = 1, align2 = (params_left ? 2 : 0);
1610 struct smbsrv_request *this_req;
1612 max_bytes = req_max_data(req) - (align1 + align2);
1614 this_param = params_left;
1615 if (this_param > max_bytes) {
1616 this_param = max_bytes;
1618 max_bytes -= this_param;
1620 this_data = data_left;
1621 if (this_data > max_bytes) {
1622 this_data = max_bytes;
1625 /* don't destroy unless this is the last chunk */
1626 if (params_left - this_param != 0 ||
1627 data_left - this_data != 0) {
1628 this_req = smbsrv_setup_secondary_request(req);
1633 req_grow_data(this_req, this_param + this_data + (align1 + align2));
1635 SSVAL(this_req->out.vwv, VWV(0), trans->out.params.length);
1636 SSVAL(this_req->out.vwv, VWV(1), trans->out.data.length);
1637 SSVAL(this_req->out.vwv, VWV(2), 0);
1639 SSVAL(this_req->out.vwv, VWV(3), this_param);
1640 SSVAL(this_req->out.vwv, VWV(4), align1 + PTR_DIFF(this_req->out.data, this_req->out.hdr));
1641 SSVAL(this_req->out.vwv, VWV(5), PTR_DIFF(params, trans->out.params.data));
1643 SSVAL(this_req->out.vwv, VWV(6), this_data);
1644 SSVAL(this_req->out.vwv, VWV(7), align1 + align2 +
1645 PTR_DIFF(this_req->out.data + this_param, this_req->out.hdr));
1646 SSVAL(this_req->out.vwv, VWV(8), PTR_DIFF(data, trans->out.data.data));
1648 SSVAL(this_req->out.vwv, VWV(9), trans->out.setup_count);
1649 for (i=0;i<trans->out.setup_count;i++) {
1650 SSVAL(this_req->out.vwv, VWV(10+i), trans->out.setup[i]);
1653 memset(this_req->out.data, 0, align1);
1654 if (this_param != 0) {
1655 memcpy(this_req->out.data + align1, params, this_param);
1657 memset(this_req->out.data+this_param+align1, 0, align2);
1658 if (this_data != 0) {
1659 memcpy(this_req->out.data+this_param+align1+align2, data, this_data);
1662 params_left -= this_param;
1663 data_left -= this_data;
1664 params += this_param;
1667 smbsrv_send_reply(this_req);
1668 } while (params_left != 0 || data_left != 0);
1673 answer a reconstructed trans request
1675 static void reply_trans_complete(struct smbsrv_request *req, uint8_t command,
1676 struct smb_trans2 *trans)
1678 struct trans_op *op;
1680 SMBSRV_TALLOC_IO_PTR(op, struct trans_op);
1681 SMBSRV_SETUP_NTVFS_REQUEST(reply_trans_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1685 op->command = command;
1689 /* its a full request, give it to the backend */
1690 if (command == SMBtrans) {
1691 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_trans(req->ntvfs, trans));
1694 SMBSRV_CALL_NTVFS_BACKEND(trans2_backend(req, op));
1700 Reply to an SMBtrans or SMBtrans2 request
1702 static void reply_trans_generic(struct smbsrv_request *req, uint8_t command)
1704 struct smb_trans2 *trans;
1706 uint16_t param_ofs, data_ofs;
1707 uint16_t param_count, data_count;
1708 uint16_t param_total, data_total;
1711 if (req->in.wct < 14) {
1712 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1716 trans = talloc(req, struct smb_trans2);
1717 if (trans == NULL) {
1718 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
1722 param_total = SVAL(req->in.vwv, VWV(0));
1723 data_total = SVAL(req->in.vwv, VWV(1));
1724 trans->in.max_param = SVAL(req->in.vwv, VWV(2));
1725 trans->in.max_data = SVAL(req->in.vwv, VWV(3));
1726 trans->in.max_setup = CVAL(req->in.vwv, VWV(4));
1727 trans->in.flags = SVAL(req->in.vwv, VWV(5));
1728 trans->in.timeout = IVAL(req->in.vwv, VWV(6));
1729 param_count = SVAL(req->in.vwv, VWV(9));
1730 param_ofs = SVAL(req->in.vwv, VWV(10));
1731 data_count = SVAL(req->in.vwv, VWV(11));
1732 data_ofs = SVAL(req->in.vwv, VWV(12));
1733 trans->in.setup_count = CVAL(req->in.vwv, VWV(13));
1735 if (req->in.wct != 14 + trans->in.setup_count) {
1736 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
1740 /* parse out the setup words */
1741 trans->in.setup = talloc_array(trans, uint16_t, trans->in.setup_count);
1742 if (trans->in.setup_count && !trans->in.setup) {
1743 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
1746 for (i=0;i<trans->in.setup_count;i++) {
1747 trans->in.setup[i] = SVAL(req->in.vwv, VWV(14+i));
1750 if (command == SMBtrans) {
1751 req_pull_string(req, &trans->in.trans_name, req->in.data, -1, STR_TERMINATE);
1754 if (!req_pull_blob(req, req->in.hdr + param_ofs, param_count, &trans->in.params) ||
1755 !req_pull_blob(req, req->in.hdr + data_ofs, data_count, &trans->in.data)) {
1756 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1760 /* is it a partial request? if so, then send a 'send more' message */
1761 if (param_total > param_count || data_total > data_count) {
1762 reply_trans_continue(req, command, trans);
1766 reply_trans_complete(req, command, trans);
1771 Reply to an SMBtranss2 request
1773 static void reply_transs_generic(struct smbsrv_request *req, uint8_t command)
1775 struct smbsrv_trans_partial *tp;
1776 struct smb_trans2 *trans = NULL;
1777 uint16_t param_ofs, data_ofs;
1778 uint16_t param_count, data_count;
1779 uint16_t param_disp, data_disp;
1780 uint16_t param_total, data_total;
1781 DATA_BLOB params, data;
1784 if (req->in.wct < 8) {
1785 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1789 for (tp=req->smb_conn->trans_partial;tp;tp=tp->next) {
1790 if (tp->command == command &&
1791 SVAL(tp->req->in.hdr, HDR_MID) == SVAL(req->in.hdr, HDR_MID)) {
1792 /* TODO: check the VUID, PID and TID too? */
1798 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1804 param_total = SVAL(req->in.vwv, VWV(0));
1805 data_total = SVAL(req->in.vwv, VWV(1));
1806 param_count = SVAL(req->in.vwv, VWV(2));
1807 param_ofs = SVAL(req->in.vwv, VWV(3));
1808 param_disp = SVAL(req->in.vwv, VWV(4));
1809 data_count = SVAL(req->in.vwv, VWV(5));
1810 data_ofs = SVAL(req->in.vwv, VWV(6));
1811 data_disp = SVAL(req->in.vwv, VWV(7));
1813 if (!req_pull_blob(req, req->in.hdr + param_ofs, param_count, ¶ms) ||
1814 !req_pull_blob(req, req->in.hdr + data_ofs, data_count, &data)) {
1815 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1819 /* only allow contiguous requests */
1820 if ((param_count != 0 &&
1821 param_disp != trans->in.params.length) ||
1823 data_disp != trans->in.data.length)) {
1824 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1828 /* add to the existing request */
1829 if (param_count != 0) {
1830 trans->in.params.data = talloc_realloc(trans,
1831 trans->in.params.data,
1833 param_disp + param_count);
1834 if (trans->in.params.data == NULL) {
1837 trans->in.params.length = param_disp + param_count;
1840 if (data_count != 0) {
1841 trans->in.data.data = talloc_realloc(trans,
1842 trans->in.data.data,
1844 data_disp + data_count);
1845 if (trans->in.data.data == NULL) {
1848 trans->in.data.length = data_disp + data_count;
1851 memcpy(trans->in.params.data + param_disp, params.data, params.length);
1852 memcpy(trans->in.data.data + data_disp, data.data, data.length);
1854 /* the sequence number of the reply is taken from the last secondary
1856 tp->req->seq_num = req->seq_num;
1858 /* we don't reply to Transs2 requests */
1861 if (trans->in.params.length == param_total &&
1862 trans->in.data.length == data_total) {
1863 /* its now complete */
1864 DLIST_REMOVE(tp->req->smb_conn->trans_partial, tp);
1865 reply_trans_complete(tp->req, command, trans);
1870 smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
1871 DLIST_REMOVE(req->smb_conn->trans_partial, tp);
1878 Reply to an SMBtrans2
1880 void smbsrv_reply_trans2(struct smbsrv_request *req)
1882 reply_trans_generic(req, SMBtrans2);
1886 Reply to an SMBtrans
1888 void smbsrv_reply_trans(struct smbsrv_request *req)
1890 reply_trans_generic(req, SMBtrans);
1894 Reply to an SMBtranss request
1896 void smbsrv_reply_transs(struct smbsrv_request *req)
1898 reply_transs_generic(req, SMBtrans);
1902 Reply to an SMBtranss2 request
1904 void smbsrv_reply_transs2(struct smbsrv_request *req)
1906 reply_transs_generic(req, SMBtrans2);