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
27 #define CHECK_MIN_BLOB_SIZE(blob, size) do { \
28 if ((blob)->length < (size)) { \
29 return NT_STATUS_INFO_LENGTH_MISMATCH; \
32 /* grow the data allocation size of a trans2 reply - this guarantees
33 that requests to grow the data size later will not change the
35 static void trans2_grow_data_allocation(struct smbsrv_request
*req
,
36 struct smb_trans2
*trans
,
39 if (new_size
<= trans
->out
.data
.length
) {
42 trans
->out
.data
.data
= talloc_realloc(req
, trans
->out
.data
.data
, new_size
);
46 /* grow the data size of a trans2 reply */
47 static void trans2_grow_data(struct smbsrv_request
*req
,
48 struct smb_trans2
*trans
,
51 trans2_grow_data_allocation(req
, trans
, new_size
);
52 trans
->out
.data
.length
= new_size
;
55 /* grow the data, zero filling any new bytes */
56 static void trans2_grow_data_fill(struct smbsrv_request
*req
,
57 struct smb_trans2
*trans
,
60 uint16_t old_size
= trans
->out
.data
.length
;
61 trans2_grow_data(req
, trans
, new_size
);
62 if (new_size
> old_size
) {
63 memset(trans
->out
.data
.data
+ old_size
, 0, new_size
- old_size
);
68 /* setup a trans2 reply, given the data and params sizes */
69 static void trans2_setup_reply(struct smbsrv_request
*req
,
70 struct smb_trans2
*trans
,
71 uint16_t param_size
, uint16_t data_size
,
74 trans
->out
.setup_count
= setup_count
;
75 if (setup_count
!= 0) {
76 trans
->out
.setup
= talloc_zero(req
, sizeof(uint16_t) * setup_count
);
78 trans
->out
.params
= data_blob_talloc(req
, NULL
, param_size
);
79 trans
->out
.data
= data_blob_talloc(req
, NULL
, data_size
);
84 pull a string from a blob in a trans2 request
86 static size_t trans2_pull_blob_string(struct smbsrv_request
*req
,
87 const DATA_BLOB
*blob
,
92 /* we use STR_NO_RANGE_CHECK because the params are allocated
93 separately in a DATA_BLOB, so we need to do our own range
95 if (offset
>= blob
->length
) {
100 return req_pull_string(req
, str
,
102 blob
->length
- offset
,
103 STR_NO_RANGE_CHECK
| flags
);
107 push a string into the data section of a trans2 request
108 return the number of bytes consumed in the output
110 static size_t trans2_push_data_string(struct smbsrv_request
*req
,
111 struct smb_trans2
*trans
,
114 const WIRE_STRING
*str
,
118 int alignment
= 0, ret
= 0, pkt_len
;
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 (!str
->s
|| offset
>= trans
->out
.data
.length
) {
124 if (flags
& STR_LEN8BIT
) {
125 SCVAL(trans
->out
.data
.data
, len_offset
, 0);
127 SIVAL(trans
->out
.data
.data
, len_offset
, 0);
132 flags
|= STR_NO_RANGE_CHECK
;
134 if (dest_len
== -1 || (dest_len
> trans
->out
.data
.length
- offset
)) {
135 dest_len
= trans
->out
.data
.length
- offset
;
138 if (!(flags
& (STR_ASCII
|STR_UNICODE
))) {
139 flags
|= (req
->flags2
& FLAGS2_UNICODE_STRINGS
) ? STR_UNICODE
: STR_ASCII
;
142 if ((offset
&1) && (flags
& STR_UNICODE
) && !(flags
& STR_NOALIGN
)) {
145 SCVAL(trans
->out
.data
.data
+ offset
, 0, 0);
146 ret
= push_string(trans
->out
.data
.data
+ offset
+ 1, str
->s
, dest_len
-1, flags
);
149 ret
= push_string(trans
->out
.data
.data
+ offset
, str
->s
, dest_len
, flags
);
152 /* sometimes the string needs to be terminated, but the length
153 on the wire must not include the termination! */
156 if ((flags
& STR_LEN_NOTERM
) && (flags
& STR_TERMINATE
)) {
157 if ((flags
& STR_UNICODE
) && ret
>= 2) {
160 if ((flags
& STR_ASCII
) && ret
>= 1) {
165 if (flags
& STR_LEN8BIT
) {
166 SCVAL(trans
->out
.data
.data
, len_offset
, pkt_len
);
168 SIVAL(trans
->out
.data
.data
, len_offset
, pkt_len
);
171 return ret
+ alignment
;
175 append a string to the data section of a trans2 reply
176 len_offset points to the place in the packet where the length field
179 static void trans2_append_data_string(struct smbsrv_request
*req
,
180 struct smb_trans2
*trans
,
181 const WIRE_STRING
*str
,
187 const int max_bytes_per_char
= 3;
189 offset
= trans
->out
.data
.length
;
190 trans2_grow_data(req
, trans
, offset
+ (2+strlen_m(str
->s
))*max_bytes_per_char
);
191 ret
= trans2_push_data_string(req
, trans
, len_offset
, offset
, str
, -1, flags
);
192 trans2_grow_data(req
, trans
, offset
+ ret
);
197 trans2 qfsinfo implementation
199 static NTSTATUS
trans2_qfsinfo(struct smbsrv_request
*req
, struct smb_trans2
*trans
)
201 union smb_fsinfo fsinfo
;
207 /* make sure we got enough parameters */
208 if (trans
->in
.params
.length
!= 2) {
209 return NT_STATUS_FOOBAR
;
212 level
= SVAL(trans
->in
.params
.data
, 0);
215 case SMB_QFS_ALLOCATION
:
216 fsinfo
.allocation
.level
= RAW_QFS_ALLOCATION
;
218 status
= req
->tcon
->ntvfs_ops
->fsinfo(req
, &fsinfo
);
219 if (!NT_STATUS_IS_OK(status
)) {
223 trans2_setup_reply(req
, trans
, 0, 18, 0);
225 SIVAL(trans
->out
.data
.data
, 0, fsinfo
.allocation
.out
.fs_id
);
226 SIVAL(trans
->out
.data
.data
, 4, fsinfo
.allocation
.out
.sectors_per_unit
);
227 SIVAL(trans
->out
.data
.data
, 8, fsinfo
.allocation
.out
.total_alloc_units
);
228 SIVAL(trans
->out
.data
.data
, 12, fsinfo
.allocation
.out
.avail_alloc_units
);
229 SSVAL(trans
->out
.data
.data
, 16, fsinfo
.allocation
.out
.bytes_per_sector
);
234 fsinfo
.volume
.level
= RAW_QFS_VOLUME
;
236 status
= req
->tcon
->ntvfs_ops
->fsinfo(req
, &fsinfo
);
237 if (!NT_STATUS_IS_OK(status
)) {
241 trans2_setup_reply(req
, trans
, 0, 5, 0);
243 SIVAL(trans
->out
.data
.data
, 0, fsinfo
.volume
.out
.serial_number
);
244 /* w2k3 implements this incorrectly for unicode - it
245 * leaves the last byte off the string */
246 trans2_append_data_string(req
, trans
,
247 &fsinfo
.volume
.out
.volume_name
,
248 4, STR_LEN8BIT
|STR_NOALIGN
);
252 case SMB_QFS_VOLUME_INFO
:
253 case SMB_QFS_VOLUME_INFORMATION
:
254 fsinfo
.volume_info
.level
= RAW_QFS_VOLUME_INFO
;
256 status
= req
->tcon
->ntvfs_ops
->fsinfo(req
, &fsinfo
);
257 if (!NT_STATUS_IS_OK(status
)) {
261 trans2_setup_reply(req
, trans
, 0, 18, 0);
263 push_nttime(trans
->out
.data
.data
, 0, fsinfo
.volume_info
.out
.create_time
);
264 SIVAL(trans
->out
.data
.data
, 8, fsinfo
.volume_info
.out
.serial_number
);
265 SSVAL(trans
->out
.data
.data
, 16, 0); /* padding */
266 trans2_append_data_string(req
, trans
,
267 &fsinfo
.volume_info
.out
.volume_name
,
272 case SMB_QFS_SIZE_INFO
:
273 case SMB_QFS_SIZE_INFORMATION
:
274 fsinfo
.size_info
.level
= RAW_QFS_SIZE_INFO
;
276 status
= req
->tcon
->ntvfs_ops
->fsinfo(req
, &fsinfo
);
277 if (!NT_STATUS_IS_OK(status
)) {
281 trans2_setup_reply(req
, trans
, 0, 24, 0);
283 SBVAL(trans
->out
.data
.data
, 0, fsinfo
.size_info
.out
.total_alloc_units
);
284 SBVAL(trans
->out
.data
.data
, 8, fsinfo
.size_info
.out
.avail_alloc_units
);
285 SIVAL(trans
->out
.data
.data
, 16, fsinfo
.size_info
.out
.sectors_per_unit
);
286 SIVAL(trans
->out
.data
.data
, 20, fsinfo
.size_info
.out
.bytes_per_sector
);
290 case SMB_QFS_DEVICE_INFO
:
291 case SMB_QFS_DEVICE_INFORMATION
:
292 fsinfo
.device_info
.level
= RAW_QFS_DEVICE_INFO
;
294 status
= req
->tcon
->ntvfs_ops
->fsinfo(req
, &fsinfo
);
295 if (!NT_STATUS_IS_OK(status
)) {
298 trans2_setup_reply(req
, trans
, 0, 8, 0);
299 SIVAL(trans
->out
.data
.data
, 0, fsinfo
.device_info
.out
.device_type
);
300 SIVAL(trans
->out
.data
.data
, 4, fsinfo
.device_info
.out
.characteristics
);
304 case SMB_QFS_ATTRIBUTE_INFO
:
305 case SMB_QFS_ATTRIBUTE_INFORMATION
:
306 fsinfo
.attribute_info
.level
= RAW_QFS_ATTRIBUTE_INFO
;
308 status
= req
->tcon
->ntvfs_ops
->fsinfo(req
, &fsinfo
);
309 if (!NT_STATUS_IS_OK(status
)) {
313 trans2_setup_reply(req
, trans
, 0, 12, 0);
315 SIVAL(trans
->out
.data
.data
, 0, fsinfo
.attribute_info
.out
.fs_attr
);
316 SIVAL(trans
->out
.data
.data
, 4, fsinfo
.attribute_info
.out
.max_file_component_length
);
317 /* this must not be null terminated or win98 gets
318 confused! also note that w2k3 returns this as
319 unicode even when ascii is negotiated */
320 trans2_append_data_string(req
, trans
,
321 &fsinfo
.attribute_info
.out
.fs_type
,
326 case SMB_QFS_QUOTA_INFORMATION
:
327 fsinfo
.quota_information
.level
= RAW_QFS_QUOTA_INFORMATION
;
329 status
= req
->tcon
->ntvfs_ops
->fsinfo(req
, &fsinfo
);
330 if (!NT_STATUS_IS_OK(status
)) {
334 trans2_setup_reply(req
, trans
, 0, 48, 0);
336 SBVAL(trans
->out
.data
.data
, 0, fsinfo
.quota_information
.out
.unknown
[0]);
337 SBVAL(trans
->out
.data
.data
, 8, fsinfo
.quota_information
.out
.unknown
[1]);
338 SBVAL(trans
->out
.data
.data
, 16, fsinfo
.quota_information
.out
.unknown
[2]);
339 SBVAL(trans
->out
.data
.data
, 24, fsinfo
.quota_information
.out
.quota_soft
);
340 SBVAL(trans
->out
.data
.data
, 32, fsinfo
.quota_information
.out
.quota_hard
);
341 SBVAL(trans
->out
.data
.data
, 40, fsinfo
.quota_information
.out
.quota_flags
);
346 case SMB_QFS_FULL_SIZE_INFORMATION
:
347 fsinfo
.full_size_information
.level
= RAW_QFS_FULL_SIZE_INFORMATION
;
349 status
= req
->tcon
->ntvfs_ops
->fsinfo(req
, &fsinfo
);
350 if (!NT_STATUS_IS_OK(status
)) {
354 trans2_setup_reply(req
, trans
, 0, 32, 0);
356 SBVAL(trans
->out
.data
.data
, 0, fsinfo
.full_size_information
.out
.total_alloc_units
);
357 SBVAL(trans
->out
.data
.data
, 8, fsinfo
.full_size_information
.out
.call_avail_alloc_units
);
358 SBVAL(trans
->out
.data
.data
, 16, fsinfo
.full_size_information
.out
.actual_avail_alloc_units
);
359 SIVAL(trans
->out
.data
.data
, 24, fsinfo
.full_size_information
.out
.sectors_per_unit
);
360 SIVAL(trans
->out
.data
.data
, 28, fsinfo
.full_size_information
.out
.bytes_per_sector
);
364 case SMB_QFS_OBJECTID_INFORMATION
:
365 fsinfo
.objectid_information
.level
= RAW_QFS_OBJECTID_INFORMATION
;
367 status
= req
->tcon
->ntvfs_ops
->fsinfo(req
, &fsinfo
);
368 if (!NT_STATUS_IS_OK(status
)) {
372 trans2_setup_reply(req
, trans
, 0, 64, 0);
374 status
= ndr_push_struct_blob(&guid_blob
, req
,
375 &fsinfo
.objectid_information
.out
.guid
,
376 (ndr_push_flags_fn_t
)ndr_push_GUID
);
377 if (!NT_STATUS_IS_OK(status
)) {
381 memcpy(trans
->out
.data
.data
, guid_blob
.data
, GUID_SIZE
);
384 SBVAL(trans
->out
.data
.data
, 16 + 8*i
, fsinfo
.objectid_information
.out
.unknown
[i
]);
389 return NT_STATUS_INVALID_LEVEL
;
393 fill in the reply from a qpathinfo or qfileinfo call
395 static NTSTATUS
trans2_fileinfo_fill(struct smbsrv_request
*req
, struct smb_trans2
*trans
,
396 union smb_fileinfo
*st
)
400 switch (st
->generic
.level
) {
401 case RAW_FILEINFO_GENERIC
:
402 case RAW_FILEINFO_GETATTR
:
403 case RAW_FILEINFO_GETATTRE
:
404 /* handled elsewhere */
405 return NT_STATUS_INVALID_LEVEL
;
407 case RAW_FILEINFO_BASIC_INFO
:
408 case RAW_FILEINFO_BASIC_INFORMATION
:
409 trans2_setup_reply(req
, trans
, 2, 40, 0);
411 SSVAL(trans
->out
.params
.data
, 0, 0);
412 push_nttime(trans
->out
.data
.data
, 0, st
->basic_info
.out
.create_time
);
413 push_nttime(trans
->out
.data
.data
, 8, st
->basic_info
.out
.access_time
);
414 push_nttime(trans
->out
.data
.data
, 16, st
->basic_info
.out
.write_time
);
415 push_nttime(trans
->out
.data
.data
, 24, st
->basic_info
.out
.change_time
);
416 SIVAL(trans
->out
.data
.data
, 32, st
->basic_info
.out
.attrib
);
417 SIVAL(trans
->out
.data
.data
, 36, 0); /* padding */
420 case RAW_FILEINFO_STANDARD
:
421 trans2_setup_reply(req
, trans
, 2, 22, 0);
423 SSVAL(trans
->out
.params
.data
, 0, 0);
424 srv_push_dos_date2(req
->smb_conn
, trans
->out
.data
.data
, 0, st
->standard
.out
.create_time
);
425 srv_push_dos_date2(req
->smb_conn
, trans
->out
.data
.data
, 4, st
->standard
.out
.access_time
);
426 srv_push_dos_date2(req
->smb_conn
, trans
->out
.data
.data
, 8, st
->standard
.out
.write_time
);
427 SIVAL(trans
->out
.data
.data
, 12, st
->standard
.out
.size
);
428 SIVAL(trans
->out
.data
.data
, 16, st
->standard
.out
.alloc_size
);
429 SSVAL(trans
->out
.data
.data
, 20, st
->standard
.out
.attrib
);
432 case RAW_FILEINFO_EA_SIZE
:
433 trans2_setup_reply(req
, trans
, 2, 26, 0);
435 SSVAL(trans
->out
.params
.data
, 0, 0);
436 srv_push_dos_date2(req
->smb_conn
, trans
->out
.data
.data
, 0, st
->ea_size
.out
.create_time
);
437 srv_push_dos_date2(req
->smb_conn
, trans
->out
.data
.data
, 4, st
->ea_size
.out
.access_time
);
438 srv_push_dos_date2(req
->smb_conn
, trans
->out
.data
.data
, 8, st
->ea_size
.out
.write_time
);
439 SIVAL(trans
->out
.data
.data
, 12, st
->ea_size
.out
.size
);
440 SIVAL(trans
->out
.data
.data
, 16, st
->ea_size
.out
.alloc_size
);
441 SSVAL(trans
->out
.data
.data
, 20, st
->ea_size
.out
.attrib
);
442 SIVAL(trans
->out
.data
.data
, 22, st
->ea_size
.out
.ea_size
);
445 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION
:
446 trans2_setup_reply(req
, trans
, 2, 56, 0);
448 SSVAL(trans
->out
.params
.data
, 0, 0);
449 push_nttime(trans
->out
.data
.data
, 0, st
->network_open_information
.out
.create_time
);
450 push_nttime(trans
->out
.data
.data
, 8, st
->network_open_information
.out
.access_time
);
451 push_nttime(trans
->out
.data
.data
, 16, st
->network_open_information
.out
.write_time
);
452 push_nttime(trans
->out
.data
.data
, 24, st
->network_open_information
.out
.change_time
);
453 SBVAL(trans
->out
.data
.data
, 32, st
->network_open_information
.out
.alloc_size
);
454 SBVAL(trans
->out
.data
.data
, 40, st
->network_open_information
.out
.size
);
455 SIVAL(trans
->out
.data
.data
, 48, st
->network_open_information
.out
.attrib
);
456 SIVAL(trans
->out
.data
.data
, 52, 0); /* padding */
459 case RAW_FILEINFO_STANDARD_INFO
:
460 case RAW_FILEINFO_STANDARD_INFORMATION
:
461 trans2_setup_reply(req
, trans
, 2, 24, 0);
462 SSVAL(trans
->out
.params
.data
, 0, 0);
463 SBVAL(trans
->out
.data
.data
, 0, st
->standard_info
.out
.alloc_size
);
464 SBVAL(trans
->out
.data
.data
, 8, st
->standard_info
.out
.size
);
465 SIVAL(trans
->out
.data
.data
, 16, st
->standard_info
.out
.nlink
);
466 SCVAL(trans
->out
.data
.data
, 20, st
->standard_info
.out
.delete_pending
);
467 SCVAL(trans
->out
.data
.data
, 21, st
->standard_info
.out
.directory
);
468 SSVAL(trans
->out
.data
.data
, 22, 0); /* padding */
471 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION
:
472 trans2_setup_reply(req
, trans
, 2, 8, 0);
473 SSVAL(trans
->out
.params
.data
, 0, 0);
474 SIVAL(trans
->out
.data
.data
, 0, st
->attribute_tag_information
.out
.attrib
);
475 SIVAL(trans
->out
.data
.data
, 4, st
->attribute_tag_information
.out
.reparse_tag
);
478 case RAW_FILEINFO_EA_INFO
:
479 case RAW_FILEINFO_EA_INFORMATION
:
480 trans2_setup_reply(req
, trans
, 2, 4, 0);
481 SSVAL(trans
->out
.params
.data
, 0, 0);
482 SIVAL(trans
->out
.data
.data
, 0, st
->ea_info
.out
.ea_size
);
485 case RAW_FILEINFO_MODE_INFORMATION
:
486 trans2_setup_reply(req
, trans
, 2, 4, 0);
487 SSVAL(trans
->out
.params
.data
, 0, 0);
488 SIVAL(trans
->out
.data
.data
, 0, st
->mode_information
.out
.mode
);
491 case RAW_FILEINFO_ALIGNMENT_INFORMATION
:
492 trans2_setup_reply(req
, trans
, 2, 4, 0);
493 SSVAL(trans
->out
.params
.data
, 0, 0);
494 SIVAL(trans
->out
.data
.data
, 0,
495 st
->alignment_information
.out
.alignment_requirement
);
498 case RAW_FILEINFO_ALL_EAS
:
499 if (st
->all_eas
.out
.num_eas
== 0) {
500 trans2_setup_reply(req
, trans
, 2, 4, 0);
501 SSVAL(trans
->out
.params
.data
, 0, 0);
502 SIVAL(trans
->out
.data
.data
, 0, 0);
504 uint32_t list_size
= ea_list_size(st
->all_eas
.out
.num_eas
,
505 st
->all_eas
.out
.eas
);
506 trans2_setup_reply(req
, trans
, 2, list_size
, 0);
507 SSVAL(trans
->out
.params
.data
, 0, 0);
508 ea_put_list(trans
->out
.data
.data
,
509 st
->all_eas
.out
.num_eas
, st
->all_eas
.out
.eas
);
513 case RAW_FILEINFO_ACCESS_INFORMATION
:
514 trans2_setup_reply(req
, trans
, 2, 4, 0);
515 SSVAL(trans
->out
.params
.data
, 0, 0);
516 SIVAL(trans
->out
.data
.data
, 0, st
->access_information
.out
.access_flags
);
519 case RAW_FILEINFO_POSITION_INFORMATION
:
520 trans2_setup_reply(req
, trans
, 2, 8, 0);
521 SSVAL(trans
->out
.params
.data
, 0, 0);
522 SBVAL(trans
->out
.data
.data
, 0, st
->position_information
.out
.position
);
525 case RAW_FILEINFO_COMPRESSION_INFO
:
526 case RAW_FILEINFO_COMPRESSION_INFORMATION
:
527 trans2_setup_reply(req
, trans
, 2, 16, 0);
528 SSVAL(trans
->out
.params
.data
, 0, 0);
529 SBVAL(trans
->out
.data
.data
, 0, st
->compression_info
.out
.compressed_size
);
530 SSVAL(trans
->out
.data
.data
, 8, st
->compression_info
.out
.format
);
531 SCVAL(trans
->out
.data
.data
, 10, st
->compression_info
.out
.unit_shift
);
532 SCVAL(trans
->out
.data
.data
, 11, st
->compression_info
.out
.chunk_shift
);
533 SCVAL(trans
->out
.data
.data
, 12, st
->compression_info
.out
.cluster_shift
);
534 SSVAL(trans
->out
.data
.data
, 13, 0); /* 3 bytes padding */
535 SCVAL(trans
->out
.data
.data
, 15, 0);
538 case RAW_FILEINFO_IS_NAME_VALID
:
539 trans2_setup_reply(req
, trans
, 2, 0, 0);
540 SSVAL(trans
->out
.params
.data
, 0, 0);
543 case RAW_FILEINFO_INTERNAL_INFORMATION
:
544 trans2_setup_reply(req
, trans
, 2, 8, 0);
545 SSVAL(trans
->out
.params
.data
, 0, 0);
546 SBVAL(trans
->out
.data
.data
, 0, st
->internal_information
.out
.file_id
);
549 case RAW_FILEINFO_ALL_INFO
:
550 case RAW_FILEINFO_ALL_INFORMATION
:
551 trans2_setup_reply(req
, trans
, 2, 72, 0);
553 SSVAL(trans
->out
.params
.data
, 0, 0);
554 push_nttime(trans
->out
.data
.data
, 0, st
->all_info
.out
.create_time
);
555 push_nttime(trans
->out
.data
.data
, 8, st
->all_info
.out
.access_time
);
556 push_nttime(trans
->out
.data
.data
, 16, st
->all_info
.out
.write_time
);
557 push_nttime(trans
->out
.data
.data
, 24, st
->all_info
.out
.change_time
);
558 SIVAL(trans
->out
.data
.data
, 32, st
->all_info
.out
.attrib
);
559 SIVAL(trans
->out
.data
.data
, 36, 0);
560 SBVAL(trans
->out
.data
.data
, 40, st
->all_info
.out
.alloc_size
);
561 SBVAL(trans
->out
.data
.data
, 48, st
->all_info
.out
.size
);
562 SIVAL(trans
->out
.data
.data
, 56, st
->all_info
.out
.nlink
);
563 SCVAL(trans
->out
.data
.data
, 60, st
->all_info
.out
.delete_pending
);
564 SCVAL(trans
->out
.data
.data
, 61, st
->all_info
.out
.directory
);
565 SSVAL(trans
->out
.data
.data
, 62, 0); /* padding */
566 SIVAL(trans
->out
.data
.data
, 64, st
->all_info
.out
.ea_size
);
567 trans2_append_data_string(req
, trans
, &st
->all_info
.out
.fname
,
571 case RAW_FILEINFO_NAME_INFO
:
572 case RAW_FILEINFO_NAME_INFORMATION
:
573 trans2_setup_reply(req
, trans
, 2, 4, 0);
574 SSVAL(trans
->out
.params
.data
, 0, 0);
575 trans2_append_data_string(req
, trans
, &st
->name_info
.out
.fname
, 0, STR_UNICODE
);
578 case RAW_FILEINFO_ALT_NAME_INFO
:
579 case RAW_FILEINFO_ALT_NAME_INFORMATION
:
580 trans2_setup_reply(req
, trans
, 2, 4, 0);
581 SSVAL(trans
->out
.params
.data
, 0, 0);
582 trans2_append_data_string(req
, trans
, &st
->alt_name_info
.out
.fname
, 0, STR_UNICODE
);
585 case RAW_FILEINFO_STREAM_INFO
:
586 case RAW_FILEINFO_STREAM_INFORMATION
:
587 trans2_setup_reply(req
, trans
, 2, 0, 0);
589 SSVAL(trans
->out
.params
.data
, 0, 0);
591 for (i
=0;i
<st
->stream_info
.out
.num_streams
;i
++) {
592 uint16_t data_size
= trans
->out
.data
.length
;
595 trans2_grow_data(req
, trans
, data_size
+ 24);
596 data
= trans
->out
.data
.data
+ data_size
;
597 SBVAL(data
, 8, st
->stream_info
.out
.streams
[i
].size
);
598 SBVAL(data
, 16, st
->stream_info
.out
.streams
[i
].alloc_size
);
599 trans2_append_data_string(req
, trans
,
600 &st
->stream_info
.out
.streams
[i
].stream_name
,
601 data_size
+ 4, STR_UNICODE
);
602 if (i
== st
->stream_info
.out
.num_streams
- 1) {
603 SIVAL(trans
->out
.data
.data
, data_size
, 0);
605 trans2_grow_data_fill(req
, trans
, (trans
->out
.data
.length
+7)&~7);
606 SIVAL(trans
->out
.data
.data
, data_size
,
607 trans
->out
.data
.length
- data_size
);
613 return NT_STATUS_INVALID_LEVEL
;
617 trans2 qpathinfo implementation
619 static NTSTATUS
trans2_qpathinfo(struct smbsrv_request
*req
, struct smb_trans2
*trans
)
621 union smb_fileinfo st
;
625 /* make sure we got enough parameters */
626 if (trans
->in
.params
.length
< 8) {
627 return NT_STATUS_FOOBAR
;
630 level
= SVAL(trans
->in
.params
.data
, 0);
632 trans2_pull_blob_string(req
, &trans
->in
.params
, 6, &st
.generic
.in
.fname
, 0);
633 if (st
.generic
.in
.fname
== NULL
) {
634 return NT_STATUS_FOOBAR
;
637 /* work out the backend level - we make it 1-1 in the header */
638 st
.generic
.level
= (enum smb_fileinfo_level
)level
;
639 if (st
.generic
.level
>= RAW_FILEINFO_GENERIC
) {
640 return NT_STATUS_INVALID_LEVEL
;
643 /* call the backend */
644 status
= req
->tcon
->ntvfs_ops
->qpathinfo(req
, &st
);
645 if (!NT_STATUS_IS_OK(status
)) {
649 /* fill in the reply parameters */
650 status
= trans2_fileinfo_fill(req
, trans
, &st
);
657 trans2 qpathinfo implementation
659 static NTSTATUS
trans2_qfileinfo(struct smbsrv_request
*req
, struct smb_trans2
*trans
)
661 union smb_fileinfo st
;
665 /* make sure we got enough parameters */
666 if (trans
->in
.params
.length
< 4) {
667 return NT_STATUS_FOOBAR
;
670 st
.generic
.in
.fnum
= SVAL(trans
->in
.params
.data
, 0);
671 level
= SVAL(trans
->in
.params
.data
, 2);
673 /* work out the backend level - we make it 1-1 in the header */
674 st
.generic
.level
= (enum smb_fileinfo_level
)level
;
675 if (st
.generic
.level
>= RAW_FILEINFO_GENERIC
) {
676 return NT_STATUS_INVALID_LEVEL
;
679 /* call the backend */
680 status
= req
->tcon
->ntvfs_ops
->qfileinfo(req
, &st
);
681 if (!NT_STATUS_IS_OK(status
)) {
685 /* fill in the reply parameters */
686 status
= trans2_fileinfo_fill(req
, trans
, &st
);
693 parse a trans2 setfileinfo/setpathinfo data blob
695 static NTSTATUS
trans2_parse_sfileinfo(struct smbsrv_request
*req
,
696 union smb_setfileinfo
*st
,
697 const DATA_BLOB
*blob
)
701 switch (st
->generic
.level
) {
702 case RAW_SFILEINFO_GENERIC
:
703 case RAW_SFILEINFO_SETATTR
:
704 case RAW_SFILEINFO_SETATTRE
:
705 /* handled elsewhere */
706 return NT_STATUS_INVALID_LEVEL
;
708 case RAW_SFILEINFO_STANDARD
:
709 CHECK_MIN_BLOB_SIZE(blob
, 12);
710 st
->standard
.in
.create_time
= srv_pull_dos_date2(req
->smb_conn
, blob
->data
+ 0);
711 st
->standard
.in
.access_time
= srv_pull_dos_date2(req
->smb_conn
, blob
->data
+ 4);
712 st
->standard
.in
.write_time
= srv_pull_dos_date2(req
->smb_conn
, blob
->data
+ 8);
715 case RAW_SFILEINFO_EA_SET
:
716 CHECK_MIN_BLOB_SIZE(blob
, 4);
717 len
= IVAL(blob
->data
, 0);
718 if (len
> blob
->length
|| len
< 4) {
719 return NT_STATUS_INFO_LENGTH_MISMATCH
;
723 blob2
.data
= blob
->data
+4;
724 blob2
.length
= len
-4;
725 len
= ea_pull_struct(&blob2
, req
, &st
->ea_set
.in
.ea
);
728 return NT_STATUS_INVALID_PARAMETER
;
732 case SMB_SFILEINFO_BASIC_INFO
:
733 case SMB_SFILEINFO_BASIC_INFORMATION
:
734 CHECK_MIN_BLOB_SIZE(blob
, 36);
735 st
->basic_info
.in
.create_time
= pull_nttime(blob
->data
, 0);
736 st
->basic_info
.in
.access_time
= pull_nttime(blob
->data
, 8);
737 st
->basic_info
.in
.write_time
= pull_nttime(blob
->data
, 16);
738 st
->basic_info
.in
.change_time
= pull_nttime(blob
->data
, 24);
739 st
->basic_info
.in
.attrib
= IVAL(blob
->data
, 32);
742 case SMB_SFILEINFO_DISPOSITION_INFO
:
743 case SMB_SFILEINFO_DISPOSITION_INFORMATION
:
744 CHECK_MIN_BLOB_SIZE(blob
, 1);
745 st
->disposition_info
.in
.delete_on_close
= CVAL(blob
->data
, 0);
748 case SMB_SFILEINFO_ALLOCATION_INFO
:
749 case SMB_SFILEINFO_ALLOCATION_INFORMATION
:
750 CHECK_MIN_BLOB_SIZE(blob
, 8);
751 st
->allocation_info
.in
.alloc_size
= BVAL(blob
->data
, 0);
754 case RAW_SFILEINFO_END_OF_FILE_INFO
:
755 case RAW_SFILEINFO_END_OF_FILE_INFORMATION
:
756 CHECK_MIN_BLOB_SIZE(blob
, 8);
757 st
->end_of_file_info
.in
.size
= BVAL(blob
->data
, 0);
760 case RAW_SFILEINFO_RENAME_INFORMATION
: {
763 CHECK_MIN_BLOB_SIZE(blob
, 12);
764 st
->rename_information
.in
.overwrite
= CVAL(blob
->data
, 0);
765 st
->rename_information
.in
.root_fid
= IVAL(blob
->data
, 4);
766 len
= IVAL(blob
->data
, 8);
767 blob2
.data
= blob
->data
+12;
768 blob2
.length
= MIN(blob
->length
, len
);
769 trans2_pull_blob_string(req
, &blob2
, 0,
770 &st
->rename_information
.in
.new_name
, STR_UNICODE
);
774 case RAW_SFILEINFO_POSITION_INFORMATION
:
775 CHECK_MIN_BLOB_SIZE(blob
, 8);
776 st
->position_information
.in
.position
= BVAL(blob
->data
, 0);
779 case RAW_SFILEINFO_MODE_INFORMATION
:
780 CHECK_MIN_BLOB_SIZE(blob
, 4);
781 st
->mode_information
.in
.mode
= IVAL(blob
->data
, 0);
785 return NT_STATUS_INVALID_LEVEL
;
789 trans2 setfileinfo implementation
791 static NTSTATUS
trans2_setfileinfo(struct smbsrv_request
*req
, struct smb_trans2
*trans
)
793 union smb_setfileinfo st
;
795 uint16_t level
, fnum
;
798 /* make sure we got enough parameters */
799 if (trans
->in
.params
.length
< 4) {
800 return NT_STATUS_FOOBAR
;
803 fnum
= SVAL(trans
->in
.params
.data
, 0);
804 level
= SVAL(trans
->in
.params
.data
, 2);
806 blob
= &trans
->in
.data
;
808 st
.generic
.file
.fnum
= fnum
;
809 st
.generic
.level
= (enum smb_setfileinfo_level
)level
;
811 status
= trans2_parse_sfileinfo(req
, &st
, blob
);
812 if (!NT_STATUS_IS_OK(status
)) {
816 status
= req
->tcon
->ntvfs_ops
->setfileinfo(req
, &st
);
817 if (!NT_STATUS_IS_OK(status
)) {
821 trans2_setup_reply(req
, trans
, 2, 0, 0);
822 SSVAL(trans
->out
.params
.data
, 0, 0);
827 trans2 setpathinfo implementation
829 static NTSTATUS
trans2_setpathinfo(struct smbsrv_request
*req
, struct smb_trans2
*trans
)
831 union smb_setfileinfo st
;
836 /* make sure we got enough parameters */
837 if (trans
->in
.params
.length
< 4) {
838 return NT_STATUS_FOOBAR
;
841 level
= SVAL(trans
->in
.params
.data
, 0);
842 blob
= &trans
->in
.data
;
843 st
.generic
.level
= (enum smb_setfileinfo_level
)level
;
845 trans2_pull_blob_string(req
, &trans
->in
.params
, 6, &st
.generic
.file
.fname
, 0);
846 if (st
.generic
.file
.fname
== NULL
) {
847 return NT_STATUS_FOOBAR
;
850 status
= trans2_parse_sfileinfo(req
, &st
, blob
);
851 if (!NT_STATUS_IS_OK(status
)) {
855 status
= req
->tcon
->ntvfs_ops
->setpathinfo(req
, &st
);
856 if (!NT_STATUS_IS_OK(status
)) {
860 trans2_setup_reply(req
, trans
, 2, 0, 0);
861 SSVAL(trans
->out
.params
.data
, 0, 0);
866 /* a structure to encapsulate the state information about an in-progress ffirst/fnext operation */
868 struct smbsrv_request
*req
;
869 struct smb_trans2
*trans
;
870 enum smb_search_level level
;
871 uint16_t last_entry_offset
;
876 fill a single entry in a trans2 find reply
878 static void find_fill_info(struct smbsrv_request
*req
,
879 struct smb_trans2
*trans
,
880 struct find_state
*state
,
881 union smb_search_data
*file
)
884 uint_t ofs
= trans
->out
.data
.length
;
886 switch (state
->level
) {
887 case RAW_SEARCH_SEARCH
:
888 case RAW_SEARCH_FFIRST
:
889 case RAW_SEARCH_FUNIQUE
:
890 case RAW_SEARCH_GENERIC
:
891 /* handled elsewhere */
894 case RAW_SEARCH_STANDARD
:
895 if (state
->flags
& FLAG_TRANS2_FIND_REQUIRE_RESUME
) {
896 trans2_grow_data(req
, trans
, ofs
+ 27);
897 SIVAL(trans
->out
.data
.data
, ofs
, file
->standard
.resume_key
);
900 trans2_grow_data(req
, trans
, ofs
+ 23);
902 data
= trans
->out
.data
.data
+ ofs
;
903 srv_push_dos_date2(req
->smb_conn
, data
, 0, file
->standard
.create_time
);
904 srv_push_dos_date2(req
->smb_conn
, data
, 4, file
->standard
.access_time
);
905 srv_push_dos_date2(req
->smb_conn
, data
, 8, file
->standard
.write_time
);
906 SIVAL(data
, 12, file
->standard
.size
);
907 SIVAL(data
, 16, file
->standard
.alloc_size
);
908 SSVAL(data
, 20, file
->standard
.attrib
);
909 trans2_append_data_string(req
, trans
, &file
->standard
.name
,
910 ofs
+ 22, STR_LEN8BIT
| STR_TERMINATE
| STR_LEN_NOTERM
);
913 case RAW_SEARCH_EA_SIZE
:
914 if (state
->flags
& FLAG_TRANS2_FIND_REQUIRE_RESUME
) {
915 trans2_grow_data(req
, trans
, ofs
+ 31);
916 SIVAL(trans
->out
.data
.data
, ofs
, file
->ea_size
.resume_key
);
919 trans2_grow_data(req
, trans
, ofs
+ 27);
921 data
= trans
->out
.data
.data
+ ofs
;
922 srv_push_dos_date2(req
->smb_conn
, data
, 0, file
->ea_size
.create_time
);
923 srv_push_dos_date2(req
->smb_conn
, data
, 4, file
->ea_size
.access_time
);
924 srv_push_dos_date2(req
->smb_conn
, data
, 8, file
->ea_size
.write_time
);
925 SIVAL(data
, 12, file
->ea_size
.size
);
926 SIVAL(data
, 16, file
->ea_size
.alloc_size
);
927 SSVAL(data
, 20, file
->ea_size
.attrib
);
928 SIVAL(data
, 22, file
->ea_size
.ea_size
);
929 trans2_append_data_string(req
, trans
, &file
->ea_size
.name
,
930 ofs
+ 26, STR_LEN8BIT
| STR_NOALIGN
);
931 trans2_grow_data(req
, trans
, trans
->out
.data
.length
+ 1);
932 trans
->out
.data
.data
[trans
->out
.data
.length
-1] = 0;
935 case RAW_SEARCH_DIRECTORY_INFO
:
936 trans2_grow_data(req
, trans
, ofs
+ 64);
937 data
= trans
->out
.data
.data
+ ofs
;
938 SIVAL(data
, 4, file
->directory_info
.file_index
);
939 push_nttime(data
, 8, file
->directory_info
.create_time
);
940 push_nttime(data
, 16, file
->directory_info
.access_time
);
941 push_nttime(data
, 24, file
->directory_info
.write_time
);
942 push_nttime(data
, 32, file
->directory_info
.change_time
);
943 SBVAL(data
, 40, file
->directory_info
.size
);
944 SBVAL(data
, 48, file
->directory_info
.alloc_size
);
945 SIVAL(data
, 56, file
->directory_info
.attrib
);
946 trans2_append_data_string(req
, trans
, &file
->directory_info
.name
,
947 ofs
+ 60, STR_TERMINATE_ASCII
);
948 data
= trans
->out
.data
.data
+ ofs
;
949 SIVAL(data
, 0, trans
->out
.data
.length
- ofs
);
952 case RAW_SEARCH_FULL_DIRECTORY_INFO
:
953 trans2_grow_data(req
, trans
, ofs
+ 68);
954 data
= trans
->out
.data
.data
+ ofs
;
955 SIVAL(data
, 4, file
->full_directory_info
.file_index
);
956 push_nttime(data
, 8, file
->full_directory_info
.create_time
);
957 push_nttime(data
, 16, file
->full_directory_info
.access_time
);
958 push_nttime(data
, 24, file
->full_directory_info
.write_time
);
959 push_nttime(data
, 32, file
->full_directory_info
.change_time
);
960 SBVAL(data
, 40, file
->full_directory_info
.size
);
961 SBVAL(data
, 48, file
->full_directory_info
.alloc_size
);
962 SIVAL(data
, 56, file
->full_directory_info
.attrib
);
963 SIVAL(data
, 64, file
->full_directory_info
.ea_size
);
964 trans2_append_data_string(req
, trans
, &file
->full_directory_info
.name
,
965 ofs
+ 60, STR_TERMINATE_ASCII
);
966 data
= trans
->out
.data
.data
+ ofs
;
967 SIVAL(data
, 0, trans
->out
.data
.length
- ofs
);
970 case RAW_SEARCH_NAME_INFO
:
971 trans2_grow_data(req
, trans
, ofs
+ 12);
972 data
= trans
->out
.data
.data
+ ofs
;
973 SIVAL(data
, 4, file
->name_info
.file_index
);
974 trans2_append_data_string(req
, trans
, &file
->name_info
.name
,
975 ofs
+ 8, STR_TERMINATE_ASCII
);
976 data
= trans
->out
.data
.data
+ ofs
;
977 SIVAL(data
, 0, trans
->out
.data
.length
- ofs
);
980 case RAW_SEARCH_BOTH_DIRECTORY_INFO
:
981 trans2_grow_data(req
, trans
, ofs
+ 94);
982 data
= trans
->out
.data
.data
+ ofs
;
983 SIVAL(data
, 4, file
->both_directory_info
.file_index
);
984 push_nttime(data
, 8, file
->both_directory_info
.create_time
);
985 push_nttime(data
, 16, file
->both_directory_info
.access_time
);
986 push_nttime(data
, 24, file
->both_directory_info
.write_time
);
987 push_nttime(data
, 32, file
->both_directory_info
.change_time
);
988 SBVAL(data
, 40, file
->both_directory_info
.size
);
989 SBVAL(data
, 48, file
->both_directory_info
.alloc_size
);
990 SIVAL(data
, 56, file
->both_directory_info
.attrib
);
991 SIVAL(data
, 64, file
->both_directory_info
.ea_size
);
992 SCVAL(data
, 69, 0); /* reserved */
993 memset(data
+70,0,24);
994 trans2_push_data_string(req
, trans
,
996 &file
->both_directory_info
.short_name
,
997 24, STR_UNICODE
| STR_LEN8BIT
);
998 trans2_append_data_string(req
, trans
, &file
->both_directory_info
.name
,
999 ofs
+ 60, STR_TERMINATE_ASCII
);
1000 data
= trans
->out
.data
.data
+ ofs
;
1001 SIVAL(data
, 0, trans
->out
.data
.length
- ofs
);
1004 case RAW_SEARCH_ID_FULL_DIRECTORY_INFO
:
1005 trans2_grow_data(req
, trans
, ofs
+ 80);
1006 data
= trans
->out
.data
.data
+ ofs
;
1007 SIVAL(data
, 4, file
->id_full_directory_info
.file_index
);
1008 push_nttime(data
, 8, file
->id_full_directory_info
.create_time
);
1009 push_nttime(data
, 16, file
->id_full_directory_info
.access_time
);
1010 push_nttime(data
, 24, file
->id_full_directory_info
.write_time
);
1011 push_nttime(data
, 32, file
->id_full_directory_info
.change_time
);
1012 SBVAL(data
, 40, file
->id_full_directory_info
.size
);
1013 SBVAL(data
, 48, file
->id_full_directory_info
.alloc_size
);
1014 SIVAL(data
, 56, file
->id_full_directory_info
.attrib
);
1015 SIVAL(data
, 64, file
->id_full_directory_info
.ea_size
);
1016 SIVAL(data
, 68, 0); /* padding */
1017 SBVAL(data
, 72, file
->id_full_directory_info
.file_id
);
1018 trans2_append_data_string(req
, trans
, &file
->id_full_directory_info
.name
,
1019 ofs
+ 60, STR_TERMINATE_ASCII
);
1020 data
= trans
->out
.data
.data
+ ofs
;
1021 SIVAL(data
, 0, trans
->out
.data
.length
- ofs
);
1024 case RAW_SEARCH_ID_BOTH_DIRECTORY_INFO
:
1025 trans2_grow_data(req
, trans
, ofs
+ 104);
1026 data
= trans
->out
.data
.data
+ ofs
;
1027 SIVAL(data
, 4, file
->id_both_directory_info
.file_index
);
1028 push_nttime(data
, 8, file
->id_both_directory_info
.create_time
);
1029 push_nttime(data
, 16, file
->id_both_directory_info
.access_time
);
1030 push_nttime(data
, 24, file
->id_both_directory_info
.write_time
);
1031 push_nttime(data
, 32, file
->id_both_directory_info
.change_time
);
1032 SBVAL(data
, 40, file
->id_both_directory_info
.size
);
1033 SBVAL(data
, 48, file
->id_both_directory_info
.alloc_size
);
1034 SIVAL(data
, 56, file
->id_both_directory_info
.attrib
);
1035 SIVAL(data
, 64, file
->id_both_directory_info
.ea_size
);
1036 SCVAL(data
, 69, 0); /* reserved */
1037 memset(data
+70,0,26);
1038 trans2_push_data_string(req
, trans
,
1040 &file
->id_both_directory_info
.short_name
,
1041 24, STR_UNICODE
| STR_LEN8BIT
);
1042 SBVAL(data
, 96, file
->id_both_directory_info
.file_id
);
1043 trans2_append_data_string(req
, trans
, &file
->id_both_directory_info
.name
,
1044 ofs
+ 60, STR_TERMINATE_ASCII
);
1045 data
= trans
->out
.data
.data
+ ofs
;
1046 SIVAL(data
, 0, trans
->out
.data
.length
- ofs
);
1051 /* callback function for trans2 findfirst/findnext */
1052 static BOOL
find_callback(void *private, union smb_search_data
*file
)
1054 struct find_state
*state
= (struct find_state
*)private;
1055 struct smb_trans2
*trans
= state
->trans
;
1058 old_length
= trans
->out
.data
.length
;
1060 find_fill_info(state
->req
, trans
, state
, file
);
1062 /* see if we have gone beyond the user specified maximum */
1063 if (trans
->out
.data
.length
> trans
->in
.max_data
) {
1064 /* restore the old length and tell the backend to stop */
1065 trans2_grow_data(state
->req
, trans
, old_length
);
1069 state
->last_entry_offset
= old_length
;
1075 trans2 findfirst implementation
1077 static NTSTATUS
trans2_findfirst(struct smbsrv_request
*req
, struct smb_trans2
*trans
)
1079 union smb_search_first search
;
1083 struct find_state state
;
1085 /* make sure we got all the parameters */
1086 if (trans
->in
.params
.length
< 14) {
1087 return NT_STATUS_FOOBAR
;
1090 search
.t2ffirst
.in
.search_attrib
= SVAL(trans
->in
.params
.data
, 0);
1091 search
.t2ffirst
.in
.max_count
= SVAL(trans
->in
.params
.data
, 2);
1092 search
.t2ffirst
.in
.flags
= SVAL(trans
->in
.params
.data
, 4);
1093 level
= SVAL(trans
->in
.params
.data
, 6);
1094 search
.t2ffirst
.in
.storage_type
= IVAL(trans
->in
.params
.data
, 8);
1096 trans2_pull_blob_string(req
, &trans
->in
.params
, 12, &search
.t2ffirst
.in
.pattern
, 0);
1097 if (search
.t2ffirst
.in
.pattern
== NULL
) {
1098 return NT_STATUS_FOOBAR
;
1101 search
.t2ffirst
.level
= (enum smb_search_level
)level
;
1102 if (search
.t2ffirst
.level
>= RAW_SEARCH_GENERIC
) {
1103 return NT_STATUS_INVALID_LEVEL
;
1106 /* setup the private state structure that the backend will give us in the callback */
1108 state
.trans
= trans
;
1109 state
.level
= search
.t2ffirst
.level
;
1110 state
.last_entry_offset
= 0;
1111 state
.flags
= search
.t2ffirst
.in
.flags
;
1113 /* setup for just a header in the reply */
1114 trans2_setup_reply(req
, trans
, 10, 0, 0);
1116 /* call the backend */
1117 status
= req
->tcon
->ntvfs_ops
->search_first(req
, &search
, &state
, find_callback
);
1118 if (!NT_STATUS_IS_OK(status
)) {
1119 trans2_setup_reply(req
, trans
, 0, 0, 0);
1123 /* fill in the findfirst reply header */
1124 param
= trans
->out
.params
.data
;
1125 SSVAL(param
, VWV(0), search
.t2ffirst
.out
.handle
);
1126 SSVAL(param
, VWV(1), search
.t2ffirst
.out
.count
);
1127 SSVAL(param
, VWV(2), search
.t2ffirst
.out
.end_of_search
);
1128 SSVAL(param
, VWV(3), 0);
1129 SSVAL(param
, VWV(4), state
.last_entry_offset
);
1131 return NT_STATUS_OK
;
1136 trans2 findnext implementation
1138 static NTSTATUS
trans2_findnext(struct smbsrv_request
*req
, struct smb_trans2
*trans
)
1140 union smb_search_next search
;
1144 struct find_state state
;
1146 /* make sure we got all the parameters */
1147 if (trans
->in
.params
.length
< 12) {
1148 return NT_STATUS_FOOBAR
;
1151 search
.t2fnext
.in
.handle
= SVAL(trans
->in
.params
.data
, 0);
1152 search
.t2fnext
.in
.max_count
= SVAL(trans
->in
.params
.data
, 2);
1153 level
= SVAL(trans
->in
.params
.data
, 4);
1154 search
.t2fnext
.in
.resume_key
= IVAL(trans
->in
.params
.data
, 6);
1155 search
.t2fnext
.in
.flags
= SVAL(trans
->in
.params
.data
, 10);
1157 trans2_pull_blob_string(req
, &trans
->in
.params
, 12, &search
.t2fnext
.in
.last_name
, 0);
1158 if (search
.t2fnext
.in
.last_name
== NULL
) {
1159 return NT_STATUS_FOOBAR
;
1162 search
.t2fnext
.level
= (enum smb_search_level
)level
;
1163 if (search
.t2fnext
.level
>= RAW_SEARCH_GENERIC
) {
1164 return NT_STATUS_INVALID_LEVEL
;
1167 /* setup the private state structure that the backend will give us in the callback */
1169 state
.trans
= trans
;
1170 state
.level
= search
.t2fnext
.level
;
1171 state
.last_entry_offset
= 0;
1172 state
.flags
= search
.t2fnext
.in
.flags
;
1174 /* setup for just a header in the reply */
1175 trans2_setup_reply(req
, trans
, 8, 0, 0);
1177 /* call the backend */
1178 status
= req
->tcon
->ntvfs_ops
->search_next(req
, &search
, &state
, find_callback
);
1179 if (!NT_STATUS_IS_OK(status
)) {
1183 /* fill in the findfirst reply header */
1184 param
= trans
->out
.params
.data
;
1185 SSVAL(param
, VWV(0), search
.t2fnext
.out
.count
);
1186 SSVAL(param
, VWV(1), search
.t2fnext
.out
.end_of_search
);
1187 SSVAL(param
, VWV(2), 0);
1188 SSVAL(param
, VWV(3), state
.last_entry_offset
);
1190 return NT_STATUS_OK
;
1195 backend for trans2 requests
1197 static NTSTATUS
trans2_backend(struct smbsrv_request
*req
, struct smb_trans2
*trans
)
1199 if (req
->tcon
->ntvfs_ops
->trans2
!= NULL
) {
1200 /* direct trans2 pass thru */
1201 return req
->tcon
->ntvfs_ops
->trans2(req
, trans
);
1204 /* must have at least one setup word */
1205 if (trans
->in
.setup_count
< 1) {
1206 return NT_STATUS_FOOBAR
;
1209 /* the trans2 command is in setup[0] */
1210 switch (trans
->in
.setup
[0]) {
1211 case TRANSACT2_FINDFIRST
:
1212 return trans2_findfirst(req
, trans
);
1213 case TRANSACT2_FINDNEXT
:
1214 return trans2_findnext(req
, trans
);
1215 case TRANSACT2_QPATHINFO
:
1216 return trans2_qpathinfo(req
, trans
);
1217 case TRANSACT2_QFILEINFO
:
1218 return trans2_qfileinfo(req
, trans
);
1219 case TRANSACT2_SETFILEINFO
:
1220 return trans2_setfileinfo(req
, trans
);
1221 case TRANSACT2_SETPATHINFO
:
1222 return trans2_setpathinfo(req
, trans
);
1223 case TRANSACT2_QFSINFO
:
1224 return trans2_qfsinfo(req
, trans
);
1227 /* an unknown trans2 command */
1228 return NT_STATUS_FOOBAR
;
1233 backend for trans requests
1235 static NTSTATUS
trans_backend(struct smbsrv_request
*req
, struct smb_trans2
*trans
)
1237 if (!req
->tcon
->ntvfs_ops
->trans
) {
1238 return NT_STATUS_NOT_IMPLEMENTED
;
1240 return req
->tcon
->ntvfs_ops
->trans(req
, trans
);
1244 /****************************************************************************
1245 Reply to an SMBtrans or SMBtrans2 request
1246 ****************************************************************************/
1247 void reply_trans_generic(struct smbsrv_request
*req
, uint8_t command
)
1249 struct smb_trans2 trans
;
1251 uint16_t param_ofs
, data_ofs
;
1252 uint16_t param_count
, data_count
;
1253 uint16_t params_left
, data_left
;
1254 uint16_t param_total
, data_total
;
1255 char *params
, *data
;
1259 if (req
->in
.wct
< 14) {
1260 req_reply_error(req
, NT_STATUS_FOOBAR
);
1264 param_total
= SVAL(req
->in
.vwv
, VWV(0));
1265 data_total
= SVAL(req
->in
.vwv
, VWV(1));
1266 trans
.in
.max_param
= SVAL(req
->in
.vwv
, VWV(2));
1267 trans
.in
.max_data
= SVAL(req
->in
.vwv
, VWV(3));
1268 trans
.in
.max_setup
= CVAL(req
->in
.vwv
, VWV(4));
1269 trans
.in
.flags
= SVAL(req
->in
.vwv
, VWV(5));
1270 trans
.in
.timeout
= IVAL(req
->in
.vwv
, VWV(6));
1271 param_count
= SVAL(req
->in
.vwv
, VWV(9));
1272 param_ofs
= SVAL(req
->in
.vwv
, VWV(10));
1273 data_count
= SVAL(req
->in
.vwv
, VWV(11));
1274 data_ofs
= SVAL(req
->in
.vwv
, VWV(12));
1275 trans
.in
.setup_count
= CVAL(req
->in
.vwv
, VWV(13));
1277 if (req
->in
.wct
!= 14 + trans
.in
.setup_count
) {
1278 req_reply_dos_error(req
, ERRSRV
, ERRerror
);
1282 /* parse out the setup words */
1283 trans
.in
.setup
= talloc(req
, trans
.in
.setup_count
* sizeof(uint16_t));
1284 if (trans
.in
.setup_count
&& !trans
.in
.setup
) {
1285 req_reply_error(req
, NT_STATUS_NO_MEMORY
);
1288 for (i
=0;i
<trans
.in
.setup_count
;i
++) {
1289 trans
.in
.setup
[i
] = SVAL(req
->in
.vwv
, VWV(14+i
));
1292 if (command
== SMBtrans
) {
1293 req_pull_string(req
, &trans
.in
.trans_name
, req
->in
.data
, -1, STR_TERMINATE
);
1296 if (!req_pull_blob(req
, req
->in
.hdr
+ param_ofs
, param_count
, &trans
.in
.params
) ||
1297 !req_pull_blob(req
, req
->in
.hdr
+ data_ofs
, data_count
, &trans
.in
.data
)) {
1298 req_reply_error(req
, NT_STATUS_FOOBAR
);
1302 /* is it a partial request? if so, then send a 'send more' message */
1303 if (param_total
> param_count
||
1304 data_total
> data_count
) {
1305 DEBUG(0,("REWRITE: not handling partial trans requests!\n"));
1309 /* its a full request, give it to the backend */
1310 if (command
== SMBtrans
) {
1311 status
= trans_backend(req
, &trans
);
1313 status
= trans2_backend(req
, &trans
);
1316 if (NT_STATUS_IS_ERR(status
)) {
1317 req_reply_error(req
, status
);
1321 params_left
= trans
.out
.params
.length
;
1322 data_left
= trans
.out
.data
.length
;
1323 params
= trans
.out
.params
.data
;
1324 data
= trans
.out
.data
.data
;
1326 /* we need to divide up the reply into chunks that fit into
1327 the negotiated buffer size */
1329 uint16_t this_data
, this_param
, max_bytes
;
1330 uint_t align1
= 1, align2
= (params_left
? 2 : 0);
1332 req_setup_reply(req
, 10 + trans
.out
.setup_count
, 0);
1334 if (!NT_STATUS_IS_OK(status
)) {
1335 req_setup_error(req
, status
);
1338 max_bytes
= req_max_data(req
) - (align1
+ align2
);
1340 this_param
= params_left
;
1341 if (this_param
> max_bytes
) {
1342 this_param
= max_bytes
;
1344 max_bytes
-= this_param
;
1346 this_data
= data_left
;
1347 if (this_data
> max_bytes
) {
1348 this_data
= max_bytes
;
1351 req_grow_data(req
, this_param
+ this_data
+ (align1
+ align2
));
1353 SSVAL(req
->out
.vwv
, VWV(0), trans
.out
.params
.length
);
1354 SSVAL(req
->out
.vwv
, VWV(1), trans
.out
.data
.length
);
1355 SSVAL(req
->out
.vwv
, VWV(2), 0);
1357 SSVAL(req
->out
.vwv
, VWV(3), this_param
);
1358 SSVAL(req
->out
.vwv
, VWV(4), align1
+ PTR_DIFF(req
->out
.data
, req
->out
.hdr
));
1359 SSVAL(req
->out
.vwv
, VWV(5), PTR_DIFF(params
, trans
.out
.params
.data
));
1361 SSVAL(req
->out
.vwv
, VWV(6), this_data
);
1362 SSVAL(req
->out
.vwv
, VWV(7), align1
+ align2
+
1363 PTR_DIFF(req
->out
.data
+ this_param
, req
->out
.hdr
));
1364 SSVAL(req
->out
.vwv
, VWV(8), PTR_DIFF(data
, trans
.out
.data
.data
));
1366 SSVAL(req
->out
.vwv
, VWV(9), trans
.out
.setup_count
);
1367 for (i
=0;i
<trans
.out
.setup_count
;i
++) {
1368 SSVAL(req
->out
.vwv
, VWV(10+i
), trans
.out
.setup
[i
]);
1371 memset(req
->out
.data
, 0, align1
);
1372 if (this_param
!= 0) {
1373 memcpy(req
->out
.data
+ align1
, params
, this_param
);
1375 memset(req
->out
.data
+this_param
+align1
, 0, align2
);
1376 if (this_data
!= 0) {
1377 memcpy(req
->out
.data
+this_param
+align1
+align2
, data
, this_data
);
1380 params_left
-= this_param
;
1381 data_left
-= this_data
;
1382 params
+= this_param
;
1385 /* don't destroy unless this is the last chunk */
1386 if (params_left
!= 0 || data_left
!= 0) {
1387 talloc_increase_ref_count(req
);
1390 req_send_reply(req
);
1391 } while (params_left
!= 0 || data_left
!= 0);
1395 /****************************************************************************
1396 Reply to an SMBtrans2
1397 ****************************************************************************/
1398 void reply_trans2(struct smbsrv_request
*req
)
1400 reply_trans_generic(req
, SMBtrans2
);
1403 /****************************************************************************
1404 Reply to an SMBtrans
1405 ****************************************************************************/
1406 void reply_trans(struct smbsrv_request
*req
)
1408 reply_trans_generic(req
, SMBtrans
);
1411 /****************************************************************************
1412 Reply to an SMBtranss2 request
1413 ****************************************************************************/
1414 void reply_transs2(struct smbsrv_request
*req
)
1416 req_reply_error(req
, NT_STATUS_FOOBAR
);