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 3 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, see <http://www.gnu.org/licenses/>.
20 This file handles the parsing of transact2 requests
24 #include "lib/util/dlinklist.h"
25 #include "smb_server/smb_server.h"
26 #include "librpc/gen_ndr/ndr_misc.h"
27 #include "ntvfs/ntvfs.h"
28 #include "libcli/raw/libcliraw.h"
30 #define TRANS2_CHECK_ASYNC_STATUS_SIMPLE do { \
31 if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) { \
32 trans2_setup_reply(trans, 0, 0, 0);\
33 return req->ntvfs->async_states->status; \
36 #define TRANS2_CHECK_ASYNC_STATUS(ptr, type) do { \
37 TRANS2_CHECK_ASYNC_STATUS_SIMPLE; \
38 ptr = talloc_get_type(op->op_info, type); \
40 #define TRANS2_CHECK(cmd) do { \
43 NT_STATUS_NOT_OK_RETURN(_status); \
47 hold the state of a nttrans op while in progress. Needed to allow for async backend
51 struct smbsrv_request
*req
;
52 struct smb_trans2
*trans
;
54 NTSTATUS (*send_fn
)(struct trans_op
*);
58 #define CHECK_MIN_BLOB_SIZE(blob, size) do { \
59 if ((blob)->length < (size)) { \
60 return NT_STATUS_INFO_LENGTH_MISMATCH; \
63 /* setup a trans2 reply, given the data and params sizes */
64 static NTSTATUS
trans2_setup_reply(struct smb_trans2
*trans
,
65 uint16_t param_size
, uint16_t data_size
,
68 trans
->out
.setup_count
= setup_count
;
69 if (setup_count
> 0) {
70 trans
->out
.setup
= talloc_zero_array(trans
, uint16_t, setup_count
);
71 NT_STATUS_HAVE_NO_MEMORY(trans
->out
.setup
);
73 trans
->out
.params
= data_blob_talloc(trans
, NULL
, param_size
);
74 if (param_size
> 0) NT_STATUS_HAVE_NO_MEMORY(trans
->out
.params
.data
);
76 trans
->out
.data
= data_blob_talloc(trans
, NULL
, data_size
);
77 if (data_size
> 0) NT_STATUS_HAVE_NO_MEMORY(trans
->out
.data
.data
);
82 static NTSTATUS
trans2_push_fsinfo(struct smbsrv_connection
*smb_conn
,
85 union smb_fsinfo
*fsinfo
,
86 int default_str_flags
)
88 enum smb_fsinfo_level passthru_level
;
90 switch (fsinfo
->generic
.level
) {
91 case RAW_QFS_ALLOCATION
:
92 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx
, blob
, 18));
94 SIVAL(blob
->data
, 0, fsinfo
->allocation
.out
.fs_id
);
95 SIVAL(blob
->data
, 4, fsinfo
->allocation
.out
.sectors_per_unit
);
96 SIVAL(blob
->data
, 8, fsinfo
->allocation
.out
.total_alloc_units
);
97 SIVAL(blob
->data
, 12, fsinfo
->allocation
.out
.avail_alloc_units
);
98 SSVAL(blob
->data
, 16, fsinfo
->allocation
.out
.bytes_per_sector
);
103 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx
, blob
, 5));
105 SIVAL(blob
->data
, 0, fsinfo
->volume
.out
.serial_number
);
106 /* w2k3 implements this incorrectly for unicode - it
107 * leaves the last byte off the string */
108 TRANS2_CHECK(smbsrv_blob_append_string(mem_ctx
, blob
,
109 fsinfo
->volume
.out
.volume_name
.s
,
110 4, default_str_flags
,
111 STR_LEN8BIT
|STR_NOALIGN
));
115 case RAW_QFS_VOLUME_INFO
:
116 passthru_level
= RAW_QFS_VOLUME_INFORMATION
;
119 case RAW_QFS_SIZE_INFO
:
120 passthru_level
= RAW_QFS_SIZE_INFORMATION
;
123 case RAW_QFS_DEVICE_INFO
:
124 passthru_level
= RAW_QFS_DEVICE_INFORMATION
;
127 case RAW_QFS_ATTRIBUTE_INFO
:
128 passthru_level
= RAW_QFS_ATTRIBUTE_INFORMATION
;
132 passthru_level
= fsinfo
->generic
.level
;
136 return smbsrv_push_passthru_fsinfo(mem_ctx
, blob
,
137 passthru_level
, fsinfo
,
142 trans2 qfsinfo implementation send
144 static NTSTATUS
trans2_qfsinfo_send(struct trans_op
*op
)
146 struct smbsrv_request
*req
= op
->req
;
147 struct smb_trans2
*trans
= op
->trans
;
148 union smb_fsinfo
*fsinfo
;
150 TRANS2_CHECK_ASYNC_STATUS(fsinfo
, union smb_fsinfo
);
152 TRANS2_CHECK(trans2_setup_reply(trans
, 0, 0, 0));
154 TRANS2_CHECK(trans2_push_fsinfo(req
->smb_conn
, trans
,
155 &trans
->out
.data
, fsinfo
,
156 SMBSRV_REQ_DEFAULT_STR_FLAGS(req
)));
162 trans2 qfsinfo implementation
164 static NTSTATUS
trans2_qfsinfo(struct smbsrv_request
*req
, struct trans_op
*op
)
166 struct smb_trans2
*trans
= op
->trans
;
167 union smb_fsinfo
*fsinfo
;
170 /* make sure we got enough parameters */
171 if (trans
->in
.params
.length
!= 2) {
172 return NT_STATUS_FOOBAR
;
175 fsinfo
= talloc(op
, union smb_fsinfo
);
176 NT_STATUS_HAVE_NO_MEMORY(fsinfo
);
178 level
= SVAL(trans
->in
.params
.data
, 0);
180 /* work out the backend level - we make it 1-1 in the header */
181 fsinfo
->generic
.level
= (enum smb_fsinfo_level
)level
;
182 if (fsinfo
->generic
.level
>= RAW_QFS_GENERIC
) {
183 return NT_STATUS_INVALID_LEVEL
;
186 op
->op_info
= fsinfo
;
187 op
->send_fn
= trans2_qfsinfo_send
;
189 return ntvfs_fsinfo(req
->ntvfs
, fsinfo
);
194 trans2 open implementation send
196 static NTSTATUS
trans2_open_send(struct trans_op
*op
)
198 struct smbsrv_request
*req
= op
->req
;
199 struct smb_trans2
*trans
= op
->trans
;
202 TRANS2_CHECK_ASYNC_STATUS(io
, union smb_open
);
204 TRANS2_CHECK(trans2_setup_reply(trans
, 30, 0, 0));
206 smbsrv_push_fnum(trans
->out
.params
.data
, VWV(0), io
->t2open
.out
.file
.ntvfs
);
207 SSVAL(trans
->out
.params
.data
, VWV(1), io
->t2open
.out
.attrib
);
208 srv_push_dos_date3(req
->smb_conn
, trans
->out
.params
.data
,
209 VWV(2), io
->t2open
.out
.write_time
);
210 SIVAL(trans
->out
.params
.data
, VWV(4), io
->t2open
.out
.size
);
211 SSVAL(trans
->out
.params
.data
, VWV(6), io
->t2open
.out
.access
);
212 SSVAL(trans
->out
.params
.data
, VWV(7), io
->t2open
.out
.ftype
);
213 SSVAL(trans
->out
.params
.data
, VWV(8), io
->t2open
.out
.devstate
);
214 SSVAL(trans
->out
.params
.data
, VWV(9), io
->t2open
.out
.action
);
215 SIVAL(trans
->out
.params
.data
, VWV(10), 0); /* reserved */
216 SSVAL(trans
->out
.params
.data
, VWV(12), 0); /* EaErrorOffset */
217 SIVAL(trans
->out
.params
.data
, VWV(13), 0); /* EaLength */
223 trans2 open implementation
225 static NTSTATUS
trans2_open(struct smbsrv_request
*req
, struct trans_op
*op
)
227 struct smb_trans2
*trans
= op
->trans
;
230 /* make sure we got enough parameters */
231 if (trans
->in
.params
.length
< 29) {
232 return NT_STATUS_FOOBAR
;
235 io
= talloc(op
, union smb_open
);
236 NT_STATUS_HAVE_NO_MEMORY(io
);
238 io
->t2open
.level
= RAW_OPEN_T2OPEN
;
239 io
->t2open
.in
.flags
= SVAL(trans
->in
.params
.data
, VWV(0));
240 io
->t2open
.in
.open_mode
= SVAL(trans
->in
.params
.data
, VWV(1));
241 io
->t2open
.in
.search_attrs
= SVAL(trans
->in
.params
.data
, VWV(2));
242 io
->t2open
.in
.file_attrs
= SVAL(trans
->in
.params
.data
, VWV(3));
243 io
->t2open
.in
.write_time
= srv_pull_dos_date(req
->smb_conn
,
244 trans
->in
.params
.data
+ VWV(4));
245 io
->t2open
.in
.open_func
= SVAL(trans
->in
.params
.data
, VWV(6));
246 io
->t2open
.in
.size
= IVAL(trans
->in
.params
.data
, VWV(7));
247 io
->t2open
.in
.timeout
= IVAL(trans
->in
.params
.data
, VWV(9));
248 io
->t2open
.in
.num_eas
= 0;
249 io
->t2open
.in
.eas
= NULL
;
251 smbsrv_blob_pull_string(req
, &trans
->in
.params
, 28, &io
->t2open
.in
.fname
, 0);
252 if (io
->t2open
.in
.fname
== NULL
) {
253 return NT_STATUS_FOOBAR
;
256 TRANS2_CHECK(ea_pull_list(&trans
->in
.data
, io
, &io
->t2open
.in
.num_eas
, &io
->t2open
.in
.eas
));
259 op
->send_fn
= trans2_open_send
;
261 return ntvfs_open(req
->ntvfs
, io
);
268 static NTSTATUS
trans2_simple_send(struct trans_op
*op
)
270 struct smbsrv_request
*req
= op
->req
;
271 struct smb_trans2
*trans
= op
->trans
;
273 TRANS2_CHECK_ASYNC_STATUS_SIMPLE
;
275 TRANS2_CHECK(trans2_setup_reply(trans
, 2, 0, 0));
277 SSVAL(trans
->out
.params
.data
, VWV(0), 0);
283 trans2 mkdir implementation
285 static NTSTATUS
trans2_mkdir(struct smbsrv_request
*req
, struct trans_op
*op
)
287 struct smb_trans2
*trans
= op
->trans
;
290 /* make sure we got enough parameters */
291 if (trans
->in
.params
.length
< 5) {
292 return NT_STATUS_FOOBAR
;
295 io
= talloc(op
, union smb_mkdir
);
296 NT_STATUS_HAVE_NO_MEMORY(io
);
298 io
->t2mkdir
.level
= RAW_MKDIR_T2MKDIR
;
299 smbsrv_blob_pull_string(req
, &trans
->in
.params
, 4, &io
->t2mkdir
.in
.path
, 0);
300 if (io
->t2mkdir
.in
.path
== NULL
) {
301 return NT_STATUS_FOOBAR
;
304 TRANS2_CHECK(ea_pull_list(&trans
->in
.data
, io
,
305 &io
->t2mkdir
.in
.num_eas
,
306 &io
->t2mkdir
.in
.eas
));
309 op
->send_fn
= trans2_simple_send
;
311 return ntvfs_mkdir(req
->ntvfs
, io
);
314 static NTSTATUS
trans2_push_fileinfo(struct smbsrv_connection
*smb_conn
,
317 union smb_fileinfo
*st
,
318 int default_str_flags
)
321 enum smb_fileinfo_level passthru_level
;
323 switch (st
->generic
.level
) {
324 case RAW_FILEINFO_GENERIC
:
325 case RAW_FILEINFO_GETATTR
:
326 case RAW_FILEINFO_GETATTRE
:
327 case RAW_FILEINFO_SEC_DESC
:
328 case RAW_FILEINFO_SMB2_ALL_EAS
:
329 case RAW_FILEINFO_SMB2_ALL_INFORMATION
:
330 /* handled elsewhere */
331 return NT_STATUS_INVALID_LEVEL
;
333 case RAW_FILEINFO_UNIX_BASIC
:
334 case RAW_FILEINFO_UNIX_LINK
:
335 /* not implemented yet */
336 return NT_STATUS_INVALID_LEVEL
;
338 case RAW_FILEINFO_STANDARD
:
339 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx
, blob
, 22));
341 srv_push_dos_date2(smb_conn
, blob
->data
, 0, st
->standard
.out
.create_time
);
342 srv_push_dos_date2(smb_conn
, blob
->data
, 4, st
->standard
.out
.access_time
);
343 srv_push_dos_date2(smb_conn
, blob
->data
, 8, st
->standard
.out
.write_time
);
344 SIVAL(blob
->data
, 12, st
->standard
.out
.size
);
345 SIVAL(blob
->data
, 16, st
->standard
.out
.alloc_size
);
346 SSVAL(blob
->data
, 20, st
->standard
.out
.attrib
);
349 case RAW_FILEINFO_EA_SIZE
:
350 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx
, blob
, 26));
352 srv_push_dos_date2(smb_conn
, blob
->data
, 0, st
->ea_size
.out
.create_time
);
353 srv_push_dos_date2(smb_conn
, blob
->data
, 4, st
->ea_size
.out
.access_time
);
354 srv_push_dos_date2(smb_conn
, blob
->data
, 8, st
->ea_size
.out
.write_time
);
355 SIVAL(blob
->data
, 12, st
->ea_size
.out
.size
);
356 SIVAL(blob
->data
, 16, st
->ea_size
.out
.alloc_size
);
357 SSVAL(blob
->data
, 20, st
->ea_size
.out
.attrib
);
358 SIVAL(blob
->data
, 22, st
->ea_size
.out
.ea_size
);
361 case RAW_FILEINFO_EA_LIST
:
362 list_size
= ea_list_size(st
->ea_list
.out
.num_eas
,
363 st
->ea_list
.out
.eas
);
364 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx
, blob
, list_size
));
366 ea_put_list(blob
->data
,
367 st
->ea_list
.out
.num_eas
, st
->ea_list
.out
.eas
);
370 case RAW_FILEINFO_ALL_EAS
:
371 list_size
= ea_list_size(st
->all_eas
.out
.num_eas
,
372 st
->all_eas
.out
.eas
);
373 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx
, blob
, list_size
));
375 ea_put_list(blob
->data
,
376 st
->all_eas
.out
.num_eas
, st
->all_eas
.out
.eas
);
379 case RAW_FILEINFO_IS_NAME_VALID
:
382 case RAW_FILEINFO_BASIC_INFO
:
383 passthru_level
= RAW_FILEINFO_BASIC_INFORMATION
;
386 case RAW_FILEINFO_STANDARD_INFO
:
387 passthru_level
= RAW_FILEINFO_STANDARD_INFORMATION
;
390 case RAW_FILEINFO_EA_INFO
:
391 passthru_level
= RAW_FILEINFO_EA_INFORMATION
;
394 case RAW_FILEINFO_COMPRESSION_INFO
:
395 passthru_level
= RAW_FILEINFO_COMPRESSION_INFORMATION
;
398 case RAW_FILEINFO_ALL_INFO
:
399 passthru_level
= RAW_FILEINFO_ALL_INFORMATION
;
402 case RAW_FILEINFO_NAME_INFO
:
403 passthru_level
= RAW_FILEINFO_NAME_INFORMATION
;
406 case RAW_FILEINFO_ALT_NAME_INFO
:
407 passthru_level
= RAW_FILEINFO_ALT_NAME_INFORMATION
;
410 case RAW_FILEINFO_STREAM_INFO
:
411 passthru_level
= RAW_FILEINFO_STREAM_INFORMATION
;
415 passthru_level
= st
->generic
.level
;
419 return smbsrv_push_passthru_fileinfo(mem_ctx
, blob
,
425 fill in the reply from a qpathinfo or qfileinfo call
427 static NTSTATUS
trans2_fileinfo_send(struct trans_op
*op
)
429 struct smbsrv_request
*req
= op
->req
;
430 struct smb_trans2
*trans
= op
->trans
;
431 union smb_fileinfo
*st
;
433 TRANS2_CHECK_ASYNC_STATUS(st
, union smb_fileinfo
);
435 TRANS2_CHECK(trans2_setup_reply(trans
, 2, 0, 0));
436 SSVAL(trans
->out
.params
.data
, 0, 0);
438 TRANS2_CHECK(trans2_push_fileinfo(req
->smb_conn
, trans
,
439 &trans
->out
.data
, st
,
440 SMBSRV_REQ_DEFAULT_STR_FLAGS(req
)));
446 trans2 qpathinfo implementation
448 static NTSTATUS
trans2_qpathinfo(struct smbsrv_request
*req
, struct trans_op
*op
)
450 struct smb_trans2
*trans
= op
->trans
;
451 union smb_fileinfo
*st
;
454 /* make sure we got enough parameters */
455 if (trans
->in
.params
.length
< 2) {
456 return NT_STATUS_FOOBAR
;
459 st
= talloc(op
, union smb_fileinfo
);
460 NT_STATUS_HAVE_NO_MEMORY(st
);
462 level
= SVAL(trans
->in
.params
.data
, 0);
464 smbsrv_blob_pull_string(req
, &trans
->in
.params
, 6, &st
->generic
.in
.file
.path
, 0);
465 if (st
->generic
.in
.file
.path
== NULL
) {
466 return NT_STATUS_FOOBAR
;
469 /* work out the backend level - we make it 1-1 in the header */
470 st
->generic
.level
= (enum smb_fileinfo_level
)level
;
471 if (st
->generic
.level
>= RAW_FILEINFO_GENERIC
) {
472 return NT_STATUS_INVALID_LEVEL
;
475 if (st
->generic
.level
== RAW_FILEINFO_EA_LIST
) {
476 TRANS2_CHECK(ea_pull_name_list(&trans
->in
.data
, req
,
477 &st
->ea_list
.in
.num_names
,
478 &st
->ea_list
.in
.ea_names
));
482 op
->send_fn
= trans2_fileinfo_send
;
484 return ntvfs_qpathinfo(req
->ntvfs
, st
);
489 trans2 qpathinfo implementation
491 static NTSTATUS
trans2_qfileinfo(struct smbsrv_request
*req
, struct trans_op
*op
)
493 struct smb_trans2
*trans
= op
->trans
;
494 union smb_fileinfo
*st
;
496 struct ntvfs_handle
*h
;
498 /* make sure we got enough parameters */
499 if (trans
->in
.params
.length
< 4) {
500 return NT_STATUS_FOOBAR
;
503 st
= talloc(op
, union smb_fileinfo
);
504 NT_STATUS_HAVE_NO_MEMORY(st
);
506 h
= smbsrv_pull_fnum(req
, trans
->in
.params
.data
, 0);
507 level
= SVAL(trans
->in
.params
.data
, 2);
509 st
->generic
.in
.file
.ntvfs
= h
;
510 /* work out the backend level - we make it 1-1 in the header */
511 st
->generic
.level
= (enum smb_fileinfo_level
)level
;
512 if (st
->generic
.level
>= RAW_FILEINFO_GENERIC
) {
513 return NT_STATUS_INVALID_LEVEL
;
516 if (st
->generic
.level
== RAW_FILEINFO_EA_LIST
) {
517 TRANS2_CHECK(ea_pull_name_list(&trans
->in
.data
, req
,
518 &st
->ea_list
.in
.num_names
,
519 &st
->ea_list
.in
.ea_names
));
523 op
->send_fn
= trans2_fileinfo_send
;
525 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st
->generic
.in
.file
.ntvfs
);
526 return ntvfs_qfileinfo(req
->ntvfs
, st
);
531 parse a trans2 setfileinfo/setpathinfo data blob
533 static NTSTATUS
trans2_parse_sfileinfo(struct smbsrv_request
*req
,
534 union smb_setfileinfo
*st
,
535 const DATA_BLOB
*blob
)
537 enum smb_setfileinfo_level passthru_level
;
539 switch (st
->generic
.level
) {
540 case RAW_SFILEINFO_GENERIC
:
541 case RAW_SFILEINFO_SETATTR
:
542 case RAW_SFILEINFO_SETATTRE
:
543 case RAW_SFILEINFO_SEC_DESC
:
544 /* handled elsewhere */
545 return NT_STATUS_INVALID_LEVEL
;
547 case RAW_SFILEINFO_STANDARD
:
548 CHECK_MIN_BLOB_SIZE(blob
, 12);
550 st
->standard
.in
.create_time
= srv_pull_dos_date2(req
->smb_conn
, blob
->data
+ 0);
551 st
->standard
.in
.access_time
= srv_pull_dos_date2(req
->smb_conn
, blob
->data
+ 4);
552 st
->standard
.in
.write_time
= srv_pull_dos_date2(req
->smb_conn
, blob
->data
+ 8);
556 case RAW_SFILEINFO_EA_SET
:
557 return ea_pull_list(blob
, req
,
558 &st
->ea_set
.in
.num_eas
,
561 case SMB_SFILEINFO_BASIC_INFO
:
562 case SMB_SFILEINFO_BASIC_INFORMATION
:
563 passthru_level
= SMB_SFILEINFO_BASIC_INFORMATION
;
566 case SMB_SFILEINFO_DISPOSITION_INFO
:
567 case SMB_SFILEINFO_DISPOSITION_INFORMATION
:
568 passthru_level
= SMB_SFILEINFO_DISPOSITION_INFORMATION
;
571 case SMB_SFILEINFO_ALLOCATION_INFO
:
572 case SMB_SFILEINFO_ALLOCATION_INFORMATION
:
573 passthru_level
= SMB_SFILEINFO_ALLOCATION_INFORMATION
;
576 case RAW_SFILEINFO_END_OF_FILE_INFO
:
577 case RAW_SFILEINFO_END_OF_FILE_INFORMATION
:
578 passthru_level
= RAW_SFILEINFO_END_OF_FILE_INFORMATION
;
581 case RAW_SFILEINFO_RENAME_INFORMATION
:
582 case RAW_SFILEINFO_POSITION_INFORMATION
:
583 case RAW_SFILEINFO_MODE_INFORMATION
:
584 passthru_level
= st
->generic
.level
;
587 case RAW_SFILEINFO_UNIX_BASIC
:
588 case RAW_SFILEINFO_UNIX_LINK
:
589 case RAW_SFILEINFO_UNIX_HLINK
:
590 case RAW_SFILEINFO_1023
:
591 case RAW_SFILEINFO_1025
:
592 case RAW_SFILEINFO_1029
:
593 case RAW_SFILEINFO_1032
:
594 case RAW_SFILEINFO_1039
:
595 case RAW_SFILEINFO_1040
:
596 return NT_STATUS_INVALID_LEVEL
;
599 /* we need a default here to cope with invalid values on the wire */
600 return NT_STATUS_INVALID_LEVEL
;
603 return smbsrv_pull_passthru_sfileinfo(st
, passthru_level
, st
,
604 blob
, SMBSRV_REQ_DEFAULT_STR_FLAGS(req
),
609 trans2 setfileinfo implementation
611 static NTSTATUS
trans2_setfileinfo(struct smbsrv_request
*req
, struct trans_op
*op
)
613 struct smb_trans2
*trans
= op
->trans
;
614 union smb_setfileinfo
*st
;
616 struct ntvfs_handle
*h
;
618 /* make sure we got enough parameters */
619 if (trans
->in
.params
.length
< 4) {
620 return NT_STATUS_FOOBAR
;
623 st
= talloc(op
, union smb_setfileinfo
);
624 NT_STATUS_HAVE_NO_MEMORY(st
);
626 h
= smbsrv_pull_fnum(req
, trans
->in
.params
.data
, 0);
627 level
= SVAL(trans
->in
.params
.data
, 2);
629 st
->generic
.in
.file
.ntvfs
= h
;
630 /* work out the backend level - we make it 1-1 in the header */
631 st
->generic
.level
= (enum smb_setfileinfo_level
)level
;
632 if (st
->generic
.level
>= RAW_SFILEINFO_GENERIC
) {
633 return NT_STATUS_INVALID_LEVEL
;
636 TRANS2_CHECK(trans2_parse_sfileinfo(req
, st
, &trans
->in
.data
));
639 op
->send_fn
= trans2_simple_send
;
641 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st
->generic
.in
.file
.ntvfs
);
642 return ntvfs_setfileinfo(req
->ntvfs
, st
);
646 trans2 setpathinfo implementation
648 static NTSTATUS
trans2_setpathinfo(struct smbsrv_request
*req
, struct trans_op
*op
)
650 struct smb_trans2
*trans
= op
->trans
;
651 union smb_setfileinfo
*st
;
654 /* make sure we got enough parameters */
655 if (trans
->in
.params
.length
< 4) {
656 return NT_STATUS_FOOBAR
;
659 st
= talloc(op
, union smb_setfileinfo
);
660 NT_STATUS_HAVE_NO_MEMORY(st
);
662 level
= SVAL(trans
->in
.params
.data
, 0);
664 smbsrv_blob_pull_string(req
, &trans
->in
.params
, 6, &st
->generic
.in
.file
.path
, 0);
665 if (st
->generic
.in
.file
.path
== NULL
) {
666 return NT_STATUS_FOOBAR
;
669 /* work out the backend level - we make it 1-1 in the header */
670 st
->generic
.level
= (enum smb_setfileinfo_level
)level
;
671 if (st
->generic
.level
>= RAW_SFILEINFO_GENERIC
) {
672 return NT_STATUS_INVALID_LEVEL
;
675 TRANS2_CHECK(trans2_parse_sfileinfo(req
, st
, &trans
->in
.data
));
678 op
->send_fn
= trans2_simple_send
;
680 return ntvfs_setpathinfo(req
->ntvfs
, st
);
684 /* a structure to encapsulate the state information about an in-progress ffirst/fnext operation */
688 enum smb_search_data_level data_level
;
689 uint16_t last_entry_offset
;
694 fill a single entry in a trans2 find reply
696 static NTSTATUS
find_fill_info(struct find_state
*state
,
697 const union smb_search_data
*file
)
699 struct smbsrv_request
*req
= state
->op
->req
;
700 struct smb_trans2
*trans
= state
->op
->trans
;
702 uint_t ofs
= trans
->out
.data
.length
;
705 switch (state
->data_level
) {
706 case RAW_SEARCH_DATA_GENERIC
:
707 case RAW_SEARCH_DATA_SEARCH
:
708 /* handled elsewhere */
709 return NT_STATUS_INVALID_LEVEL
;
711 case RAW_SEARCH_DATA_STANDARD
:
712 if (state
->flags
& FLAG_TRANS2_FIND_REQUIRE_RESUME
) {
713 TRANS2_CHECK(smbsrv_blob_grow_data(trans
, &trans
->out
.data
, ofs
+ 27));
714 SIVAL(trans
->out
.data
.data
, ofs
, file
->standard
.resume_key
);
717 TRANS2_CHECK(smbsrv_blob_grow_data(trans
, &trans
->out
.data
, ofs
+ 23));
719 data
= trans
->out
.data
.data
+ ofs
;
720 srv_push_dos_date2(req
->smb_conn
, data
, 0, file
->standard
.create_time
);
721 srv_push_dos_date2(req
->smb_conn
, data
, 4, file
->standard
.access_time
);
722 srv_push_dos_date2(req
->smb_conn
, data
, 8, file
->standard
.write_time
);
723 SIVAL(data
, 12, file
->standard
.size
);
724 SIVAL(data
, 16, file
->standard
.alloc_size
);
725 SSVAL(data
, 20, file
->standard
.attrib
);
726 TRANS2_CHECK(smbsrv_blob_append_string(trans
, &trans
->out
.data
, file
->standard
.name
.s
,
727 ofs
+ 22, SMBSRV_REQ_DEFAULT_STR_FLAGS(req
),
728 STR_LEN8BIT
| STR_TERMINATE
| STR_LEN_NOTERM
));
731 case RAW_SEARCH_DATA_EA_SIZE
:
732 if (state
->flags
& FLAG_TRANS2_FIND_REQUIRE_RESUME
) {
733 TRANS2_CHECK(smbsrv_blob_grow_data(trans
, &trans
->out
.data
, ofs
+ 31));
734 SIVAL(trans
->out
.data
.data
, ofs
, file
->ea_size
.resume_key
);
737 TRANS2_CHECK(smbsrv_blob_grow_data(trans
, &trans
->out
.data
, ofs
+ 27));
739 data
= trans
->out
.data
.data
+ ofs
;
740 srv_push_dos_date2(req
->smb_conn
, data
, 0, file
->ea_size
.create_time
);
741 srv_push_dos_date2(req
->smb_conn
, data
, 4, file
->ea_size
.access_time
);
742 srv_push_dos_date2(req
->smb_conn
, data
, 8, file
->ea_size
.write_time
);
743 SIVAL(data
, 12, file
->ea_size
.size
);
744 SIVAL(data
, 16, file
->ea_size
.alloc_size
);
745 SSVAL(data
, 20, file
->ea_size
.attrib
);
746 SIVAL(data
, 22, file
->ea_size
.ea_size
);
747 TRANS2_CHECK(smbsrv_blob_append_string(trans
, &trans
->out
.data
, file
->ea_size
.name
.s
,
748 ofs
+ 26, SMBSRV_REQ_DEFAULT_STR_FLAGS(req
),
749 STR_LEN8BIT
| STR_NOALIGN
));
750 TRANS2_CHECK(smbsrv_blob_fill_data(trans
, &trans
->out
.data
, trans
->out
.data
.length
+ 1));
753 case RAW_SEARCH_DATA_EA_LIST
:
754 ea_size
= ea_list_size(file
->ea_list
.eas
.num_eas
, file
->ea_list
.eas
.eas
);
755 if (state
->flags
& FLAG_TRANS2_FIND_REQUIRE_RESUME
) {
756 TRANS2_CHECK(smbsrv_blob_grow_data(trans
, &trans
->out
.data
, ofs
+ 27 + ea_size
));
757 SIVAL(trans
->out
.data
.data
, ofs
, file
->ea_list
.resume_key
);
760 TRANS2_CHECK(smbsrv_blob_grow_data(trans
, &trans
->out
.data
, ofs
+ 23 + ea_size
));
762 data
= trans
->out
.data
.data
+ ofs
;
763 srv_push_dos_date2(req
->smb_conn
, data
, 0, file
->ea_list
.create_time
);
764 srv_push_dos_date2(req
->smb_conn
, data
, 4, file
->ea_list
.access_time
);
765 srv_push_dos_date2(req
->smb_conn
, data
, 8, file
->ea_list
.write_time
);
766 SIVAL(data
, 12, file
->ea_list
.size
);
767 SIVAL(data
, 16, file
->ea_list
.alloc_size
);
768 SSVAL(data
, 20, file
->ea_list
.attrib
);
769 ea_put_list(data
+22, file
->ea_list
.eas
.num_eas
, file
->ea_list
.eas
.eas
);
770 TRANS2_CHECK(smbsrv_blob_append_string(trans
, &trans
->out
.data
, file
->ea_list
.name
.s
,
771 ofs
+ 22 + ea_size
, SMBSRV_REQ_DEFAULT_STR_FLAGS(req
),
772 STR_LEN8BIT
| STR_NOALIGN
));
773 TRANS2_CHECK(smbsrv_blob_fill_data(trans
, &trans
->out
.data
, trans
->out
.data
.length
+ 1));
776 case RAW_SEARCH_DATA_DIRECTORY_INFO
:
777 case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO
:
778 case RAW_SEARCH_DATA_NAME_INFO
:
779 case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
:
780 case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO
:
781 case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO
:
782 return smbsrv_push_passthru_search(trans
, &trans
->out
.data
, state
->data_level
, file
,
783 SMBSRV_REQ_DEFAULT_STR_FLAGS(req
));
785 case RAW_SEARCH_DATA_UNIX_INFO
:
786 return NT_STATUS_INVALID_LEVEL
;
792 /* callback function for trans2 findfirst/findnext */
793 static bool find_callback(void *private, const union smb_search_data
*file
)
795 struct find_state
*state
= talloc_get_type(private, struct find_state
);
796 struct smb_trans2
*trans
= state
->op
->trans
;
799 old_length
= trans
->out
.data
.length
;
801 if (!NT_STATUS_IS_OK(find_fill_info(state
, file
)) ||
802 trans
->out
.data
.length
> trans
->in
.max_data
) {
803 /* restore the old length and tell the backend to stop */
804 smbsrv_blob_grow_data(trans
, &trans
->out
.data
, old_length
);
808 state
->last_entry_offset
= old_length
;
813 trans2 findfirst send
815 static NTSTATUS
trans2_findfirst_send(struct trans_op
*op
)
817 struct smbsrv_request
*req
= op
->req
;
818 struct smb_trans2
*trans
= op
->trans
;
819 union smb_search_first
*search
;
820 struct find_state
*state
;
823 TRANS2_CHECK_ASYNC_STATUS(state
, struct find_state
);
824 search
= talloc_get_type(state
->search
, union smb_search_first
);
826 /* fill in the findfirst reply header */
827 param
= trans
->out
.params
.data
;
828 SSVAL(param
, VWV(0), search
->t2ffirst
.out
.handle
);
829 SSVAL(param
, VWV(1), search
->t2ffirst
.out
.count
);
830 SSVAL(param
, VWV(2), search
->t2ffirst
.out
.end_of_search
);
831 SSVAL(param
, VWV(3), 0);
832 SSVAL(param
, VWV(4), state
->last_entry_offset
);
839 trans2 findfirst implementation
841 static NTSTATUS
trans2_findfirst(struct smbsrv_request
*req
, struct trans_op
*op
)
843 struct smb_trans2
*trans
= op
->trans
;
844 union smb_search_first
*search
;
846 struct find_state
*state
;
848 /* make sure we got all the parameters */
849 if (trans
->in
.params
.length
< 14) {
850 return NT_STATUS_FOOBAR
;
853 search
= talloc(op
, union smb_search_first
);
854 NT_STATUS_HAVE_NO_MEMORY(search
);
856 search
->t2ffirst
.in
.search_attrib
= SVAL(trans
->in
.params
.data
, 0);
857 search
->t2ffirst
.in
.max_count
= SVAL(trans
->in
.params
.data
, 2);
858 search
->t2ffirst
.in
.flags
= SVAL(trans
->in
.params
.data
, 4);
859 level
= SVAL(trans
->in
.params
.data
, 6);
860 search
->t2ffirst
.in
.storage_type
= IVAL(trans
->in
.params
.data
, 8);
862 smbsrv_blob_pull_string(req
, &trans
->in
.params
, 12, &search
->t2ffirst
.in
.pattern
, 0);
863 if (search
->t2ffirst
.in
.pattern
== NULL
) {
864 return NT_STATUS_FOOBAR
;
867 search
->t2ffirst
.level
= RAW_SEARCH_TRANS2
;
868 search
->t2ffirst
.data_level
= (enum smb_search_data_level
)level
;
869 if (search
->t2ffirst
.data_level
>= RAW_SEARCH_DATA_GENERIC
) {
870 return NT_STATUS_INVALID_LEVEL
;
873 if (search
->t2ffirst
.data_level
== RAW_SEARCH_DATA_EA_LIST
) {
874 TRANS2_CHECK(ea_pull_name_list(&trans
->in
.data
, req
,
875 &search
->t2ffirst
.in
.num_names
,
876 &search
->t2ffirst
.in
.ea_names
));
879 /* setup the private state structure that the backend will
880 give us in the callback */
881 state
= talloc(op
, struct find_state
);
882 NT_STATUS_HAVE_NO_MEMORY(state
);
884 state
->search
= search
;
885 state
->data_level
= search
->t2ffirst
.data_level
;
886 state
->last_entry_offset
= 0;
887 state
->flags
= search
->t2ffirst
.in
.flags
;
889 /* setup for just a header in the reply */
890 TRANS2_CHECK(trans2_setup_reply(trans
, 10, 0, 0));
893 op
->send_fn
= trans2_findfirst_send
;
895 return ntvfs_search_first(req
->ntvfs
, search
, state
, find_callback
);
902 static NTSTATUS
trans2_findnext_send(struct trans_op
*op
)
904 struct smbsrv_request
*req
= op
->req
;
905 struct smb_trans2
*trans
= op
->trans
;
906 union smb_search_next
*search
;
907 struct find_state
*state
;
910 TRANS2_CHECK_ASYNC_STATUS(state
, struct find_state
);
911 search
= talloc_get_type(state
->search
, union smb_search_next
);
913 /* fill in the findfirst reply header */
914 param
= trans
->out
.params
.data
;
915 SSVAL(param
, VWV(0), search
->t2fnext
.out
.count
);
916 SSVAL(param
, VWV(1), search
->t2fnext
.out
.end_of_search
);
917 SSVAL(param
, VWV(2), 0);
918 SSVAL(param
, VWV(3), state
->last_entry_offset
);
925 trans2 findnext implementation
927 static NTSTATUS
trans2_findnext(struct smbsrv_request
*req
, struct trans_op
*op
)
929 struct smb_trans2
*trans
= op
->trans
;
930 union smb_search_next
*search
;
932 struct find_state
*state
;
934 /* make sure we got all the parameters */
935 if (trans
->in
.params
.length
< 12) {
936 return NT_STATUS_FOOBAR
;
939 search
= talloc(op
, union smb_search_next
);
940 NT_STATUS_HAVE_NO_MEMORY(search
);
942 search
->t2fnext
.in
.handle
= SVAL(trans
->in
.params
.data
, 0);
943 search
->t2fnext
.in
.max_count
= SVAL(trans
->in
.params
.data
, 2);
944 level
= SVAL(trans
->in
.params
.data
, 4);
945 search
->t2fnext
.in
.resume_key
= IVAL(trans
->in
.params
.data
, 6);
946 search
->t2fnext
.in
.flags
= SVAL(trans
->in
.params
.data
, 10);
948 smbsrv_blob_pull_string(req
, &trans
->in
.params
, 12, &search
->t2fnext
.in
.last_name
, 0);
949 if (search
->t2fnext
.in
.last_name
== NULL
) {
950 return NT_STATUS_FOOBAR
;
953 search
->t2fnext
.level
= RAW_SEARCH_TRANS2
;
954 search
->t2fnext
.data_level
= (enum smb_search_data_level
)level
;
955 if (search
->t2fnext
.data_level
>= RAW_SEARCH_DATA_GENERIC
) {
956 return NT_STATUS_INVALID_LEVEL
;
959 if (search
->t2fnext
.data_level
== RAW_SEARCH_DATA_EA_LIST
) {
960 TRANS2_CHECK(ea_pull_name_list(&trans
->in
.data
, req
,
961 &search
->t2fnext
.in
.num_names
,
962 &search
->t2fnext
.in
.ea_names
));
965 /* setup the private state structure that the backend will give us in the callback */
966 state
= talloc(op
, struct find_state
);
967 NT_STATUS_HAVE_NO_MEMORY(state
);
969 state
->search
= search
;
970 state
->data_level
= search
->t2fnext
.data_level
;
971 state
->last_entry_offset
= 0;
972 state
->flags
= search
->t2fnext
.in
.flags
;
974 /* setup for just a header in the reply */
975 TRANS2_CHECK(trans2_setup_reply(trans
, 8, 0, 0));
978 op
->send_fn
= trans2_findnext_send
;
980 return ntvfs_search_next(req
->ntvfs
, search
, state
, find_callback
);
985 backend for trans2 requests
987 static NTSTATUS
trans2_backend(struct smbsrv_request
*req
, struct trans_op
*op
)
989 struct smb_trans2
*trans
= op
->trans
;
992 /* direct trans2 pass thru */
993 status
= ntvfs_trans2(req
->ntvfs
, trans
);
994 if (!NT_STATUS_EQUAL(NT_STATUS_NOT_IMPLEMENTED
, status
)) {
998 /* must have at least one setup word */
999 if (trans
->in
.setup_count
< 1) {
1000 return NT_STATUS_FOOBAR
;
1003 /* the trans2 command is in setup[0] */
1004 switch (trans
->in
.setup
[0]) {
1005 case TRANSACT2_FINDFIRST
:
1006 return trans2_findfirst(req
, op
);
1007 case TRANSACT2_FINDNEXT
:
1008 return trans2_findnext(req
, op
);
1009 case TRANSACT2_QPATHINFO
:
1010 return trans2_qpathinfo(req
, op
);
1011 case TRANSACT2_QFILEINFO
:
1012 return trans2_qfileinfo(req
, op
);
1013 case TRANSACT2_SETFILEINFO
:
1014 return trans2_setfileinfo(req
, op
);
1015 case TRANSACT2_SETPATHINFO
:
1016 return trans2_setpathinfo(req
, op
);
1017 case TRANSACT2_QFSINFO
:
1018 return trans2_qfsinfo(req
, op
);
1019 case TRANSACT2_OPEN
:
1020 return trans2_open(req
, op
);
1021 case TRANSACT2_MKDIR
:
1022 return trans2_mkdir(req
, op
);
1025 /* an unknown trans2 command */
1026 return NT_STATUS_FOOBAR
;
1031 send a continue request
1033 static void reply_trans_continue(struct smbsrv_request
*req
, uint8_t command
,
1034 struct smb_trans2
*trans
)
1036 struct smbsrv_trans_partial
*tp
;
1039 /* make sure they don't flood us */
1040 for (count
=0,tp
=req
->smb_conn
->trans_partial
;tp
;tp
=tp
->next
) count
++;
1042 smbsrv_send_error(req
, NT_STATUS_INSUFFICIENT_RESOURCES
);
1046 tp
= talloc(req
, struct smbsrv_trans_partial
);
1048 tp
->req
= talloc_reference(tp
, req
);
1050 tp
->command
= command
;
1052 DLIST_ADD(req
->smb_conn
->trans_partial
, tp
);
1054 /* send a 'please continue' reply */
1055 smbsrv_setup_reply(req
, 0, 0);
1056 smbsrv_send_reply(req
);
1061 answer a reconstructed trans request
1063 static void reply_trans_send(struct ntvfs_request
*ntvfs
)
1065 struct smbsrv_request
*req
;
1066 struct trans_op
*op
;
1067 struct smb_trans2
*trans
;
1068 uint16_t params_left
, data_left
;
1069 uint8_t *params
, *data
;
1072 SMBSRV_CHECK_ASYNC_STATUS_ERR(op
, struct trans_op
);
1075 /* if this function needs work to form the nttrans reply buffer, then
1077 if (op
->send_fn
!= NULL
) {
1079 status
= op
->send_fn(op
);
1080 if (!NT_STATUS_IS_OK(status
)) {
1081 smbsrv_send_error(req
, status
);
1086 params_left
= trans
->out
.params
.length
;
1087 data_left
= trans
->out
.data
.length
;
1088 params
= trans
->out
.params
.data
;
1089 data
= trans
->out
.data
.data
;
1091 smbsrv_setup_reply(req
, 10 + trans
->out
.setup_count
, 0);
1093 if (!NT_STATUS_IS_OK(req
->ntvfs
->async_states
->status
)) {
1094 smbsrv_setup_error(req
, req
->ntvfs
->async_states
->status
);
1097 /* we need to divide up the reply into chunks that fit into
1098 the negotiated buffer size */
1100 uint16_t this_data
, this_param
, max_bytes
;
1101 uint_t align1
= 1, align2
= (params_left
? 2 : 0);
1102 struct smbsrv_request
*this_req
;
1104 max_bytes
= req_max_data(req
) - (align1
+ align2
);
1106 this_param
= params_left
;
1107 if (this_param
> max_bytes
) {
1108 this_param
= max_bytes
;
1110 max_bytes
-= this_param
;
1112 this_data
= data_left
;
1113 if (this_data
> max_bytes
) {
1114 this_data
= max_bytes
;
1117 /* don't destroy unless this is the last chunk */
1118 if (params_left
- this_param
!= 0 ||
1119 data_left
- this_data
!= 0) {
1120 this_req
= smbsrv_setup_secondary_request(req
);
1125 req_grow_data(this_req
, this_param
+ this_data
+ (align1
+ align2
));
1127 SSVAL(this_req
->out
.vwv
, VWV(0), trans
->out
.params
.length
);
1128 SSVAL(this_req
->out
.vwv
, VWV(1), trans
->out
.data
.length
);
1129 SSVAL(this_req
->out
.vwv
, VWV(2), 0);
1131 SSVAL(this_req
->out
.vwv
, VWV(3), this_param
);
1132 SSVAL(this_req
->out
.vwv
, VWV(4), align1
+ PTR_DIFF(this_req
->out
.data
, this_req
->out
.hdr
));
1133 SSVAL(this_req
->out
.vwv
, VWV(5), PTR_DIFF(params
, trans
->out
.params
.data
));
1135 SSVAL(this_req
->out
.vwv
, VWV(6), this_data
);
1136 SSVAL(this_req
->out
.vwv
, VWV(7), align1
+ align2
+
1137 PTR_DIFF(this_req
->out
.data
+ this_param
, this_req
->out
.hdr
));
1138 SSVAL(this_req
->out
.vwv
, VWV(8), PTR_DIFF(data
, trans
->out
.data
.data
));
1140 SSVAL(this_req
->out
.vwv
, VWV(9), trans
->out
.setup_count
);
1141 for (i
=0;i
<trans
->out
.setup_count
;i
++) {
1142 SSVAL(this_req
->out
.vwv
, VWV(10+i
), trans
->out
.setup
[i
]);
1145 memset(this_req
->out
.data
, 0, align1
);
1146 if (this_param
!= 0) {
1147 memcpy(this_req
->out
.data
+ align1
, params
, this_param
);
1149 memset(this_req
->out
.data
+this_param
+align1
, 0, align2
);
1150 if (this_data
!= 0) {
1151 memcpy(this_req
->out
.data
+this_param
+align1
+align2
, data
, this_data
);
1154 params_left
-= this_param
;
1155 data_left
-= this_data
;
1156 params
+= this_param
;
1159 smbsrv_send_reply(this_req
);
1160 } while (params_left
!= 0 || data_left
!= 0);
1165 answer a reconstructed trans request
1167 static void reply_trans_complete(struct smbsrv_request
*req
, uint8_t command
,
1168 struct smb_trans2
*trans
)
1170 struct trans_op
*op
;
1172 SMBSRV_TALLOC_IO_PTR(op
, struct trans_op
);
1173 SMBSRV_SETUP_NTVFS_REQUEST(reply_trans_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
1177 op
->command
= command
;
1181 /* its a full request, give it to the backend */
1182 if (command
== SMBtrans
) {
1183 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_trans(req
->ntvfs
, trans
));
1186 SMBSRV_CALL_NTVFS_BACKEND(trans2_backend(req
, op
));
1192 Reply to an SMBtrans or SMBtrans2 request
1194 static void reply_trans_generic(struct smbsrv_request
*req
, uint8_t command
)
1196 struct smb_trans2
*trans
;
1198 uint16_t param_ofs
, data_ofs
;
1199 uint16_t param_count
, data_count
;
1200 uint16_t param_total
, data_total
;
1203 if (req
->in
.wct
< 14) {
1204 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
1208 trans
= talloc(req
, struct smb_trans2
);
1209 if (trans
== NULL
) {
1210 smbsrv_send_error(req
, NT_STATUS_NO_MEMORY
);
1214 param_total
= SVAL(req
->in
.vwv
, VWV(0));
1215 data_total
= SVAL(req
->in
.vwv
, VWV(1));
1216 trans
->in
.max_param
= SVAL(req
->in
.vwv
, VWV(2));
1217 trans
->in
.max_data
= SVAL(req
->in
.vwv
, VWV(3));
1218 trans
->in
.max_setup
= CVAL(req
->in
.vwv
, VWV(4));
1219 trans
->in
.flags
= SVAL(req
->in
.vwv
, VWV(5));
1220 trans
->in
.timeout
= IVAL(req
->in
.vwv
, VWV(6));
1221 param_count
= SVAL(req
->in
.vwv
, VWV(9));
1222 param_ofs
= SVAL(req
->in
.vwv
, VWV(10));
1223 data_count
= SVAL(req
->in
.vwv
, VWV(11));
1224 data_ofs
= SVAL(req
->in
.vwv
, VWV(12));
1225 trans
->in
.setup_count
= CVAL(req
->in
.vwv
, VWV(13));
1227 if (req
->in
.wct
!= 14 + trans
->in
.setup_count
) {
1228 smbsrv_send_error(req
, NT_STATUS_DOS(ERRSRV
, ERRerror
));
1232 /* parse out the setup words */
1233 trans
->in
.setup
= talloc_array(trans
, uint16_t, trans
->in
.setup_count
);
1234 if (trans
->in
.setup_count
&& !trans
->in
.setup
) {
1235 smbsrv_send_error(req
, NT_STATUS_NO_MEMORY
);
1238 for (i
=0;i
<trans
->in
.setup_count
;i
++) {
1239 trans
->in
.setup
[i
] = SVAL(req
->in
.vwv
, VWV(14+i
));
1242 if (command
== SMBtrans
) {
1243 req_pull_string(req
, &trans
->in
.trans_name
, req
->in
.data
, -1, STR_TERMINATE
);
1246 if (!req_pull_blob(req
, req
->in
.hdr
+ param_ofs
, param_count
, &trans
->in
.params
) ||
1247 !req_pull_blob(req
, req
->in
.hdr
+ data_ofs
, data_count
, &trans
->in
.data
)) {
1248 smbsrv_send_error(req
, NT_STATUS_FOOBAR
);
1252 /* is it a partial request? if so, then send a 'send more' message */
1253 if (param_total
> param_count
|| data_total
> data_count
) {
1254 reply_trans_continue(req
, command
, trans
);
1258 reply_trans_complete(req
, command
, trans
);
1263 Reply to an SMBtranss2 request
1265 static void reply_transs_generic(struct smbsrv_request
*req
, uint8_t command
)
1267 struct smbsrv_trans_partial
*tp
;
1268 struct smb_trans2
*trans
= NULL
;
1269 uint16_t param_ofs
, data_ofs
;
1270 uint16_t param_count
, data_count
;
1271 uint16_t param_disp
, data_disp
;
1272 uint16_t param_total
, data_total
;
1273 DATA_BLOB params
, data
;
1276 if (req
->in
.wct
< 8) {
1277 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
1281 for (tp
=req
->smb_conn
->trans_partial
;tp
;tp
=tp
->next
) {
1282 if (tp
->command
== command
&&
1283 SVAL(tp
->req
->in
.hdr
, HDR_MID
) == SVAL(req
->in
.hdr
, HDR_MID
)) {
1284 /* TODO: check the VUID, PID and TID too? */
1290 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
1296 param_total
= SVAL(req
->in
.vwv
, VWV(0));
1297 data_total
= SVAL(req
->in
.vwv
, VWV(1));
1298 param_count
= SVAL(req
->in
.vwv
, VWV(2));
1299 param_ofs
= SVAL(req
->in
.vwv
, VWV(3));
1300 param_disp
= SVAL(req
->in
.vwv
, VWV(4));
1301 data_count
= SVAL(req
->in
.vwv
, VWV(5));
1302 data_ofs
= SVAL(req
->in
.vwv
, VWV(6));
1303 data_disp
= SVAL(req
->in
.vwv
, VWV(7));
1305 if (!req_pull_blob(req
, req
->in
.hdr
+ param_ofs
, param_count
, ¶ms
) ||
1306 !req_pull_blob(req
, req
->in
.hdr
+ data_ofs
, data_count
, &data
)) {
1307 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
1311 /* only allow contiguous requests */
1312 if ((param_count
!= 0 &&
1313 param_disp
!= trans
->in
.params
.length
) ||
1315 data_disp
!= trans
->in
.data
.length
)) {
1316 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
1320 /* add to the existing request */
1321 if (param_count
!= 0) {
1322 trans
->in
.params
.data
= talloc_realloc(trans
,
1323 trans
->in
.params
.data
,
1325 param_disp
+ param_count
);
1326 if (trans
->in
.params
.data
== NULL
) {
1329 trans
->in
.params
.length
= param_disp
+ param_count
;
1332 if (data_count
!= 0) {
1333 trans
->in
.data
.data
= talloc_realloc(trans
,
1334 trans
->in
.data
.data
,
1336 data_disp
+ data_count
);
1337 if (trans
->in
.data
.data
== NULL
) {
1340 trans
->in
.data
.length
= data_disp
+ data_count
;
1343 memcpy(trans
->in
.params
.data
+ param_disp
, params
.data
, params
.length
);
1344 memcpy(trans
->in
.data
.data
+ data_disp
, data
.data
, data
.length
);
1346 /* the sequence number of the reply is taken from the last secondary
1348 tp
->req
->seq_num
= req
->seq_num
;
1350 /* we don't reply to Transs2 requests */
1353 if (trans
->in
.params
.length
== param_total
&&
1354 trans
->in
.data
.length
== data_total
) {
1355 /* its now complete */
1356 DLIST_REMOVE(tp
->req
->smb_conn
->trans_partial
, tp
);
1357 reply_trans_complete(tp
->req
, command
, trans
);
1362 smbsrv_send_error(tp
->req
, NT_STATUS_NO_MEMORY
);
1363 DLIST_REMOVE(req
->smb_conn
->trans_partial
, tp
);
1370 Reply to an SMBtrans2
1372 void smbsrv_reply_trans2(struct smbsrv_request
*req
)
1374 reply_trans_generic(req
, SMBtrans2
);
1378 Reply to an SMBtrans
1380 void smbsrv_reply_trans(struct smbsrv_request
*req
)
1382 reply_trans_generic(req
, SMBtrans
);
1386 Reply to an SMBtranss request
1388 void smbsrv_reply_transs(struct smbsrv_request
*req
)
1390 reply_transs_generic(req
, SMBtrans
);
1394 Reply to an SMBtranss2 request
1396 void smbsrv_reply_transs2(struct smbsrv_request
*req
)
1398 reply_transs_generic(req
, SMBtrans2
);