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); \
43 hold the state of a nttrans op while in progress. Needed to allow for async backend
47 struct smbsrv_request *req;
48 struct smb_trans2 *trans;
50 NTSTATUS (*send_fn)(struct trans_op *);
54 #define CHECK_MIN_BLOB_SIZE(blob, size) do { \
55 if ((blob)->length < (size)) { \
56 return NT_STATUS_INFO_LENGTH_MISMATCH; \
59 /* grow the data allocation size of a trans2 reply - this guarantees
60 that requests to grow the data size later will not change the
62 static BOOL trans2_grow_data_allocation(struct smb_trans2 *trans,
65 if (new_size <= trans->out.data.length) {
68 trans->out.data.data = talloc_realloc(trans, trans->out.data.data,
70 return (trans->out.data.data != NULL);
74 /* grow the data size of a trans2 reply */
75 static BOOL trans2_grow_data(struct smb_trans2 *trans,
78 if (!trans2_grow_data_allocation(trans, new_size)) {
81 trans->out.data.length = new_size;
85 /* grow the data, zero filling any new bytes */
86 static BOOL trans2_grow_data_fill(struct smb_trans2 *trans,
89 uint32_t old_size = trans->out.data.length;
90 if (!trans2_grow_data(trans, new_size)) {
93 if (new_size > old_size) {
94 memset(trans->out.data.data + old_size, 0, new_size - old_size);
100 /* setup a trans2 reply, given the data and params sizes */
101 static void trans2_setup_reply(struct smb_trans2 *trans,
102 uint16_t param_size, uint16_t data_size,
103 uint16_t setup_count)
105 trans->out.setup_count = setup_count;
106 if (setup_count != 0) {
107 trans->out.setup = talloc_zero_array(trans, uint16_t, setup_count);
109 trans->out.params = data_blob_talloc(trans, NULL, param_size);
110 trans->out.data = data_blob_talloc(trans, NULL, data_size);
115 pull a string from a blob in a trans2 request
117 static size_t trans2_pull_blob_string(struct smbsrv_request *req,
118 const DATA_BLOB *blob,
123 /* we use STR_NO_RANGE_CHECK because the params are allocated
124 separately in a DATA_BLOB, so we need to do our own range
126 if (offset >= blob->length) {
131 return req_pull_string(req, str,
133 blob->length - offset,
134 STR_NO_RANGE_CHECK | flags);
138 push a string into the data section of a trans2 request
139 return the number of bytes consumed in the output
141 static size_t trans2_push_data_string(struct smbsrv_request *req,
142 struct smb_trans2 *trans,
145 const struct smb_wire_string *str,
149 int alignment = 0, ret = 0, pkt_len;
151 /* we use STR_NO_RANGE_CHECK because the params are allocated
152 separately in a DATA_BLOB, so we need to do our own range
154 if (!str->s || offset >= trans->out.data.length) {
155 if (flags & STR_LEN8BIT) {
156 SCVAL(trans->out.data.data, len_offset, 0);
158 SIVAL(trans->out.data.data, len_offset, 0);
163 flags |= STR_NO_RANGE_CHECK;
165 if (dest_len == -1 || (dest_len > trans->out.data.length - offset)) {
166 dest_len = trans->out.data.length - offset;
169 if (!(flags & (STR_ASCII|STR_UNICODE))) {
170 flags |= (req->flags2 & FLAGS2_UNICODE_STRINGS) ? STR_UNICODE : STR_ASCII;
173 if ((offset&1) && (flags & STR_UNICODE) && !(flags & STR_NOALIGN)) {
176 SCVAL(trans->out.data.data + offset, 0, 0);
177 ret = push_string(trans->out.data.data + offset + 1, str->s, dest_len-1, flags);
180 ret = push_string(trans->out.data.data + offset, str->s, dest_len, flags);
183 /* sometimes the string needs to be terminated, but the length
184 on the wire must not include the termination! */
187 if ((flags & STR_LEN_NOTERM) && (flags & STR_TERMINATE)) {
188 if ((flags & STR_UNICODE) && ret >= 2) {
191 if ((flags & STR_ASCII) && ret >= 1) {
196 if (flags & STR_LEN8BIT) {
197 SCVAL(trans->out.data.data, len_offset, pkt_len);
199 SIVAL(trans->out.data.data, len_offset, pkt_len);
202 return ret + alignment;
206 append a string to the data section of a trans2 reply
207 len_offset points to the place in the packet where the length field
210 static void trans2_append_data_string(struct smbsrv_request *req,
211 struct smb_trans2 *trans,
212 const struct smb_wire_string *str,
218 const int max_bytes_per_char = 3;
220 offset = trans->out.data.length;
221 trans2_grow_data(trans, offset + (2+strlen_m(str->s))*max_bytes_per_char);
222 ret = trans2_push_data_string(req, trans, len_offset, offset, str, -1, flags);
223 trans2_grow_data(trans, offset + ret);
227 align the end of the data section of a trans reply on an even boundary
229 static void trans2_align_data(struct smbsrv_request *req, struct smb_trans2 *trans)
231 if ((trans->out.data.length & 1) == 0) {
234 trans2_grow_data(trans, trans->out.data.length+1);
235 SCVAL(trans->out.data.data, trans->out.data.length-1, 0);
240 trans2 qfsinfo implementation send
242 static NTSTATUS trans2_qfsinfo_send(struct trans_op *op)
244 struct smbsrv_request *req = op->req;
245 struct smb_trans2 *trans = op->trans;
246 union smb_fsinfo *fsinfo;
251 TRANS2_CHECK_ASYNC_STATUS(fsinfo, union smb_fsinfo);
253 switch (fsinfo->generic.level) {
254 case SMB_QFS_ALLOCATION:
255 trans2_setup_reply(trans, 0, 18, 0);
257 SIVAL(trans->out.data.data, 0, fsinfo->allocation.out.fs_id);
258 SIVAL(trans->out.data.data, 4, fsinfo->allocation.out.sectors_per_unit);
259 SIVAL(trans->out.data.data, 8, fsinfo->allocation.out.total_alloc_units);
260 SIVAL(trans->out.data.data, 12, fsinfo->allocation.out.avail_alloc_units);
261 SSVAL(trans->out.data.data, 16, fsinfo->allocation.out.bytes_per_sector);
266 trans2_setup_reply(trans, 0, 5, 0);
268 SIVAL(trans->out.data.data, 0, fsinfo->volume.out.serial_number);
269 /* w2k3 implements this incorrectly for unicode - it
270 * leaves the last byte off the string */
271 trans2_append_data_string(req, trans,
272 &fsinfo->volume.out.volume_name,
273 4, STR_LEN8BIT|STR_NOALIGN);
277 case SMB_QFS_VOLUME_INFO:
278 case SMB_QFS_VOLUME_INFORMATION:
279 trans2_setup_reply(trans, 0, 18, 0);
281 push_nttime(trans->out.data.data, 0, fsinfo->volume_info.out.create_time);
282 SIVAL(trans->out.data.data, 8, fsinfo->volume_info.out.serial_number);
283 SSVAL(trans->out.data.data, 16, 0); /* padding */
284 trans2_append_data_string(req, trans,
285 &fsinfo->volume_info.out.volume_name,
290 case SMB_QFS_SIZE_INFO:
291 case SMB_QFS_SIZE_INFORMATION:
292 trans2_setup_reply(trans, 0, 24, 0);
294 SBVAL(trans->out.data.data, 0, fsinfo->size_info.out.total_alloc_units);
295 SBVAL(trans->out.data.data, 8, fsinfo->size_info.out.avail_alloc_units);
296 SIVAL(trans->out.data.data, 16, fsinfo->size_info.out.sectors_per_unit);
297 SIVAL(trans->out.data.data, 20, fsinfo->size_info.out.bytes_per_sector);
301 case SMB_QFS_DEVICE_INFO:
302 case SMB_QFS_DEVICE_INFORMATION:
303 trans2_setup_reply(trans, 0, 8, 0);
304 SIVAL(trans->out.data.data, 0, fsinfo->device_info.out.device_type);
305 SIVAL(trans->out.data.data, 4, fsinfo->device_info.out.characteristics);
309 case SMB_QFS_ATTRIBUTE_INFO:
310 case SMB_QFS_ATTRIBUTE_INFORMATION:
311 trans2_setup_reply(trans, 0, 12, 0);
313 SIVAL(trans->out.data.data, 0, fsinfo->attribute_info.out.fs_attr);
314 SIVAL(trans->out.data.data, 4, fsinfo->attribute_info.out.max_file_component_length);
315 /* this must not be null terminated or win98 gets
316 confused! also note that w2k3 returns this as
317 unicode even when ascii is negotiated */
318 trans2_append_data_string(req, trans,
319 &fsinfo->attribute_info.out.fs_type,
324 case SMB_QFS_QUOTA_INFORMATION:
325 trans2_setup_reply(trans, 0, 48, 0);
327 SBVAL(trans->out.data.data, 0, fsinfo->quota_information.out.unknown[0]);
328 SBVAL(trans->out.data.data, 8, fsinfo->quota_information.out.unknown[1]);
329 SBVAL(trans->out.data.data, 16, fsinfo->quota_information.out.unknown[2]);
330 SBVAL(trans->out.data.data, 24, fsinfo->quota_information.out.quota_soft);
331 SBVAL(trans->out.data.data, 32, fsinfo->quota_information.out.quota_hard);
332 SBVAL(trans->out.data.data, 40, fsinfo->quota_information.out.quota_flags);
337 case SMB_QFS_FULL_SIZE_INFORMATION:
338 trans2_setup_reply(trans, 0, 32, 0);
340 SBVAL(trans->out.data.data, 0, fsinfo->full_size_information.out.total_alloc_units);
341 SBVAL(trans->out.data.data, 8, fsinfo->full_size_information.out.call_avail_alloc_units);
342 SBVAL(trans->out.data.data, 16, fsinfo->full_size_information.out.actual_avail_alloc_units);
343 SIVAL(trans->out.data.data, 24, fsinfo->full_size_information.out.sectors_per_unit);
344 SIVAL(trans->out.data.data, 28, fsinfo->full_size_information.out.bytes_per_sector);
348 case SMB_QFS_OBJECTID_INFORMATION:
349 trans2_setup_reply(trans, 0, 64, 0);
351 status = ndr_push_struct_blob(&guid_blob, req,
352 &fsinfo->objectid_information.out.guid,
353 (ndr_push_flags_fn_t)ndr_push_GUID);
354 if (!NT_STATUS_IS_OK(status)) {
358 memcpy(trans->out.data.data, guid_blob.data, guid_blob.length);
361 SBVAL(trans->out.data.data, 16 + 8*i, fsinfo->objectid_information.out.unknown[i]);
366 return NT_STATUS_INVALID_LEVEL;
370 trans2 qfsinfo implementation
372 static NTSTATUS trans2_qfsinfo(struct smbsrv_request *req, struct trans_op *op)
374 struct smb_trans2 *trans = op->trans;
375 union smb_fsinfo *fsinfo;
378 /* make sure we got enough parameters */
379 if (trans->in.params.length != 2) {
380 return NT_STATUS_FOOBAR;
383 fsinfo = talloc(op, union smb_fsinfo);
384 NT_STATUS_HAVE_NO_MEMORY(fsinfo);
386 op->op_info = fsinfo;
387 op->send_fn = trans2_qfsinfo_send;
389 level = SVAL(trans->in.params.data, 0);
392 case SMB_QFS_ALLOCATION:
393 fsinfo->allocation.level = RAW_QFS_ALLOCATION;
394 return ntvfs_fsinfo(req->ntvfs, fsinfo);
397 fsinfo->volume.level = RAW_QFS_VOLUME;
398 return ntvfs_fsinfo(req->ntvfs, fsinfo);
400 case SMB_QFS_VOLUME_INFO:
401 case SMB_QFS_VOLUME_INFORMATION:
402 fsinfo->volume_info.level = RAW_QFS_VOLUME_INFO;
403 return ntvfs_fsinfo(req->ntvfs, fsinfo);
405 case SMB_QFS_SIZE_INFO:
406 case SMB_QFS_SIZE_INFORMATION:
407 fsinfo->size_info.level = RAW_QFS_SIZE_INFO;
408 return ntvfs_fsinfo(req->ntvfs, fsinfo);
410 case SMB_QFS_DEVICE_INFO:
411 case SMB_QFS_DEVICE_INFORMATION:
412 fsinfo->device_info.level = RAW_QFS_DEVICE_INFO;
413 return ntvfs_fsinfo(req->ntvfs, fsinfo);
415 case SMB_QFS_ATTRIBUTE_INFO:
416 case SMB_QFS_ATTRIBUTE_INFORMATION:
417 fsinfo->attribute_info.level = RAW_QFS_ATTRIBUTE_INFO;
418 return ntvfs_fsinfo(req->ntvfs, fsinfo);
420 case SMB_QFS_QUOTA_INFORMATION:
421 fsinfo->quota_information.level = RAW_QFS_QUOTA_INFORMATION;
422 return ntvfs_fsinfo(req->ntvfs, fsinfo);
424 case SMB_QFS_FULL_SIZE_INFORMATION:
425 fsinfo->full_size_information.level = RAW_QFS_FULL_SIZE_INFORMATION;
426 return ntvfs_fsinfo(req->ntvfs, fsinfo);
428 case SMB_QFS_OBJECTID_INFORMATION:
429 fsinfo->objectid_information.level = RAW_QFS_OBJECTID_INFORMATION;
430 return ntvfs_fsinfo(req->ntvfs, fsinfo);
433 return NT_STATUS_INVALID_LEVEL;
438 trans2 open implementation send
440 static NTSTATUS trans2_open_send(struct trans_op *op)
442 struct smbsrv_request *req = op->req;
443 struct smb_trans2 *trans = op->trans;
446 TRANS2_CHECK_ASYNC_STATUS(io, union smb_open);
448 trans2_setup_reply(trans, 30, 0, 0);
450 smbsrv_push_fnum(trans->out.params.data, VWV(0), io->t2open.out.file.ntvfs);
451 SSVAL(trans->out.params.data, VWV(1), io->t2open.out.attrib);
452 srv_push_dos_date3(req->smb_conn, trans->out.params.data,
453 VWV(2), io->t2open.out.write_time);
454 SIVAL(trans->out.params.data, VWV(4), io->t2open.out.size);
455 SSVAL(trans->out.params.data, VWV(6), io->t2open.out.access);
456 SSVAL(trans->out.params.data, VWV(7), io->t2open.out.ftype);
457 SSVAL(trans->out.params.data, VWV(8), io->t2open.out.devstate);
458 SSVAL(trans->out.params.data, VWV(9), io->t2open.out.action);
459 SIVAL(trans->out.params.data, VWV(10), 0); /* reserved */
460 SSVAL(trans->out.params.data, VWV(12), 0); /* EaErrorOffset */
461 SIVAL(trans->out.params.data, VWV(13), 0); /* EaLength */
467 trans2 open implementation
469 static NTSTATUS trans2_open(struct smbsrv_request *req, struct trans_op *op)
471 struct smb_trans2 *trans = op->trans;
475 /* make sure we got enough parameters */
476 if (trans->in.params.length < 29) {
477 return NT_STATUS_FOOBAR;
480 io = talloc(op, union smb_open);
481 NT_STATUS_HAVE_NO_MEMORY(io);
483 io->t2open.level = RAW_OPEN_T2OPEN;
484 io->t2open.in.flags = SVAL(trans->in.params.data, VWV(0));
485 io->t2open.in.open_mode = SVAL(trans->in.params.data, VWV(1));
486 io->t2open.in.search_attrs = SVAL(trans->in.params.data, VWV(2));
487 io->t2open.in.file_attrs = SVAL(trans->in.params.data, VWV(3));
488 io->t2open.in.write_time = srv_pull_dos_date(req->smb_conn,
489 trans->in.params.data + VWV(4));;
490 io->t2open.in.open_func = SVAL(trans->in.params.data, VWV(6));
491 io->t2open.in.size = IVAL(trans->in.params.data, VWV(7));
492 io->t2open.in.timeout = IVAL(trans->in.params.data, VWV(9));
493 io->t2open.in.num_eas = 0;
494 io->t2open.in.eas = NULL;
496 trans2_pull_blob_string(req, &trans->in.params, 28, &io->t2open.in.fname, 0);
498 status = ea_pull_list(&trans->in.data, io, &io->t2open.in.num_eas, &io->t2open.in.eas);
499 NT_STATUS_NOT_OK_RETURN(status);
502 op->send_fn = trans2_open_send;
504 return ntvfs_open(req->ntvfs, io);
511 static NTSTATUS trans2_simple_send(struct trans_op *op)
513 struct smbsrv_request *req = op->req;
514 struct smb_trans2 *trans = op->trans;
516 TRANS2_CHECK_ASYNC_STATUS_SIMPLE;
518 trans2_setup_reply(trans, 2, 0, 0);
520 SSVAL(trans->out.params.data, VWV(0), 0);
526 trans2 mkdir implementation
528 static NTSTATUS trans2_mkdir(struct smbsrv_request *req, struct trans_op *op)
530 struct smb_trans2 *trans = op->trans;
534 /* make sure we got enough parameters */
535 if (trans->in.params.length < 5) {
536 return NT_STATUS_FOOBAR;
539 io = talloc(op, union smb_mkdir);
540 NT_STATUS_HAVE_NO_MEMORY(io);
542 io->t2mkdir.level = RAW_MKDIR_T2MKDIR;
543 trans2_pull_blob_string(req, &trans->in.params, 4, &io->t2mkdir.in.path, 0);
545 status = ea_pull_list(&trans->in.data, io,
546 &io->t2mkdir.in.num_eas,
547 &io->t2mkdir.in.eas);
548 NT_STATUS_NOT_OK_RETURN(status);
551 op->send_fn = trans2_simple_send;
553 return ntvfs_mkdir(req->ntvfs, io);
557 fill in the reply from a qpathinfo or qfileinfo call
559 static NTSTATUS trans2_fileinfo_send(struct trans_op *op)
561 struct smbsrv_request *req = op->req;
562 struct smb_trans2 *trans = op->trans;
563 union smb_fileinfo *st;
567 TRANS2_CHECK_ASYNC_STATUS(st, union smb_fileinfo);
569 switch (st->generic.level) {
570 case RAW_FILEINFO_GENERIC:
571 case RAW_FILEINFO_GETATTR:
572 case RAW_FILEINFO_GETATTRE:
573 case RAW_FILEINFO_SEC_DESC:
574 /* handled elsewhere */
575 return NT_STATUS_INVALID_LEVEL;
577 case RAW_FILEINFO_BASIC_INFO:
578 case RAW_FILEINFO_BASIC_INFORMATION:
579 trans2_setup_reply(trans, 2, 40, 0);
581 SSVAL(trans->out.params.data, 0, 0);
582 push_nttime(trans->out.data.data, 0, st->basic_info.out.create_time);
583 push_nttime(trans->out.data.data, 8, st->basic_info.out.access_time);
584 push_nttime(trans->out.data.data, 16, st->basic_info.out.write_time);
585 push_nttime(trans->out.data.data, 24, st->basic_info.out.change_time);
586 SIVAL(trans->out.data.data, 32, st->basic_info.out.attrib);
587 SIVAL(trans->out.data.data, 36, 0); /* padding */
590 case RAW_FILEINFO_STANDARD:
591 trans2_setup_reply(trans, 2, 22, 0);
593 SSVAL(trans->out.params.data, 0, 0);
594 srv_push_dos_date2(req->smb_conn, trans->out.data.data, 0, st->standard.out.create_time);
595 srv_push_dos_date2(req->smb_conn, trans->out.data.data, 4, st->standard.out.access_time);
596 srv_push_dos_date2(req->smb_conn, trans->out.data.data, 8, st->standard.out.write_time);
597 SIVAL(trans->out.data.data, 12, st->standard.out.size);
598 SIVAL(trans->out.data.data, 16, st->standard.out.alloc_size);
599 SSVAL(trans->out.data.data, 20, st->standard.out.attrib);
602 case RAW_FILEINFO_EA_SIZE:
603 trans2_setup_reply(trans, 2, 26, 0);
605 SSVAL(trans->out.params.data, 0, 0);
606 srv_push_dos_date2(req->smb_conn, trans->out.data.data, 0, st->ea_size.out.create_time);
607 srv_push_dos_date2(req->smb_conn, trans->out.data.data, 4, st->ea_size.out.access_time);
608 srv_push_dos_date2(req->smb_conn, trans->out.data.data, 8, st->ea_size.out.write_time);
609 SIVAL(trans->out.data.data, 12, st->ea_size.out.size);
610 SIVAL(trans->out.data.data, 16, st->ea_size.out.alloc_size);
611 SSVAL(trans->out.data.data, 20, st->ea_size.out.attrib);
612 SIVAL(trans->out.data.data, 22, st->ea_size.out.ea_size);
615 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
616 trans2_setup_reply(trans, 2, 56, 0);
618 SSVAL(trans->out.params.data, 0, 0);
619 push_nttime(trans->out.data.data, 0, st->network_open_information.out.create_time);
620 push_nttime(trans->out.data.data, 8, st->network_open_information.out.access_time);
621 push_nttime(trans->out.data.data, 16, st->network_open_information.out.write_time);
622 push_nttime(trans->out.data.data, 24, st->network_open_information.out.change_time);
623 SBVAL(trans->out.data.data, 32, st->network_open_information.out.alloc_size);
624 SBVAL(trans->out.data.data, 40, st->network_open_information.out.size);
625 SIVAL(trans->out.data.data, 48, st->network_open_information.out.attrib);
626 SIVAL(trans->out.data.data, 52, 0); /* padding */
629 case RAW_FILEINFO_STANDARD_INFO:
630 case RAW_FILEINFO_STANDARD_INFORMATION:
631 trans2_setup_reply( trans, 2, 24, 0);
632 SSVAL(trans->out.params.data, 0, 0);
633 SBVAL(trans->out.data.data, 0, st->standard_info.out.alloc_size);
634 SBVAL(trans->out.data.data, 8, st->standard_info.out.size);
635 SIVAL(trans->out.data.data, 16, st->standard_info.out.nlink);
636 SCVAL(trans->out.data.data, 20, st->standard_info.out.delete_pending);
637 SCVAL(trans->out.data.data, 21, st->standard_info.out.directory);
638 SSVAL(trans->out.data.data, 22, 0); /* padding */
641 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
642 trans2_setup_reply(trans, 2, 8, 0);
643 SSVAL(trans->out.params.data, 0, 0);
644 SIVAL(trans->out.data.data, 0, st->attribute_tag_information.out.attrib);
645 SIVAL(trans->out.data.data, 4, st->attribute_tag_information.out.reparse_tag);
648 case RAW_FILEINFO_EA_INFO:
649 case RAW_FILEINFO_EA_INFORMATION:
650 trans2_setup_reply(trans, 2, 4, 0);
651 SSVAL(trans->out.params.data, 0, 0);
652 SIVAL(trans->out.data.data, 0, st->ea_info.out.ea_size);
655 case RAW_FILEINFO_MODE_INFORMATION:
656 trans2_setup_reply(trans, 2, 4, 0);
657 SSVAL(trans->out.params.data, 0, 0);
658 SIVAL(trans->out.data.data, 0, st->mode_information.out.mode);
661 case RAW_FILEINFO_ALIGNMENT_INFORMATION:
662 trans2_setup_reply(trans, 2, 4, 0);
663 SSVAL(trans->out.params.data, 0, 0);
664 SIVAL(trans->out.data.data, 0,
665 st->alignment_information.out.alignment_requirement);
668 case RAW_FILEINFO_EA_LIST:
669 list_size = ea_list_size(st->ea_list.out.num_eas,
670 st->ea_list.out.eas);
671 trans2_setup_reply(trans, 2, list_size, 0);
672 SSVAL(trans->out.params.data, 0, 0);
673 ea_put_list(trans->out.data.data,
674 st->ea_list.out.num_eas, st->ea_list.out.eas);
677 case RAW_FILEINFO_ALL_EAS:
678 list_size = ea_list_size(st->all_eas.out.num_eas,
679 st->all_eas.out.eas);
680 trans2_setup_reply(trans, 2, list_size, 0);
681 SSVAL(trans->out.params.data, 0, 0);
682 ea_put_list(trans->out.data.data,
683 st->all_eas.out.num_eas, st->all_eas.out.eas);
686 case RAW_FILEINFO_ACCESS_INFORMATION:
687 trans2_setup_reply(trans, 2, 4, 0);
688 SSVAL(trans->out.params.data, 0, 0);
689 SIVAL(trans->out.data.data, 0, st->access_information.out.access_flags);
692 case RAW_FILEINFO_POSITION_INFORMATION:
693 trans2_setup_reply(trans, 2, 8, 0);
694 SSVAL(trans->out.params.data, 0, 0);
695 SBVAL(trans->out.data.data, 0, st->position_information.out.position);
698 case RAW_FILEINFO_COMPRESSION_INFO:
699 case RAW_FILEINFO_COMPRESSION_INFORMATION:
700 trans2_setup_reply(trans, 2, 16, 0);
701 SSVAL(trans->out.params.data, 0, 0);
702 SBVAL(trans->out.data.data, 0, st->compression_info.out.compressed_size);
703 SSVAL(trans->out.data.data, 8, st->compression_info.out.format);
704 SCVAL(trans->out.data.data, 10, st->compression_info.out.unit_shift);
705 SCVAL(trans->out.data.data, 11, st->compression_info.out.chunk_shift);
706 SCVAL(trans->out.data.data, 12, st->compression_info.out.cluster_shift);
707 SSVAL(trans->out.data.data, 13, 0); /* 3 bytes padding */
708 SCVAL(trans->out.data.data, 15, 0);
711 case RAW_FILEINFO_IS_NAME_VALID:
712 trans2_setup_reply(trans, 2, 0, 0);
713 SSVAL(trans->out.params.data, 0, 0);
716 case RAW_FILEINFO_INTERNAL_INFORMATION:
717 trans2_setup_reply(trans, 2, 8, 0);
718 SSVAL(trans->out.params.data, 0, 0);
719 SBVAL(trans->out.data.data, 0, st->internal_information.out.file_id);
722 case RAW_FILEINFO_ALL_INFO:
723 case RAW_FILEINFO_ALL_INFORMATION:
724 trans2_setup_reply(trans, 2, 72, 0);
726 SSVAL(trans->out.params.data, 0, 0);
727 push_nttime(trans->out.data.data, 0, st->all_info.out.create_time);
728 push_nttime(trans->out.data.data, 8, st->all_info.out.access_time);
729 push_nttime(trans->out.data.data, 16, st->all_info.out.write_time);
730 push_nttime(trans->out.data.data, 24, st->all_info.out.change_time);
731 SIVAL(trans->out.data.data, 32, st->all_info.out.attrib);
732 SIVAL(trans->out.data.data, 36, 0);
733 SBVAL(trans->out.data.data, 40, st->all_info.out.alloc_size);
734 SBVAL(trans->out.data.data, 48, st->all_info.out.size);
735 SIVAL(trans->out.data.data, 56, st->all_info.out.nlink);
736 SCVAL(trans->out.data.data, 60, st->all_info.out.delete_pending);
737 SCVAL(trans->out.data.data, 61, st->all_info.out.directory);
738 SSVAL(trans->out.data.data, 62, 0); /* padding */
739 SIVAL(trans->out.data.data, 64, st->all_info.out.ea_size);
740 trans2_append_data_string(req, trans, &st->all_info.out.fname,
744 case RAW_FILEINFO_NAME_INFO:
745 case RAW_FILEINFO_NAME_INFORMATION:
746 trans2_setup_reply(trans, 2, 4, 0);
747 SSVAL(trans->out.params.data, 0, 0);
748 trans2_append_data_string(req, trans, &st->name_info.out.fname, 0, STR_UNICODE);
751 case RAW_FILEINFO_ALT_NAME_INFO:
752 case RAW_FILEINFO_ALT_NAME_INFORMATION:
753 trans2_setup_reply(trans, 2, 4, 0);
754 SSVAL(trans->out.params.data, 0, 0);
755 trans2_append_data_string(req, trans, &st->alt_name_info.out.fname, 0, STR_UNICODE);
758 case RAW_FILEINFO_STREAM_INFO:
759 case RAW_FILEINFO_STREAM_INFORMATION:
760 trans2_setup_reply(trans, 2, 0, 0);
762 SSVAL(trans->out.params.data, 0, 0);
764 for (i=0;i<st->stream_info.out.num_streams;i++) {
765 uint32_t data_size = trans->out.data.length;
768 trans2_grow_data(trans, data_size + 24);
769 data = trans->out.data.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_append_data_string(req, trans,
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(trans->out.data.data, data_size, 0);
778 trans2_grow_data_fill(trans, (trans->out.data.length+7)&~7);
779 SIVAL(trans->out.data.data, data_size,
780 trans->out.data.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 trans2 qpathinfo implementation
800 static NTSTATUS trans2_qpathinfo(struct smbsrv_request *req, struct trans_op *op)
802 struct smb_trans2 *trans = op->trans;
803 union smb_fileinfo *st;
807 /* make sure we got enough parameters */
808 if (trans->in.params.length < 2) {
809 return NT_STATUS_FOOBAR;
812 st = talloc(op, union smb_fileinfo);
813 NT_STATUS_HAVE_NO_MEMORY(st);
815 level = SVAL(trans->in.params.data, 0);
817 trans2_pull_blob_string(req, &trans->in.params, 6, &st->generic.in.file.path, 0);
818 if (st->generic.in.file.path == NULL) {
819 return NT_STATUS_FOOBAR;
822 /* work out the backend level - we make it 1-1 in the header */
823 st->generic.level = (enum smb_fileinfo_level)level;
824 if (st->generic.level >= RAW_FILEINFO_GENERIC) {
825 return NT_STATUS_INVALID_LEVEL;
828 if (st->generic.level == RAW_FILEINFO_EA_LIST) {
829 status = ea_pull_name_list(&trans->in.data, req,
830 &st->ea_list.in.num_names,
831 &st->ea_list.in.ea_names);
832 NT_STATUS_NOT_OK_RETURN(status);
836 op->send_fn = trans2_fileinfo_send;
838 return ntvfs_qpathinfo(req->ntvfs, st);
843 trans2 qpathinfo implementation
845 static NTSTATUS trans2_qfileinfo(struct smbsrv_request *req, struct trans_op *op)
847 struct smb_trans2 *trans = op->trans;
848 union smb_fileinfo *st;
851 struct ntvfs_handle *h;
853 /* make sure we got enough parameters */
854 if (trans->in.params.length < 4) {
855 return NT_STATUS_FOOBAR;
858 st = talloc(op, union smb_fileinfo);
859 NT_STATUS_HAVE_NO_MEMORY(st);
861 h = smbsrv_pull_fnum(req, trans->in.params.data, 0);
862 level = SVAL(trans->in.params.data, 2);
864 st->generic.in.file.ntvfs = h;
865 /* work out the backend level - we make it 1-1 in the header */
866 st->generic.level = (enum smb_fileinfo_level)level;
867 if (st->generic.level >= RAW_FILEINFO_GENERIC) {
868 return NT_STATUS_INVALID_LEVEL;
871 if (st->generic.level == RAW_FILEINFO_EA_LIST) {
872 status = ea_pull_name_list(&trans->in.data, req,
873 &st->ea_list.in.num_names,
874 &st->ea_list.in.ea_names);
875 NT_STATUS_NOT_OK_RETURN(status);
879 op->send_fn = trans2_fileinfo_send;
881 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st->generic.in.file.ntvfs);
882 return ntvfs_qfileinfo(req->ntvfs, st);
887 parse a trans2 setfileinfo/setpathinfo data blob
889 static NTSTATUS trans2_parse_sfileinfo(struct smbsrv_request *req,
890 union smb_setfileinfo *st,
891 const DATA_BLOB *blob)
895 switch (st->generic.level) {
896 case RAW_SFILEINFO_GENERIC:
897 case RAW_SFILEINFO_SETATTR:
898 case RAW_SFILEINFO_SETATTRE:
899 case RAW_SFILEINFO_SEC_DESC:
900 /* handled elsewhere */
901 return NT_STATUS_INVALID_LEVEL;
903 case RAW_SFILEINFO_STANDARD:
904 CHECK_MIN_BLOB_SIZE(blob, 12);
905 st->standard.in.create_time = srv_pull_dos_date2(req->smb_conn, blob->data + 0);
906 st->standard.in.access_time = srv_pull_dos_date2(req->smb_conn, blob->data + 4);
907 st->standard.in.write_time = srv_pull_dos_date2(req->smb_conn, blob->data + 8);
910 case RAW_SFILEINFO_EA_SET:
911 return ea_pull_list(blob, req,
912 &st->ea_set.in.num_eas,
915 case SMB_SFILEINFO_BASIC_INFO:
916 case SMB_SFILEINFO_BASIC_INFORMATION:
917 CHECK_MIN_BLOB_SIZE(blob, 36);
918 st->basic_info.in.create_time = pull_nttime(blob->data, 0);
919 st->basic_info.in.access_time = pull_nttime(blob->data, 8);
920 st->basic_info.in.write_time = pull_nttime(blob->data, 16);
921 st->basic_info.in.change_time = pull_nttime(blob->data, 24);
922 st->basic_info.in.attrib = IVAL(blob->data, 32);
925 case SMB_SFILEINFO_DISPOSITION_INFO:
926 case SMB_SFILEINFO_DISPOSITION_INFORMATION:
927 CHECK_MIN_BLOB_SIZE(blob, 1);
928 st->disposition_info.in.delete_on_close = CVAL(blob->data, 0);
931 case SMB_SFILEINFO_ALLOCATION_INFO:
932 case SMB_SFILEINFO_ALLOCATION_INFORMATION:
933 CHECK_MIN_BLOB_SIZE(blob, 8);
934 st->allocation_info.in.alloc_size = BVAL(blob->data, 0);
937 case RAW_SFILEINFO_END_OF_FILE_INFO:
938 case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
939 CHECK_MIN_BLOB_SIZE(blob, 8);
940 st->end_of_file_info.in.size = BVAL(blob->data, 0);
943 case RAW_SFILEINFO_RENAME_INFORMATION: {
946 CHECK_MIN_BLOB_SIZE(blob, 12);
947 st->rename_information.in.overwrite = CVAL(blob->data, 0);
948 st->rename_information.in.root_fid = IVAL(blob->data, 4);
949 len = IVAL(blob->data, 8);
950 blob2.data = blob->data+12;
951 blob2.length = MIN(blob->length, len);
952 trans2_pull_blob_string(req, &blob2, 0,
953 &st->rename_information.in.new_name, STR_UNICODE);
957 case RAW_SFILEINFO_POSITION_INFORMATION:
958 CHECK_MIN_BLOB_SIZE(blob, 8);
959 st->position_information.in.position = BVAL(blob->data, 0);
962 case RAW_SFILEINFO_MODE_INFORMATION:
963 CHECK_MIN_BLOB_SIZE(blob, 4);
964 st->mode_information.in.mode = IVAL(blob->data, 0);
967 case RAW_SFILEINFO_UNIX_BASIC:
968 case RAW_SFILEINFO_UNIX_LINK:
969 case RAW_SFILEINFO_UNIX_HLINK:
970 case RAW_SFILEINFO_1023:
971 case RAW_SFILEINFO_1025:
972 case RAW_SFILEINFO_1029:
973 case RAW_SFILEINFO_1032:
974 case RAW_SFILEINFO_1039:
975 case RAW_SFILEINFO_1040:
976 return NT_STATUS_INVALID_LEVEL;
979 return NT_STATUS_INVALID_LEVEL;
983 trans2 setfileinfo implementation
985 static NTSTATUS trans2_setfileinfo(struct smbsrv_request *req, struct trans_op *op)
987 struct smb_trans2 *trans = op->trans;
988 union smb_setfileinfo *st;
991 struct ntvfs_handle *h;
993 /* make sure we got enough parameters */
994 if (trans->in.params.length < 4) {
995 return NT_STATUS_FOOBAR;
998 st = talloc(op, union smb_setfileinfo);
999 NT_STATUS_HAVE_NO_MEMORY(st);
1001 h = smbsrv_pull_fnum(req, trans->in.params.data, 0);
1002 level = SVAL(trans->in.params.data, 2);
1004 st->generic.in.file.ntvfs = h;
1005 /* work out the backend level - we make it 1-1 in the header */
1006 st->generic.level = (enum smb_setfileinfo_level)level;
1007 if (st->generic.level >= RAW_SFILEINFO_GENERIC) {
1008 return NT_STATUS_INVALID_LEVEL;
1011 status = trans2_parse_sfileinfo(req, st, &trans->in.data);
1012 NT_STATUS_NOT_OK_RETURN(status);
1015 op->send_fn = trans2_simple_send;
1017 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st->generic.in.file.ntvfs);
1018 return ntvfs_setfileinfo(req->ntvfs, st);
1022 trans2 setpathinfo implementation
1024 static NTSTATUS trans2_setpathinfo(struct smbsrv_request *req, struct trans_op *op)
1026 struct smb_trans2 *trans = op->trans;
1027 union smb_setfileinfo *st;
1031 /* make sure we got enough parameters */
1032 if (trans->in.params.length < 4) {
1033 return NT_STATUS_FOOBAR;
1036 st = talloc(op, union smb_setfileinfo);
1037 NT_STATUS_HAVE_NO_MEMORY(st);
1039 level = SVAL(trans->in.params.data, 0);
1041 trans2_pull_blob_string(req, &trans->in.params, 6, &st->generic.in.file.path, 0);
1042 if (st->generic.in.file.path == NULL) {
1043 return NT_STATUS_FOOBAR;
1046 /* work out the backend level - we make it 1-1 in the header */
1047 st->generic.level = (enum smb_setfileinfo_level)level;
1048 if (st->generic.level >= RAW_SFILEINFO_GENERIC) {
1049 return NT_STATUS_INVALID_LEVEL;
1052 status = trans2_parse_sfileinfo(req, st, &trans->in.data);
1053 NT_STATUS_NOT_OK_RETURN(status);
1056 op->send_fn = trans2_simple_send;
1058 return ntvfs_setpathinfo(req->ntvfs, st);
1062 /* a structure to encapsulate the state information about an in-progress ffirst/fnext operation */
1064 struct trans_op *op;
1066 enum smb_search_level level;
1067 uint16_t last_entry_offset;
1072 fill a single entry in a trans2 find reply
1074 static BOOL find_fill_info(struct find_state *state,
1075 union smb_search_data *file)
1077 struct smbsrv_request *req = state->op->req;
1078 struct smb_trans2 *trans = state->op->trans;
1080 uint_t ofs = trans->out.data.length;
1083 switch (state->level) {
1084 case RAW_SEARCH_SEARCH:
1085 case RAW_SEARCH_FFIRST:
1086 case RAW_SEARCH_FUNIQUE:
1087 case RAW_SEARCH_GENERIC:
1088 case RAW_SEARCH_SMB2:
1089 /* handled elsewhere */
1092 case RAW_SEARCH_STANDARD:
1093 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
1094 trans2_grow_data(trans, ofs + 27);
1095 SIVAL(trans->out.data.data, ofs, file->standard.resume_key);
1098 trans2_grow_data(trans, ofs + 23);
1100 data = trans->out.data.data + ofs;
1101 srv_push_dos_date2(req->smb_conn, data, 0, file->standard.create_time);
1102 srv_push_dos_date2(req->smb_conn, data, 4, file->standard.access_time);
1103 srv_push_dos_date2(req->smb_conn, data, 8, file->standard.write_time);
1104 SIVAL(data, 12, file->standard.size);
1105 SIVAL(data, 16, file->standard.alloc_size);
1106 SSVAL(data, 20, file->standard.attrib);
1107 trans2_append_data_string(req, trans, &file->standard.name,
1108 ofs + 22, STR_LEN8BIT | STR_TERMINATE | STR_LEN_NOTERM);
1111 case RAW_SEARCH_EA_SIZE:
1112 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
1113 trans2_grow_data(trans, ofs + 31);
1114 SIVAL(trans->out.data.data, ofs, file->ea_size.resume_key);
1117 trans2_grow_data(trans, ofs + 27);
1119 data = trans->out.data.data + ofs;
1120 srv_push_dos_date2(req->smb_conn, data, 0, file->ea_size.create_time);
1121 srv_push_dos_date2(req->smb_conn, data, 4, file->ea_size.access_time);
1122 srv_push_dos_date2(req->smb_conn, data, 8, file->ea_size.write_time);
1123 SIVAL(data, 12, file->ea_size.size);
1124 SIVAL(data, 16, file->ea_size.alloc_size);
1125 SSVAL(data, 20, file->ea_size.attrib);
1126 SIVAL(data, 22, file->ea_size.ea_size);
1127 trans2_append_data_string(req, trans, &file->ea_size.name,
1128 ofs + 26, STR_LEN8BIT | STR_NOALIGN);
1129 trans2_grow_data(trans, trans->out.data.length + 1);
1130 trans->out.data.data[trans->out.data.length-1] = 0;
1133 case RAW_SEARCH_EA_LIST:
1134 ea_size = ea_list_size(file->ea_list.eas.num_eas, file->ea_list.eas.eas);
1135 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
1136 if (!trans2_grow_data(trans, ofs + 27 + ea_size)) {
1139 SIVAL(trans->out.data.data, ofs, file->ea_list.resume_key);
1142 if (!trans2_grow_data(trans, ofs + 23 + ea_size)) {
1146 data = trans->out.data.data + ofs;
1147 srv_push_dos_date2(req->smb_conn, data, 0, file->ea_list.create_time);
1148 srv_push_dos_date2(req->smb_conn, data, 4, file->ea_list.access_time);
1149 srv_push_dos_date2(req->smb_conn, data, 8, file->ea_list.write_time);
1150 SIVAL(data, 12, file->ea_list.size);
1151 SIVAL(data, 16, file->ea_list.alloc_size);
1152 SSVAL(data, 20, file->ea_list.attrib);
1153 ea_put_list(data+22, file->ea_list.eas.num_eas, file->ea_list.eas.eas);
1154 trans2_append_data_string(req, trans, &file->ea_list.name,
1155 ofs + 22 + ea_size, STR_LEN8BIT | STR_NOALIGN);
1156 trans2_grow_data(trans, trans->out.data.length + 1);
1157 trans->out.data.data[trans->out.data.length-1] = 0;
1160 case RAW_SEARCH_DIRECTORY_INFO:
1161 trans2_grow_data(trans, ofs + 64);
1162 data = trans->out.data.data + ofs;
1163 SIVAL(data, 4, file->directory_info.file_index);
1164 push_nttime(data, 8, file->directory_info.create_time);
1165 push_nttime(data, 16, file->directory_info.access_time);
1166 push_nttime(data, 24, file->directory_info.write_time);
1167 push_nttime(data, 32, file->directory_info.change_time);
1168 SBVAL(data, 40, file->directory_info.size);
1169 SBVAL(data, 48, file->directory_info.alloc_size);
1170 SIVAL(data, 56, file->directory_info.attrib);
1171 trans2_append_data_string(req, trans, &file->directory_info.name,
1172 ofs + 60, STR_TERMINATE_ASCII);
1173 data = trans->out.data.data + ofs;
1174 SIVAL(data, 0, trans->out.data.length - ofs);
1177 case RAW_SEARCH_FULL_DIRECTORY_INFO:
1178 trans2_grow_data(trans, ofs + 68);
1179 data = trans->out.data.data + ofs;
1180 SIVAL(data, 4, file->full_directory_info.file_index);
1181 push_nttime(data, 8, file->full_directory_info.create_time);
1182 push_nttime(data, 16, file->full_directory_info.access_time);
1183 push_nttime(data, 24, file->full_directory_info.write_time);
1184 push_nttime(data, 32, file->full_directory_info.change_time);
1185 SBVAL(data, 40, file->full_directory_info.size);
1186 SBVAL(data, 48, file->full_directory_info.alloc_size);
1187 SIVAL(data, 56, file->full_directory_info.attrib);
1188 SIVAL(data, 64, file->full_directory_info.ea_size);
1189 trans2_append_data_string(req, trans, &file->full_directory_info.name,
1190 ofs + 60, STR_TERMINATE_ASCII);
1191 data = trans->out.data.data + ofs;
1192 SIVAL(data, 0, trans->out.data.length - ofs);
1195 case RAW_SEARCH_NAME_INFO:
1196 trans2_grow_data(trans, ofs + 12);
1197 data = trans->out.data.data + ofs;
1198 SIVAL(data, 4, file->name_info.file_index);
1199 trans2_append_data_string(req, trans, &file->name_info.name,
1200 ofs + 8, STR_TERMINATE_ASCII);
1201 data = trans->out.data.data + ofs;
1202 SIVAL(data, 0, trans->out.data.length - ofs);
1205 case RAW_SEARCH_BOTH_DIRECTORY_INFO:
1206 trans2_grow_data(trans, ofs + 94);
1207 data = trans->out.data.data + ofs;
1208 SIVAL(data, 4, file->both_directory_info.file_index);
1209 push_nttime(data, 8, file->both_directory_info.create_time);
1210 push_nttime(data, 16, file->both_directory_info.access_time);
1211 push_nttime(data, 24, file->both_directory_info.write_time);
1212 push_nttime(data, 32, file->both_directory_info.change_time);
1213 SBVAL(data, 40, file->both_directory_info.size);
1214 SBVAL(data, 48, file->both_directory_info.alloc_size);
1215 SIVAL(data, 56, file->both_directory_info.attrib);
1216 SIVAL(data, 64, file->both_directory_info.ea_size);
1217 SCVAL(data, 69, 0); /* reserved */
1218 memset(data+70,0,24);
1219 trans2_push_data_string(req, trans,
1221 &file->both_directory_info.short_name,
1222 24, STR_UNICODE | STR_LEN8BIT);
1223 trans2_append_data_string(req, trans, &file->both_directory_info.name,
1224 ofs + 60, STR_TERMINATE_ASCII);
1225 trans2_align_data(req, trans);
1226 data = trans->out.data.data + ofs;
1227 SIVAL(data, 0, trans->out.data.length - ofs);
1230 case RAW_SEARCH_ID_FULL_DIRECTORY_INFO:
1231 trans2_grow_data(trans, ofs + 80);
1232 data = trans->out.data.data + ofs;
1233 SIVAL(data, 4, file->id_full_directory_info.file_index);
1234 push_nttime(data, 8, file->id_full_directory_info.create_time);
1235 push_nttime(data, 16, file->id_full_directory_info.access_time);
1236 push_nttime(data, 24, file->id_full_directory_info.write_time);
1237 push_nttime(data, 32, file->id_full_directory_info.change_time);
1238 SBVAL(data, 40, file->id_full_directory_info.size);
1239 SBVAL(data, 48, file->id_full_directory_info.alloc_size);
1240 SIVAL(data, 56, file->id_full_directory_info.attrib);
1241 SIVAL(data, 64, file->id_full_directory_info.ea_size);
1242 SIVAL(data, 68, 0); /* padding */
1243 SBVAL(data, 72, file->id_full_directory_info.file_id);
1244 trans2_append_data_string(req, trans, &file->id_full_directory_info.name,
1245 ofs + 60, STR_TERMINATE_ASCII);
1246 data = trans->out.data.data + ofs;
1247 SIVAL(data, 0, trans->out.data.length - ofs);
1250 case RAW_SEARCH_ID_BOTH_DIRECTORY_INFO:
1251 trans2_grow_data(trans, ofs + 104);
1252 data = trans->out.data.data + ofs;
1253 SIVAL(data, 4, file->id_both_directory_info.file_index);
1254 push_nttime(data, 8, file->id_both_directory_info.create_time);
1255 push_nttime(data, 16, file->id_both_directory_info.access_time);
1256 push_nttime(data, 24, file->id_both_directory_info.write_time);
1257 push_nttime(data, 32, file->id_both_directory_info.change_time);
1258 SBVAL(data, 40, file->id_both_directory_info.size);
1259 SBVAL(data, 48, file->id_both_directory_info.alloc_size);
1260 SIVAL(data, 56, file->id_both_directory_info.attrib);
1261 SIVAL(data, 64, file->id_both_directory_info.ea_size);
1262 SCVAL(data, 69, 0); /* reserved */
1263 memset(data+70,0,26);
1264 trans2_push_data_string(req, trans,
1266 &file->id_both_directory_info.short_name,
1267 24, STR_UNICODE | STR_LEN8BIT);
1268 SBVAL(data, 96, file->id_both_directory_info.file_id);
1269 trans2_append_data_string(req, trans, &file->id_both_directory_info.name,
1270 ofs + 60, STR_TERMINATE_ASCII);
1271 data = trans->out.data.data + ofs;
1272 SIVAL(data, 0, trans->out.data.length - ofs);
1279 /* callback function for trans2 findfirst/findnext */
1280 static BOOL find_callback(void *private, union smb_search_data *file)
1282 struct find_state *state = talloc_get_type(private, struct find_state);
1283 struct smb_trans2 *trans = state->op->trans;
1286 old_length = trans->out.data.length;
1288 if (!find_fill_info(state, file) ||
1289 trans->out.data.length > trans->in.max_data) {
1290 /* restore the old length and tell the backend to stop */
1291 trans2_grow_data(trans, old_length);
1295 state->last_entry_offset = old_length;
1300 trans2 findfirst send
1302 static NTSTATUS trans2_findfirst_send(struct trans_op *op)
1304 struct smbsrv_request *req = op->req;
1305 struct smb_trans2 *trans = op->trans;
1306 union smb_search_first *search;
1307 struct find_state *state;
1310 TRANS2_CHECK_ASYNC_STATUS(state, struct find_state);
1311 search = talloc_get_type(state->search, union smb_search_first);
1313 /* fill in the findfirst reply header */
1314 param = trans->out.params.data;
1315 SSVAL(param, VWV(0), search->t2ffirst.out.handle);
1316 SSVAL(param, VWV(1), search->t2ffirst.out.count);
1317 SSVAL(param, VWV(2), search->t2ffirst.out.end_of_search);
1318 SSVAL(param, VWV(3), 0);
1319 SSVAL(param, VWV(4), state->last_entry_offset);
1321 return NT_STATUS_OK;
1326 trans2 findfirst implementation
1328 static NTSTATUS trans2_findfirst(struct smbsrv_request *req, struct trans_op *op)
1330 struct smb_trans2 *trans = op->trans;
1331 union smb_search_first *search;
1334 struct find_state *state;
1336 /* make sure we got all the parameters */
1337 if (trans->in.params.length < 14) {
1338 return NT_STATUS_FOOBAR;
1341 search = talloc(op, union smb_search_first);
1342 NT_STATUS_HAVE_NO_MEMORY(search);
1344 search->t2ffirst.in.search_attrib = SVAL(trans->in.params.data, 0);
1345 search->t2ffirst.in.max_count = SVAL(trans->in.params.data, 2);
1346 search->t2ffirst.in.flags = SVAL(trans->in.params.data, 4);
1347 level = SVAL(trans->in.params.data, 6);
1348 search->t2ffirst.in.storage_type = IVAL(trans->in.params.data, 8);
1350 trans2_pull_blob_string(req, &trans->in.params, 12, &search->t2ffirst.in.pattern, 0);
1351 if (search->t2ffirst.in.pattern == NULL) {
1352 return NT_STATUS_FOOBAR;
1355 search->t2ffirst.level = (enum smb_search_level)level;
1356 if (search->t2ffirst.level >= RAW_SEARCH_GENERIC) {
1357 return NT_STATUS_INVALID_LEVEL;
1360 if (search->t2ffirst.level == RAW_SEARCH_EA_LIST) {
1361 status = ea_pull_name_list(&trans->in.data, req,
1362 &search->t2ffirst.in.num_names,
1363 &search->t2ffirst.in.ea_names);
1364 NT_STATUS_NOT_OK_RETURN(status);
1367 /* setup the private state structure that the backend will
1368 give us in the callback */
1369 state = talloc(op, struct find_state);
1370 NT_STATUS_HAVE_NO_MEMORY(state);
1372 state->search = search;
1373 state->level = search->t2ffirst.level;
1374 state->last_entry_offset= 0;
1375 state->flags = search->t2ffirst.in.flags;
1377 /* setup for just a header in the reply */
1378 trans2_setup_reply(trans, 10, 0, 0);
1380 op->op_info = state;
1381 op->send_fn = trans2_findfirst_send;
1383 return ntvfs_search_first(req->ntvfs, search, state, find_callback);
1388 trans2 findnext send
1390 static NTSTATUS trans2_findnext_send(struct trans_op *op)
1392 struct smbsrv_request *req = op->req;
1393 struct smb_trans2 *trans = op->trans;
1394 union smb_search_next *search;
1395 struct find_state *state;
1398 TRANS2_CHECK_ASYNC_STATUS(state, struct find_state);
1399 search = talloc_get_type(state->search, union smb_search_next);
1401 /* fill in the findfirst reply header */
1402 param = trans->out.params.data;
1403 SSVAL(param, VWV(0), search->t2fnext.out.count);
1404 SSVAL(param, VWV(1), search->t2fnext.out.end_of_search);
1405 SSVAL(param, VWV(2), 0);
1406 SSVAL(param, VWV(3), state->last_entry_offset);
1408 return NT_STATUS_OK;
1413 trans2 findnext implementation
1415 static NTSTATUS trans2_findnext(struct smbsrv_request *req, struct trans_op *op)
1417 struct smb_trans2 *trans = op->trans;
1418 union smb_search_next *search;
1421 struct find_state *state;
1423 /* make sure we got all the parameters */
1424 if (trans->in.params.length < 12) {
1425 return NT_STATUS_FOOBAR;
1428 search = talloc(op, union smb_search_next);
1429 NT_STATUS_HAVE_NO_MEMORY(search);
1431 search->t2fnext.in.handle = SVAL(trans->in.params.data, 0);
1432 search->t2fnext.in.max_count = SVAL(trans->in.params.data, 2);
1433 level = SVAL(trans->in.params.data, 4);
1434 search->t2fnext.in.resume_key = IVAL(trans->in.params.data, 6);
1435 search->t2fnext.in.flags = SVAL(trans->in.params.data, 10);
1437 trans2_pull_blob_string(req, &trans->in.params, 12, &search->t2fnext.in.last_name, 0);
1438 if (search->t2fnext.in.last_name == NULL) {
1439 return NT_STATUS_FOOBAR;
1442 search->t2fnext.level = (enum smb_search_level)level;
1443 if (search->t2fnext.level >= RAW_SEARCH_GENERIC) {
1444 return NT_STATUS_INVALID_LEVEL;
1447 if (search->t2fnext.level == RAW_SEARCH_EA_LIST) {
1448 status = ea_pull_name_list(&trans->in.data, req,
1449 &search->t2fnext.in.num_names,
1450 &search->t2fnext.in.ea_names);
1451 NT_STATUS_NOT_OK_RETURN(status);
1454 /* setup the private state structure that the backend will give us in the callback */
1455 state = talloc(op, struct find_state);
1456 NT_STATUS_HAVE_NO_MEMORY(state);
1458 state->search = search;
1459 state->level = search->t2fnext.level;
1460 state->last_entry_offset= 0;
1461 state->flags = search->t2fnext.in.flags;
1463 /* setup for just a header in the reply */
1464 trans2_setup_reply(trans, 8, 0, 0);
1466 op->op_info = state;
1467 op->send_fn = trans2_findnext_send;
1469 return ntvfs_search_next(req->ntvfs, search, state, find_callback);
1474 backend for trans2 requests
1476 static NTSTATUS trans2_backend(struct smbsrv_request *req, struct trans_op *op)
1478 struct smb_trans2 *trans = op->trans;
1481 /* direct trans2 pass thru */
1482 status = ntvfs_trans2(req->ntvfs, trans);
1483 if (!NT_STATUS_EQUAL(NT_STATUS_NOT_IMPLEMENTED, status)) {
1487 /* must have at least one setup word */
1488 if (trans->in.setup_count < 1) {
1489 return NT_STATUS_FOOBAR;
1492 /* the trans2 command is in setup[0] */
1493 switch (trans->in.setup[0]) {
1494 case TRANSACT2_FINDFIRST:
1495 return trans2_findfirst(req, op);
1496 case TRANSACT2_FINDNEXT:
1497 return trans2_findnext(req, op);
1498 case TRANSACT2_QPATHINFO:
1499 return trans2_qpathinfo(req, op);
1500 case TRANSACT2_QFILEINFO:
1501 return trans2_qfileinfo(req, op);
1502 case TRANSACT2_SETFILEINFO:
1503 return trans2_setfileinfo(req, op);
1504 case TRANSACT2_SETPATHINFO:
1505 return trans2_setpathinfo(req, op);
1506 case TRANSACT2_QFSINFO:
1507 return trans2_qfsinfo(req, op);
1508 case TRANSACT2_OPEN:
1509 return trans2_open(req, op);
1510 case TRANSACT2_MKDIR:
1511 return trans2_mkdir(req, op);
1514 /* an unknown trans2 command */
1515 return NT_STATUS_FOOBAR;
1520 send a continue request
1522 static void reply_trans_continue(struct smbsrv_request *req, uint8_t command,
1523 struct smb_trans2 *trans)
1525 struct smbsrv_trans_partial *tp;
1528 /* make sure they don't flood us */
1529 for (count=0,tp=req->smb_conn->trans_partial;tp;tp=tp->next) count++;
1531 smbsrv_send_error(req, NT_STATUS_INSUFFICIENT_RESOURCES);
1535 tp = talloc(req, struct smbsrv_trans_partial);
1537 tp->req = talloc_reference(tp, req);
1539 tp->command = command;
1541 DLIST_ADD(req->smb_conn->trans_partial, tp);
1543 /* send a 'please continue' reply */
1544 smbsrv_setup_reply(req, 0, 0);
1545 smbsrv_send_reply(req);
1550 answer a reconstructed trans request
1552 static void reply_trans_send(struct ntvfs_request *ntvfs)
1554 struct smbsrv_request *req;
1555 struct trans_op *op;
1556 struct smb_trans2 *trans;
1557 uint16_t params_left, data_left;
1558 uint8_t *params, *data;
1561 SMBSRV_CHECK_ASYNC_STATUS_ERR(op, struct trans_op);
1564 /* if this function needs work to form the nttrans reply buffer, then
1566 if (op->send_fn != NULL) {
1568 status = op->send_fn(op);
1569 if (!NT_STATUS_IS_OK(status)) {
1570 smbsrv_send_error(req, status);
1575 params_left = trans->out.params.length;
1576 data_left = trans->out.data.length;
1577 params = trans->out.params.data;
1578 data = trans->out.data.data;
1580 smbsrv_setup_reply(req, 10 + trans->out.setup_count, 0);
1582 if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) {
1583 smbsrv_setup_error(req, req->ntvfs->async_states->status);
1586 /* we need to divide up the reply into chunks that fit into
1587 the negotiated buffer size */
1589 uint16_t this_data, this_param, max_bytes;
1590 uint_t align1 = 1, align2 = (params_left ? 2 : 0);
1591 struct smbsrv_request *this_req;
1593 max_bytes = req_max_data(req) - (align1 + align2);
1595 this_param = params_left;
1596 if (this_param > max_bytes) {
1597 this_param = max_bytes;
1599 max_bytes -= this_param;
1601 this_data = data_left;
1602 if (this_data > max_bytes) {
1603 this_data = max_bytes;
1606 /* don't destroy unless this is the last chunk */
1607 if (params_left - this_param != 0 ||
1608 data_left - this_data != 0) {
1609 this_req = smbsrv_setup_secondary_request(req);
1614 req_grow_data(this_req, this_param + this_data + (align1 + align2));
1616 SSVAL(this_req->out.vwv, VWV(0), trans->out.params.length);
1617 SSVAL(this_req->out.vwv, VWV(1), trans->out.data.length);
1618 SSVAL(this_req->out.vwv, VWV(2), 0);
1620 SSVAL(this_req->out.vwv, VWV(3), this_param);
1621 SSVAL(this_req->out.vwv, VWV(4), align1 + PTR_DIFF(this_req->out.data, this_req->out.hdr));
1622 SSVAL(this_req->out.vwv, VWV(5), PTR_DIFF(params, trans->out.params.data));
1624 SSVAL(this_req->out.vwv, VWV(6), this_data);
1625 SSVAL(this_req->out.vwv, VWV(7), align1 + align2 +
1626 PTR_DIFF(this_req->out.data + this_param, this_req->out.hdr));
1627 SSVAL(this_req->out.vwv, VWV(8), PTR_DIFF(data, trans->out.data.data));
1629 SSVAL(this_req->out.vwv, VWV(9), trans->out.setup_count);
1630 for (i=0;i<trans->out.setup_count;i++) {
1631 SSVAL(this_req->out.vwv, VWV(10+i), trans->out.setup[i]);
1634 memset(this_req->out.data, 0, align1);
1635 if (this_param != 0) {
1636 memcpy(this_req->out.data + align1, params, this_param);
1638 memset(this_req->out.data+this_param+align1, 0, align2);
1639 if (this_data != 0) {
1640 memcpy(this_req->out.data+this_param+align1+align2, data, this_data);
1643 params_left -= this_param;
1644 data_left -= this_data;
1645 params += this_param;
1648 smbsrv_send_reply(this_req);
1649 } while (params_left != 0 || data_left != 0);
1654 answer a reconstructed trans request
1656 static void reply_trans_complete(struct smbsrv_request *req, uint8_t command,
1657 struct smb_trans2 *trans)
1659 struct trans_op *op;
1661 SMBSRV_TALLOC_IO_PTR(op, struct trans_op);
1662 SMBSRV_SETUP_NTVFS_REQUEST(reply_trans_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1666 op->command = command;
1670 /* its a full request, give it to the backend */
1671 if (command == SMBtrans) {
1672 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_trans(req->ntvfs, trans));
1675 SMBSRV_CALL_NTVFS_BACKEND(trans2_backend(req, op));
1681 Reply to an SMBtrans or SMBtrans2 request
1683 static void reply_trans_generic(struct smbsrv_request *req, uint8_t command)
1685 struct smb_trans2 *trans;
1687 uint16_t param_ofs, data_ofs;
1688 uint16_t param_count, data_count;
1689 uint16_t param_total, data_total;
1692 if (req->in.wct < 14) {
1693 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1697 trans = talloc(req, struct smb_trans2);
1698 if (trans == NULL) {
1699 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
1703 param_total = SVAL(req->in.vwv, VWV(0));
1704 data_total = SVAL(req->in.vwv, VWV(1));
1705 trans->in.max_param = SVAL(req->in.vwv, VWV(2));
1706 trans->in.max_data = SVAL(req->in.vwv, VWV(3));
1707 trans->in.max_setup = CVAL(req->in.vwv, VWV(4));
1708 trans->in.flags = SVAL(req->in.vwv, VWV(5));
1709 trans->in.timeout = IVAL(req->in.vwv, VWV(6));
1710 param_count = SVAL(req->in.vwv, VWV(9));
1711 param_ofs = SVAL(req->in.vwv, VWV(10));
1712 data_count = SVAL(req->in.vwv, VWV(11));
1713 data_ofs = SVAL(req->in.vwv, VWV(12));
1714 trans->in.setup_count = CVAL(req->in.vwv, VWV(13));
1716 if (req->in.wct != 14 + trans->in.setup_count) {
1717 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
1721 /* parse out the setup words */
1722 trans->in.setup = talloc_array(trans, uint16_t, trans->in.setup_count);
1723 if (trans->in.setup_count && !trans->in.setup) {
1724 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
1727 for (i=0;i<trans->in.setup_count;i++) {
1728 trans->in.setup[i] = SVAL(req->in.vwv, VWV(14+i));
1731 if (command == SMBtrans) {
1732 req_pull_string(req, &trans->in.trans_name, req->in.data, -1, STR_TERMINATE);
1735 if (!req_pull_blob(req, req->in.hdr + param_ofs, param_count, &trans->in.params) ||
1736 !req_pull_blob(req, req->in.hdr + data_ofs, data_count, &trans->in.data)) {
1737 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1741 /* is it a partial request? if so, then send a 'send more' message */
1742 if (param_total > param_count || data_total > data_count) {
1743 reply_trans_continue(req, command, trans);
1747 reply_trans_complete(req, command, trans);
1752 Reply to an SMBtranss2 request
1754 static void reply_transs_generic(struct smbsrv_request *req, uint8_t command)
1756 struct smbsrv_trans_partial *tp;
1757 struct smb_trans2 *trans = NULL;
1758 uint16_t param_ofs, data_ofs;
1759 uint16_t param_count, data_count;
1760 uint16_t param_disp, data_disp;
1761 uint16_t param_total, data_total;
1762 DATA_BLOB params, data;
1765 if (req->in.wct < 8) {
1766 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1770 for (tp=req->smb_conn->trans_partial;tp;tp=tp->next) {
1771 if (tp->command == command &&
1772 SVAL(tp->req->in.hdr, HDR_MID) == SVAL(req->in.hdr, HDR_MID)) {
1773 /* TODO: check the VUID, PID and TID too? */
1779 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1785 param_total = SVAL(req->in.vwv, VWV(0));
1786 data_total = SVAL(req->in.vwv, VWV(1));
1787 param_count = SVAL(req->in.vwv, VWV(2));
1788 param_ofs = SVAL(req->in.vwv, VWV(3));
1789 param_disp = SVAL(req->in.vwv, VWV(4));
1790 data_count = SVAL(req->in.vwv, VWV(5));
1791 data_ofs = SVAL(req->in.vwv, VWV(6));
1792 data_disp = SVAL(req->in.vwv, VWV(7));
1794 if (!req_pull_blob(req, req->in.hdr + param_ofs, param_count, ¶ms) ||
1795 !req_pull_blob(req, req->in.hdr + data_ofs, data_count, &data)) {
1796 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1800 /* only allow contiguous requests */
1801 if ((param_count != 0 &&
1802 param_disp != trans->in.params.length) ||
1804 data_disp != trans->in.data.length)) {
1805 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1809 /* add to the existing request */
1810 if (param_count != 0) {
1811 trans->in.params.data = talloc_realloc(trans,
1812 trans->in.params.data,
1814 param_disp + param_count);
1815 if (trans->in.params.data == NULL) {
1818 trans->in.params.length = param_disp + param_count;
1821 if (data_count != 0) {
1822 trans->in.data.data = talloc_realloc(trans,
1823 trans->in.data.data,
1825 data_disp + data_count);
1826 if (trans->in.data.data == NULL) {
1829 trans->in.data.length = data_disp + data_count;
1832 memcpy(trans->in.params.data + param_disp, params.data, params.length);
1833 memcpy(trans->in.data.data + data_disp, data.data, data.length);
1835 /* the sequence number of the reply is taken from the last secondary
1837 tp->req->seq_num = req->seq_num;
1839 /* we don't reply to Transs2 requests */
1842 if (trans->in.params.length == param_total &&
1843 trans->in.data.length == data_total) {
1844 /* its now complete */
1845 DLIST_REMOVE(tp->req->smb_conn->trans_partial, tp);
1846 reply_trans_complete(tp->req, command, trans);
1851 smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
1852 DLIST_REMOVE(req->smb_conn->trans_partial, tp);
1859 Reply to an SMBtrans2
1861 void smbsrv_reply_trans2(struct smbsrv_request *req)
1863 reply_trans_generic(req, SMBtrans2);
1867 Reply to an SMBtrans
1869 void smbsrv_reply_trans(struct smbsrv_request *req)
1871 reply_trans_generic(req, SMBtrans);
1875 Reply to an SMBtranss request
1877 void smbsrv_reply_transs(struct smbsrv_request *req)
1879 reply_transs_generic(req, SMBtrans);
1883 Reply to an SMBtranss2 request
1885 void smbsrv_reply_transs2(struct smbsrv_request *req)
1887 reply_transs_generic(req, SMBtrans2);