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 "smb_server/smb_server.h"
25 #include "ntvfs/ntvfs.h"
26 #include "libcli/raw/libcliraw.h"
27 #include "libcli/raw/raw_proto.h"
29 #define TRANS2_CHECK_ASYNC_STATUS_SIMPLE do { \
30 if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) { \
31 trans2_setup_reply(trans, 0, 0, 0);\
32 return req->ntvfs->async_states->status; \
35 #define TRANS2_CHECK_ASYNC_STATUS(ptr, type) do { \
36 TRANS2_CHECK_ASYNC_STATUS_SIMPLE; \
37 ptr = talloc_get_type(op->op_info, type); \
39 #define TRANS2_CHECK(cmd) do { \
42 NT_STATUS_NOT_OK_RETURN(_status); \
46 hold the state of a nttrans op while in progress. Needed to allow for async backend
50 struct smbsrv_request
*req
;
51 struct smb_trans2
*trans
;
53 NTSTATUS (*send_fn
)(struct trans_op
*);
57 #define CHECK_MIN_BLOB_SIZE(blob, size) do { \
58 if ((blob)->length < (size)) { \
59 return NT_STATUS_INFO_LENGTH_MISMATCH; \
62 /* setup a trans2 reply, given the data and params sizes */
63 static NTSTATUS
trans2_setup_reply(struct smb_trans2
*trans
,
64 uint16_t param_size
, uint16_t data_size
,
67 trans
->out
.setup_count
= setup_count
;
68 if (setup_count
> 0) {
69 trans
->out
.setup
= talloc_zero_array(trans
, uint16_t, setup_count
);
70 NT_STATUS_HAVE_NO_MEMORY(trans
->out
.setup
);
72 trans
->out
.params
= data_blob_talloc(trans
, NULL
, param_size
);
73 if (param_size
> 0) NT_STATUS_HAVE_NO_MEMORY(trans
->out
.params
.data
);
75 trans
->out
.data
= data_blob_talloc(trans
, NULL
, data_size
);
76 if (data_size
> 0) NT_STATUS_HAVE_NO_MEMORY(trans
->out
.data
.data
);
81 static NTSTATUS
trans2_push_fsinfo(struct smbsrv_connection
*smb_conn
,
84 union smb_fsinfo
*fsinfo
,
85 int default_str_flags
)
87 enum smb_fsinfo_level passthru_level
;
89 switch (fsinfo
->generic
.level
) {
90 case RAW_QFS_ALLOCATION
:
91 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx
, blob
, 18));
93 SIVAL(blob
->data
, 0, fsinfo
->allocation
.out
.fs_id
);
94 SIVAL(blob
->data
, 4, fsinfo
->allocation
.out
.sectors_per_unit
);
95 SIVAL(blob
->data
, 8, fsinfo
->allocation
.out
.total_alloc_units
);
96 SIVAL(blob
->data
, 12, fsinfo
->allocation
.out
.avail_alloc_units
);
97 SSVAL(blob
->data
, 16, fsinfo
->allocation
.out
.bytes_per_sector
);
102 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx
, blob
, 5));
104 SIVAL(blob
->data
, 0, fsinfo
->volume
.out
.serial_number
);
105 /* w2k3 implements this incorrectly for unicode - it
106 * leaves the last byte off the string */
107 TRANS2_CHECK(smbsrv_blob_append_string(mem_ctx
, blob
,
108 fsinfo
->volume
.out
.volume_name
.s
,
109 4, default_str_flags
,
110 STR_LEN8BIT
|STR_NOALIGN
));
114 case RAW_QFS_VOLUME_INFO
:
115 passthru_level
= RAW_QFS_VOLUME_INFORMATION
;
118 case RAW_QFS_SIZE_INFO
:
119 passthru_level
= RAW_QFS_SIZE_INFORMATION
;
122 case RAW_QFS_DEVICE_INFO
:
123 passthru_level
= RAW_QFS_DEVICE_INFORMATION
;
126 case RAW_QFS_ATTRIBUTE_INFO
:
127 passthru_level
= RAW_QFS_ATTRIBUTE_INFORMATION
;
131 passthru_level
= fsinfo
->generic
.level
;
135 return smbsrv_push_passthru_fsinfo(mem_ctx
, blob
,
136 passthru_level
, fsinfo
,
141 trans2 qfsinfo implementation send
143 static NTSTATUS
trans2_qfsinfo_send(struct trans_op
*op
)
145 struct smbsrv_request
*req
= op
->req
;
146 struct smb_trans2
*trans
= op
->trans
;
147 union smb_fsinfo
*fsinfo
;
149 TRANS2_CHECK_ASYNC_STATUS(fsinfo
, union smb_fsinfo
);
151 TRANS2_CHECK(trans2_setup_reply(trans
, 0, 0, 0));
153 TRANS2_CHECK(trans2_push_fsinfo(req
->smb_conn
, trans
,
154 &trans
->out
.data
, fsinfo
,
155 SMBSRV_REQ_DEFAULT_STR_FLAGS(req
)));
161 trans2 qfsinfo implementation
163 static NTSTATUS
trans2_qfsinfo(struct smbsrv_request
*req
, struct trans_op
*op
)
165 struct smb_trans2
*trans
= op
->trans
;
166 union smb_fsinfo
*fsinfo
;
169 /* make sure we got enough parameters */
170 if (trans
->in
.params
.length
!= 2) {
171 return NT_STATUS_FOOBAR
;
174 fsinfo
= talloc(op
, union smb_fsinfo
);
175 NT_STATUS_HAVE_NO_MEMORY(fsinfo
);
177 level
= SVAL(trans
->in
.params
.data
, 0);
179 /* work out the backend level - we make it 1-1 in the header */
180 fsinfo
->generic
.level
= (enum smb_fsinfo_level
)level
;
181 if (fsinfo
->generic
.level
>= RAW_QFS_GENERIC
) {
182 return NT_STATUS_INVALID_LEVEL
;
185 op
->op_info
= fsinfo
;
186 op
->send_fn
= trans2_qfsinfo_send
;
188 return ntvfs_fsinfo(req
->ntvfs
, fsinfo
);
193 trans2 open implementation send
195 static NTSTATUS
trans2_open_send(struct trans_op
*op
)
197 struct smbsrv_request
*req
= op
->req
;
198 struct smb_trans2
*trans
= op
->trans
;
201 TRANS2_CHECK_ASYNC_STATUS(io
, union smb_open
);
203 TRANS2_CHECK(trans2_setup_reply(trans
, 30, 0, 0));
205 smbsrv_push_fnum(trans
->out
.params
.data
, VWV(0), io
->t2open
.out
.file
.ntvfs
);
206 SSVAL(trans
->out
.params
.data
, VWV(1), io
->t2open
.out
.attrib
);
207 srv_push_dos_date3(req
->smb_conn
, trans
->out
.params
.data
,
208 VWV(2), io
->t2open
.out
.write_time
);
209 SIVAL(trans
->out
.params
.data
, VWV(4), io
->t2open
.out
.size
);
210 SSVAL(trans
->out
.params
.data
, VWV(6), io
->t2open
.out
.access
);
211 SSVAL(trans
->out
.params
.data
, VWV(7), io
->t2open
.out
.ftype
);
212 SSVAL(trans
->out
.params
.data
, VWV(8), io
->t2open
.out
.devstate
);
213 SSVAL(trans
->out
.params
.data
, VWV(9), io
->t2open
.out
.action
);
214 SIVAL(trans
->out
.params
.data
, VWV(10), 0); /* reserved */
215 SSVAL(trans
->out
.params
.data
, VWV(12), 0); /* EaErrorOffset */
216 SIVAL(trans
->out
.params
.data
, VWV(13), 0); /* EaLength */
222 trans2 open implementation
224 static NTSTATUS
trans2_open(struct smbsrv_request
*req
, struct trans_op
*op
)
226 struct smb_trans2
*trans
= op
->trans
;
229 /* make sure we got enough parameters */
230 if (trans
->in
.params
.length
< 29) {
231 return NT_STATUS_FOOBAR
;
234 io
= talloc(op
, union smb_open
);
235 NT_STATUS_HAVE_NO_MEMORY(io
);
237 io
->t2open
.level
= RAW_OPEN_T2OPEN
;
238 io
->t2open
.in
.flags
= SVAL(trans
->in
.params
.data
, VWV(0));
239 io
->t2open
.in
.open_mode
= SVAL(trans
->in
.params
.data
, VWV(1));
240 io
->t2open
.in
.search_attrs
= SVAL(trans
->in
.params
.data
, VWV(2));
241 io
->t2open
.in
.file_attrs
= SVAL(trans
->in
.params
.data
, VWV(3));
242 io
->t2open
.in
.write_time
= srv_pull_dos_date(req
->smb_conn
,
243 trans
->in
.params
.data
+ VWV(4));
244 io
->t2open
.in
.open_func
= SVAL(trans
->in
.params
.data
, VWV(6));
245 io
->t2open
.in
.size
= IVAL(trans
->in
.params
.data
, VWV(7));
246 io
->t2open
.in
.timeout
= IVAL(trans
->in
.params
.data
, VWV(9));
247 io
->t2open
.in
.num_eas
= 0;
248 io
->t2open
.in
.eas
= NULL
;
250 smbsrv_blob_pull_string(&req
->in
.bufinfo
, &trans
->in
.params
, 28, &io
->t2open
.in
.fname
, 0);
251 if (io
->t2open
.in
.fname
== NULL
) {
252 return NT_STATUS_FOOBAR
;
255 TRANS2_CHECK(ea_pull_list(&trans
->in
.data
, io
, &io
->t2open
.in
.num_eas
, &io
->t2open
.in
.eas
));
258 op
->send_fn
= trans2_open_send
;
260 return ntvfs_open(req
->ntvfs
, io
);
267 static NTSTATUS
trans2_simple_send(struct trans_op
*op
)
269 struct smbsrv_request
*req
= op
->req
;
270 struct smb_trans2
*trans
= op
->trans
;
272 TRANS2_CHECK_ASYNC_STATUS_SIMPLE
;
274 TRANS2_CHECK(trans2_setup_reply(trans
, 2, 0, 0));
276 SSVAL(trans
->out
.params
.data
, VWV(0), 0);
282 trans2 mkdir implementation
284 static NTSTATUS
trans2_mkdir(struct smbsrv_request
*req
, struct trans_op
*op
)
286 struct smb_trans2
*trans
= op
->trans
;
289 /* make sure we got enough parameters */
290 if (trans
->in
.params
.length
< 5) {
291 return NT_STATUS_FOOBAR
;
294 io
= talloc(op
, union smb_mkdir
);
295 NT_STATUS_HAVE_NO_MEMORY(io
);
297 io
->t2mkdir
.level
= RAW_MKDIR_T2MKDIR
;
298 smbsrv_blob_pull_string(&req
->in
.bufinfo
, &trans
->in
.params
, 4, &io
->t2mkdir
.in
.path
, 0);
299 if (io
->t2mkdir
.in
.path
== NULL
) {
300 return NT_STATUS_FOOBAR
;
303 TRANS2_CHECK(ea_pull_list(&trans
->in
.data
, io
,
304 &io
->t2mkdir
.in
.num_eas
,
305 &io
->t2mkdir
.in
.eas
));
308 op
->send_fn
= trans2_simple_send
;
310 return ntvfs_mkdir(req
->ntvfs
, io
);
313 static NTSTATUS
trans2_push_fileinfo(struct smbsrv_connection
*smb_conn
,
316 union smb_fileinfo
*st
,
317 int default_str_flags
)
320 enum smb_fileinfo_level passthru_level
;
322 switch (st
->generic
.level
) {
323 case RAW_FILEINFO_GENERIC
:
324 case RAW_FILEINFO_GETATTR
:
325 case RAW_FILEINFO_GETATTRE
:
326 case RAW_FILEINFO_SEC_DESC
:
327 case RAW_FILEINFO_SMB2_ALL_EAS
:
328 case RAW_FILEINFO_SMB2_ALL_INFORMATION
:
329 /* handled elsewhere */
330 return NT_STATUS_INVALID_LEVEL
;
332 case RAW_FILEINFO_UNIX_BASIC
:
333 case RAW_FILEINFO_UNIX_LINK
:
334 /* not implemented yet */
335 return NT_STATUS_INVALID_LEVEL
;
337 case RAW_FILEINFO_STANDARD
:
338 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx
, blob
, 22));
340 srv_push_dos_date2(smb_conn
, blob
->data
, 0, st
->standard
.out
.create_time
);
341 srv_push_dos_date2(smb_conn
, blob
->data
, 4, st
->standard
.out
.access_time
);
342 srv_push_dos_date2(smb_conn
, blob
->data
, 8, st
->standard
.out
.write_time
);
343 SIVAL(blob
->data
, 12, st
->standard
.out
.size
);
344 SIVAL(blob
->data
, 16, st
->standard
.out
.alloc_size
);
345 SSVAL(blob
->data
, 20, st
->standard
.out
.attrib
);
348 case RAW_FILEINFO_EA_SIZE
:
349 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx
, blob
, 26));
351 srv_push_dos_date2(smb_conn
, blob
->data
, 0, st
->ea_size
.out
.create_time
);
352 srv_push_dos_date2(smb_conn
, blob
->data
, 4, st
->ea_size
.out
.access_time
);
353 srv_push_dos_date2(smb_conn
, blob
->data
, 8, st
->ea_size
.out
.write_time
);
354 SIVAL(blob
->data
, 12, st
->ea_size
.out
.size
);
355 SIVAL(blob
->data
, 16, st
->ea_size
.out
.alloc_size
);
356 SSVAL(blob
->data
, 20, st
->ea_size
.out
.attrib
);
357 SIVAL(blob
->data
, 22, st
->ea_size
.out
.ea_size
);
360 case RAW_FILEINFO_EA_LIST
:
361 list_size
= ea_list_size(st
->ea_list
.out
.num_eas
,
362 st
->ea_list
.out
.eas
);
363 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx
, blob
, list_size
));
365 ea_put_list(blob
->data
,
366 st
->ea_list
.out
.num_eas
, st
->ea_list
.out
.eas
);
369 case RAW_FILEINFO_ALL_EAS
:
370 list_size
= ea_list_size(st
->all_eas
.out
.num_eas
,
371 st
->all_eas
.out
.eas
);
372 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx
, blob
, list_size
));
374 ea_put_list(blob
->data
,
375 st
->all_eas
.out
.num_eas
, st
->all_eas
.out
.eas
);
378 case RAW_FILEINFO_IS_NAME_VALID
:
381 case RAW_FILEINFO_BASIC_INFO
:
382 passthru_level
= RAW_FILEINFO_BASIC_INFORMATION
;
385 case RAW_FILEINFO_STANDARD_INFO
:
386 passthru_level
= RAW_FILEINFO_STANDARD_INFORMATION
;
389 case RAW_FILEINFO_EA_INFO
:
390 passthru_level
= RAW_FILEINFO_EA_INFORMATION
;
393 case RAW_FILEINFO_COMPRESSION_INFO
:
394 passthru_level
= RAW_FILEINFO_COMPRESSION_INFORMATION
;
397 case RAW_FILEINFO_ALL_INFO
:
398 passthru_level
= RAW_FILEINFO_ALL_INFORMATION
;
401 case RAW_FILEINFO_NAME_INFO
:
402 passthru_level
= RAW_FILEINFO_NAME_INFORMATION
;
405 case RAW_FILEINFO_ALT_NAME_INFO
:
406 passthru_level
= RAW_FILEINFO_ALT_NAME_INFORMATION
;
409 case RAW_FILEINFO_STREAM_INFO
:
410 passthru_level
= RAW_FILEINFO_STREAM_INFORMATION
;
414 passthru_level
= st
->generic
.level
;
418 return smbsrv_push_passthru_fileinfo(mem_ctx
, blob
,
424 fill in the reply from a qpathinfo or qfileinfo call
426 static NTSTATUS
trans2_fileinfo_send(struct trans_op
*op
)
428 struct smbsrv_request
*req
= op
->req
;
429 struct smb_trans2
*trans
= op
->trans
;
430 union smb_fileinfo
*st
;
432 TRANS2_CHECK_ASYNC_STATUS(st
, union smb_fileinfo
);
434 TRANS2_CHECK(trans2_setup_reply(trans
, 2, 0, 0));
435 SSVAL(trans
->out
.params
.data
, 0, 0);
437 TRANS2_CHECK(trans2_push_fileinfo(req
->smb_conn
, trans
,
438 &trans
->out
.data
, st
,
439 SMBSRV_REQ_DEFAULT_STR_FLAGS(req
)));
445 trans2 qpathinfo implementation
447 static NTSTATUS
trans2_qpathinfo(struct smbsrv_request
*req
, struct trans_op
*op
)
449 struct smb_trans2
*trans
= op
->trans
;
450 union smb_fileinfo
*st
;
453 /* make sure we got enough parameters */
454 if (trans
->in
.params
.length
< 2) {
455 return NT_STATUS_FOOBAR
;
458 st
= talloc(op
, union smb_fileinfo
);
459 NT_STATUS_HAVE_NO_MEMORY(st
);
461 level
= SVAL(trans
->in
.params
.data
, 0);
463 smbsrv_blob_pull_string(&req
->in
.bufinfo
, &trans
->in
.params
, 6, &st
->generic
.in
.file
.path
, 0);
464 if (st
->generic
.in
.file
.path
== NULL
) {
465 return NT_STATUS_FOOBAR
;
468 /* work out the backend level - we make it 1-1 in the header */
469 st
->generic
.level
= (enum smb_fileinfo_level
)level
;
470 if (st
->generic
.level
>= RAW_FILEINFO_GENERIC
) {
471 return NT_STATUS_INVALID_LEVEL
;
474 if (st
->generic
.level
== RAW_FILEINFO_EA_LIST
) {
475 TRANS2_CHECK(ea_pull_name_list(&trans
->in
.data
, req
,
476 &st
->ea_list
.in
.num_names
,
477 &st
->ea_list
.in
.ea_names
));
481 op
->send_fn
= trans2_fileinfo_send
;
483 return ntvfs_qpathinfo(req
->ntvfs
, st
);
488 trans2 qpathinfo implementation
490 static NTSTATUS
trans2_qfileinfo(struct smbsrv_request
*req
, struct trans_op
*op
)
492 struct smb_trans2
*trans
= op
->trans
;
493 union smb_fileinfo
*st
;
495 struct ntvfs_handle
*h
;
497 /* make sure we got enough parameters */
498 if (trans
->in
.params
.length
< 4) {
499 return NT_STATUS_FOOBAR
;
502 st
= talloc(op
, union smb_fileinfo
);
503 NT_STATUS_HAVE_NO_MEMORY(st
);
505 h
= smbsrv_pull_fnum(req
, trans
->in
.params
.data
, 0);
506 level
= SVAL(trans
->in
.params
.data
, 2);
508 st
->generic
.in
.file
.ntvfs
= h
;
509 /* work out the backend level - we make it 1-1 in the header */
510 st
->generic
.level
= (enum smb_fileinfo_level
)level
;
511 if (st
->generic
.level
>= RAW_FILEINFO_GENERIC
) {
512 return NT_STATUS_INVALID_LEVEL
;
515 if (st
->generic
.level
== RAW_FILEINFO_EA_LIST
) {
516 TRANS2_CHECK(ea_pull_name_list(&trans
->in
.data
, req
,
517 &st
->ea_list
.in
.num_names
,
518 &st
->ea_list
.in
.ea_names
));
522 op
->send_fn
= trans2_fileinfo_send
;
524 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st
->generic
.in
.file
.ntvfs
);
525 return ntvfs_qfileinfo(req
->ntvfs
, st
);
530 parse a trans2 setfileinfo/setpathinfo data blob
532 static NTSTATUS
trans2_parse_sfileinfo(struct smbsrv_request
*req
,
533 union smb_setfileinfo
*st
,
534 const DATA_BLOB
*blob
)
536 enum smb_setfileinfo_level passthru_level
;
538 switch (st
->generic
.level
) {
539 case RAW_SFILEINFO_GENERIC
:
540 case RAW_SFILEINFO_SETATTR
:
541 case RAW_SFILEINFO_SETATTRE
:
542 case RAW_SFILEINFO_SEC_DESC
:
543 /* handled elsewhere */
544 return NT_STATUS_INVALID_LEVEL
;
546 case RAW_SFILEINFO_STANDARD
:
547 CHECK_MIN_BLOB_SIZE(blob
, 12);
549 st
->standard
.in
.create_time
= srv_pull_dos_date2(req
->smb_conn
, blob
->data
+ 0);
550 st
->standard
.in
.access_time
= srv_pull_dos_date2(req
->smb_conn
, blob
->data
+ 4);
551 st
->standard
.in
.write_time
= srv_pull_dos_date2(req
->smb_conn
, blob
->data
+ 8);
555 case RAW_SFILEINFO_EA_SET
:
556 return ea_pull_list(blob
, req
,
557 &st
->ea_set
.in
.num_eas
,
560 case SMB_SFILEINFO_BASIC_INFO
:
561 case SMB_SFILEINFO_BASIC_INFORMATION
:
562 passthru_level
= SMB_SFILEINFO_BASIC_INFORMATION
;
565 case SMB_SFILEINFO_DISPOSITION_INFO
:
566 case SMB_SFILEINFO_DISPOSITION_INFORMATION
:
567 passthru_level
= SMB_SFILEINFO_DISPOSITION_INFORMATION
;
570 case SMB_SFILEINFO_ALLOCATION_INFO
:
571 case SMB_SFILEINFO_ALLOCATION_INFORMATION
:
572 passthru_level
= SMB_SFILEINFO_ALLOCATION_INFORMATION
;
575 case RAW_SFILEINFO_END_OF_FILE_INFO
:
576 case RAW_SFILEINFO_END_OF_FILE_INFORMATION
:
577 passthru_level
= RAW_SFILEINFO_END_OF_FILE_INFORMATION
;
580 case RAW_SFILEINFO_RENAME_INFORMATION
:
581 case RAW_SFILEINFO_POSITION_INFORMATION
:
582 case RAW_SFILEINFO_MODE_INFORMATION
:
583 passthru_level
= st
->generic
.level
;
586 case RAW_SFILEINFO_UNIX_BASIC
:
587 case RAW_SFILEINFO_UNIX_LINK
:
588 case RAW_SFILEINFO_UNIX_HLINK
:
589 case RAW_SFILEINFO_PIPE_INFORMATION
:
590 case RAW_SFILEINFO_VALID_DATA_INFORMATION
:
591 case RAW_SFILEINFO_SHORT_NAME_INFORMATION
:
592 case RAW_SFILEINFO_1025
:
593 case RAW_SFILEINFO_1027
:
594 case RAW_SFILEINFO_1029
:
595 case RAW_SFILEINFO_1030
:
596 case RAW_SFILEINFO_1031
:
597 case RAW_SFILEINFO_1032
:
598 case RAW_SFILEINFO_1036
:
599 case RAW_SFILEINFO_1041
:
600 case RAW_SFILEINFO_1042
:
601 case RAW_SFILEINFO_1043
:
602 case RAW_SFILEINFO_1044
:
603 return NT_STATUS_INVALID_LEVEL
;
606 /* we need a default here to cope with invalid values on the wire */
607 return NT_STATUS_INVALID_LEVEL
;
610 return smbsrv_pull_passthru_sfileinfo(st
, passthru_level
, st
,
611 blob
, SMBSRV_REQ_DEFAULT_STR_FLAGS(req
),
616 trans2 setfileinfo implementation
618 static NTSTATUS
trans2_setfileinfo(struct smbsrv_request
*req
, struct trans_op
*op
)
620 struct smb_trans2
*trans
= op
->trans
;
621 union smb_setfileinfo
*st
;
623 struct ntvfs_handle
*h
;
625 /* make sure we got enough parameters */
626 if (trans
->in
.params
.length
< 4) {
627 return NT_STATUS_FOOBAR
;
630 st
= talloc(op
, union smb_setfileinfo
);
631 NT_STATUS_HAVE_NO_MEMORY(st
);
633 h
= smbsrv_pull_fnum(req
, trans
->in
.params
.data
, 0);
634 level
= SVAL(trans
->in
.params
.data
, 2);
636 st
->generic
.in
.file
.ntvfs
= h
;
637 /* work out the backend level - we make it 1-1 in the header */
638 st
->generic
.level
= (enum smb_setfileinfo_level
)level
;
639 if (st
->generic
.level
>= RAW_SFILEINFO_GENERIC
) {
640 return NT_STATUS_INVALID_LEVEL
;
643 TRANS2_CHECK(trans2_parse_sfileinfo(req
, st
, &trans
->in
.data
));
646 op
->send_fn
= trans2_simple_send
;
648 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st
->generic
.in
.file
.ntvfs
);
649 return ntvfs_setfileinfo(req
->ntvfs
, st
);
653 trans2 setpathinfo implementation
655 static NTSTATUS
trans2_setpathinfo(struct smbsrv_request
*req
, struct trans_op
*op
)
657 struct smb_trans2
*trans
= op
->trans
;
658 union smb_setfileinfo
*st
;
661 /* make sure we got enough parameters */
662 if (trans
->in
.params
.length
< 4) {
663 return NT_STATUS_FOOBAR
;
666 st
= talloc(op
, union smb_setfileinfo
);
667 NT_STATUS_HAVE_NO_MEMORY(st
);
669 level
= SVAL(trans
->in
.params
.data
, 0);
671 smbsrv_blob_pull_string(&req
->in
.bufinfo
, &trans
->in
.params
, 6, &st
->generic
.in
.file
.path
, 0);
672 if (st
->generic
.in
.file
.path
== NULL
) {
673 return NT_STATUS_FOOBAR
;
676 /* work out the backend level - we make it 1-1 in the header */
677 st
->generic
.level
= (enum smb_setfileinfo_level
)level
;
678 if (st
->generic
.level
>= RAW_SFILEINFO_GENERIC
) {
679 return NT_STATUS_INVALID_LEVEL
;
682 TRANS2_CHECK(trans2_parse_sfileinfo(req
, st
, &trans
->in
.data
));
685 op
->send_fn
= trans2_simple_send
;
687 return ntvfs_setpathinfo(req
->ntvfs
, st
);
691 /* a structure to encapsulate the state information about an in-progress ffirst/fnext operation */
695 enum smb_search_data_level data_level
;
696 uint16_t last_entry_offset
;
701 fill a single entry in a trans2 find reply
703 static NTSTATUS
find_fill_info(struct find_state
*state
,
704 const union smb_search_data
*file
)
706 struct smbsrv_request
*req
= state
->op
->req
;
707 struct smb_trans2
*trans
= state
->op
->trans
;
709 uint_t ofs
= trans
->out
.data
.length
;
712 switch (state
->data_level
) {
713 case RAW_SEARCH_DATA_GENERIC
:
714 case RAW_SEARCH_DATA_SEARCH
:
715 /* handled elsewhere */
716 return NT_STATUS_INVALID_LEVEL
;
718 case RAW_SEARCH_DATA_STANDARD
:
719 if (state
->flags
& FLAG_TRANS2_FIND_REQUIRE_RESUME
) {
720 TRANS2_CHECK(smbsrv_blob_grow_data(trans
, &trans
->out
.data
, ofs
+ 27));
721 SIVAL(trans
->out
.data
.data
, ofs
, file
->standard
.resume_key
);
724 TRANS2_CHECK(smbsrv_blob_grow_data(trans
, &trans
->out
.data
, ofs
+ 23));
726 data
= trans
->out
.data
.data
+ ofs
;
727 srv_push_dos_date2(req
->smb_conn
, data
, 0, file
->standard
.create_time
);
728 srv_push_dos_date2(req
->smb_conn
, data
, 4, file
->standard
.access_time
);
729 srv_push_dos_date2(req
->smb_conn
, data
, 8, file
->standard
.write_time
);
730 SIVAL(data
, 12, file
->standard
.size
);
731 SIVAL(data
, 16, file
->standard
.alloc_size
);
732 SSVAL(data
, 20, file
->standard
.attrib
);
733 TRANS2_CHECK(smbsrv_blob_append_string(trans
, &trans
->out
.data
, file
->standard
.name
.s
,
734 ofs
+ 22, SMBSRV_REQ_DEFAULT_STR_FLAGS(req
),
735 STR_LEN8BIT
| STR_TERMINATE
| STR_LEN_NOTERM
));
738 case RAW_SEARCH_DATA_EA_SIZE
:
739 if (state
->flags
& FLAG_TRANS2_FIND_REQUIRE_RESUME
) {
740 TRANS2_CHECK(smbsrv_blob_grow_data(trans
, &trans
->out
.data
, ofs
+ 31));
741 SIVAL(trans
->out
.data
.data
, ofs
, file
->ea_size
.resume_key
);
744 TRANS2_CHECK(smbsrv_blob_grow_data(trans
, &trans
->out
.data
, ofs
+ 27));
746 data
= trans
->out
.data
.data
+ ofs
;
747 srv_push_dos_date2(req
->smb_conn
, data
, 0, file
->ea_size
.create_time
);
748 srv_push_dos_date2(req
->smb_conn
, data
, 4, file
->ea_size
.access_time
);
749 srv_push_dos_date2(req
->smb_conn
, data
, 8, file
->ea_size
.write_time
);
750 SIVAL(data
, 12, file
->ea_size
.size
);
751 SIVAL(data
, 16, file
->ea_size
.alloc_size
);
752 SSVAL(data
, 20, file
->ea_size
.attrib
);
753 SIVAL(data
, 22, file
->ea_size
.ea_size
);
754 TRANS2_CHECK(smbsrv_blob_append_string(trans
, &trans
->out
.data
, file
->ea_size
.name
.s
,
755 ofs
+ 26, SMBSRV_REQ_DEFAULT_STR_FLAGS(req
),
756 STR_LEN8BIT
| STR_NOALIGN
));
757 TRANS2_CHECK(smbsrv_blob_fill_data(trans
, &trans
->out
.data
, trans
->out
.data
.length
+ 1));
760 case RAW_SEARCH_DATA_EA_LIST
:
761 ea_size
= ea_list_size(file
->ea_list
.eas
.num_eas
, file
->ea_list
.eas
.eas
);
762 if (state
->flags
& FLAG_TRANS2_FIND_REQUIRE_RESUME
) {
763 TRANS2_CHECK(smbsrv_blob_grow_data(trans
, &trans
->out
.data
, ofs
+ 27 + ea_size
));
764 SIVAL(trans
->out
.data
.data
, ofs
, file
->ea_list
.resume_key
);
767 TRANS2_CHECK(smbsrv_blob_grow_data(trans
, &trans
->out
.data
, ofs
+ 23 + ea_size
));
769 data
= trans
->out
.data
.data
+ ofs
;
770 srv_push_dos_date2(req
->smb_conn
, data
, 0, file
->ea_list
.create_time
);
771 srv_push_dos_date2(req
->smb_conn
, data
, 4, file
->ea_list
.access_time
);
772 srv_push_dos_date2(req
->smb_conn
, data
, 8, file
->ea_list
.write_time
);
773 SIVAL(data
, 12, file
->ea_list
.size
);
774 SIVAL(data
, 16, file
->ea_list
.alloc_size
);
775 SSVAL(data
, 20, file
->ea_list
.attrib
);
776 ea_put_list(data
+22, file
->ea_list
.eas
.num_eas
, file
->ea_list
.eas
.eas
);
777 TRANS2_CHECK(smbsrv_blob_append_string(trans
, &trans
->out
.data
, file
->ea_list
.name
.s
,
778 ofs
+ 22 + ea_size
, SMBSRV_REQ_DEFAULT_STR_FLAGS(req
),
779 STR_LEN8BIT
| STR_NOALIGN
));
780 TRANS2_CHECK(smbsrv_blob_fill_data(trans
, &trans
->out
.data
, trans
->out
.data
.length
+ 1));
783 case RAW_SEARCH_DATA_DIRECTORY_INFO
:
784 case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO
:
785 case RAW_SEARCH_DATA_NAME_INFO
:
786 case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
:
787 case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO
:
788 case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO
:
789 return smbsrv_push_passthru_search(trans
, &trans
->out
.data
, state
->data_level
, file
,
790 SMBSRV_REQ_DEFAULT_STR_FLAGS(req
));
792 case RAW_SEARCH_DATA_UNIX_INFO
:
793 case RAW_SEARCH_DATA_UNIX_INFO2
:
794 return NT_STATUS_INVALID_LEVEL
;
800 /* callback function for trans2 findfirst/findnext */
801 static bool find_callback(void *private_data
, const union smb_search_data
*file
)
803 struct find_state
*state
= talloc_get_type(private_data
, struct find_state
);
804 struct smb_trans2
*trans
= state
->op
->trans
;
807 old_length
= trans
->out
.data
.length
;
809 if (!NT_STATUS_IS_OK(find_fill_info(state
, file
)) ||
810 trans
->out
.data
.length
> trans
->in
.max_data
) {
811 /* restore the old length and tell the backend to stop */
812 smbsrv_blob_grow_data(trans
, &trans
->out
.data
, old_length
);
816 state
->last_entry_offset
= old_length
;
821 trans2 findfirst send
823 static NTSTATUS
trans2_findfirst_send(struct trans_op
*op
)
825 struct smbsrv_request
*req
= op
->req
;
826 struct smb_trans2
*trans
= op
->trans
;
827 union smb_search_first
*search
;
828 struct find_state
*state
;
831 TRANS2_CHECK_ASYNC_STATUS(state
, struct find_state
);
832 search
= talloc_get_type(state
->search
, union smb_search_first
);
834 /* fill in the findfirst reply header */
835 param
= trans
->out
.params
.data
;
836 SSVAL(param
, VWV(0), search
->t2ffirst
.out
.handle
);
837 SSVAL(param
, VWV(1), search
->t2ffirst
.out
.count
);
838 SSVAL(param
, VWV(2), search
->t2ffirst
.out
.end_of_search
);
839 SSVAL(param
, VWV(3), 0);
840 SSVAL(param
, VWV(4), state
->last_entry_offset
);
847 trans2 findfirst implementation
849 static NTSTATUS
trans2_findfirst(struct smbsrv_request
*req
, struct trans_op
*op
)
851 struct smb_trans2
*trans
= op
->trans
;
852 union smb_search_first
*search
;
854 struct find_state
*state
;
856 /* make sure we got all the parameters */
857 if (trans
->in
.params
.length
< 14) {
858 return NT_STATUS_FOOBAR
;
861 search
= talloc(op
, union smb_search_first
);
862 NT_STATUS_HAVE_NO_MEMORY(search
);
864 search
->t2ffirst
.in
.search_attrib
= SVAL(trans
->in
.params
.data
, 0);
865 search
->t2ffirst
.in
.max_count
= SVAL(trans
->in
.params
.data
, 2);
866 search
->t2ffirst
.in
.flags
= SVAL(trans
->in
.params
.data
, 4);
867 level
= SVAL(trans
->in
.params
.data
, 6);
868 search
->t2ffirst
.in
.storage_type
= IVAL(trans
->in
.params
.data
, 8);
870 smbsrv_blob_pull_string(&req
->in
.bufinfo
, &trans
->in
.params
, 12, &search
->t2ffirst
.in
.pattern
, 0);
871 if (search
->t2ffirst
.in
.pattern
== NULL
) {
872 return NT_STATUS_FOOBAR
;
875 search
->t2ffirst
.level
= RAW_SEARCH_TRANS2
;
876 search
->t2ffirst
.data_level
= (enum smb_search_data_level
)level
;
877 if (search
->t2ffirst
.data_level
>= RAW_SEARCH_DATA_GENERIC
) {
878 return NT_STATUS_INVALID_LEVEL
;
881 if (search
->t2ffirst
.data_level
== RAW_SEARCH_DATA_EA_LIST
) {
882 TRANS2_CHECK(ea_pull_name_list(&trans
->in
.data
, req
,
883 &search
->t2ffirst
.in
.num_names
,
884 &search
->t2ffirst
.in
.ea_names
));
887 /* setup the private state structure that the backend will
888 give us in the callback */
889 state
= talloc(op
, struct find_state
);
890 NT_STATUS_HAVE_NO_MEMORY(state
);
892 state
->search
= search
;
893 state
->data_level
= search
->t2ffirst
.data_level
;
894 state
->last_entry_offset
= 0;
895 state
->flags
= search
->t2ffirst
.in
.flags
;
897 /* setup for just a header in the reply */
898 TRANS2_CHECK(trans2_setup_reply(trans
, 10, 0, 0));
901 op
->send_fn
= trans2_findfirst_send
;
903 return ntvfs_search_first(req
->ntvfs
, search
, state
, find_callback
);
910 static NTSTATUS
trans2_findnext_send(struct trans_op
*op
)
912 struct smbsrv_request
*req
= op
->req
;
913 struct smb_trans2
*trans
= op
->trans
;
914 union smb_search_next
*search
;
915 struct find_state
*state
;
918 TRANS2_CHECK_ASYNC_STATUS(state
, struct find_state
);
919 search
= talloc_get_type(state
->search
, union smb_search_next
);
921 /* fill in the findfirst reply header */
922 param
= trans
->out
.params
.data
;
923 SSVAL(param
, VWV(0), search
->t2fnext
.out
.count
);
924 SSVAL(param
, VWV(1), search
->t2fnext
.out
.end_of_search
);
925 SSVAL(param
, VWV(2), 0);
926 SSVAL(param
, VWV(3), state
->last_entry_offset
);
933 trans2 findnext implementation
935 static NTSTATUS
trans2_findnext(struct smbsrv_request
*req
, struct trans_op
*op
)
937 struct smb_trans2
*trans
= op
->trans
;
938 union smb_search_next
*search
;
940 struct find_state
*state
;
942 /* make sure we got all the parameters */
943 if (trans
->in
.params
.length
< 12) {
944 return NT_STATUS_FOOBAR
;
947 search
= talloc(op
, union smb_search_next
);
948 NT_STATUS_HAVE_NO_MEMORY(search
);
950 search
->t2fnext
.in
.handle
= SVAL(trans
->in
.params
.data
, 0);
951 search
->t2fnext
.in
.max_count
= SVAL(trans
->in
.params
.data
, 2);
952 level
= SVAL(trans
->in
.params
.data
, 4);
953 search
->t2fnext
.in
.resume_key
= IVAL(trans
->in
.params
.data
, 6);
954 search
->t2fnext
.in
.flags
= SVAL(trans
->in
.params
.data
, 10);
956 smbsrv_blob_pull_string(&req
->in
.bufinfo
, &trans
->in
.params
, 12, &search
->t2fnext
.in
.last_name
, 0);
957 if (search
->t2fnext
.in
.last_name
== NULL
) {
958 return NT_STATUS_FOOBAR
;
961 search
->t2fnext
.level
= RAW_SEARCH_TRANS2
;
962 search
->t2fnext
.data_level
= (enum smb_search_data_level
)level
;
963 if (search
->t2fnext
.data_level
>= RAW_SEARCH_DATA_GENERIC
) {
964 return NT_STATUS_INVALID_LEVEL
;
967 if (search
->t2fnext
.data_level
== RAW_SEARCH_DATA_EA_LIST
) {
968 TRANS2_CHECK(ea_pull_name_list(&trans
->in
.data
, req
,
969 &search
->t2fnext
.in
.num_names
,
970 &search
->t2fnext
.in
.ea_names
));
973 /* setup the private state structure that the backend will give us in the callback */
974 state
= talloc(op
, struct find_state
);
975 NT_STATUS_HAVE_NO_MEMORY(state
);
977 state
->search
= search
;
978 state
->data_level
= search
->t2fnext
.data_level
;
979 state
->last_entry_offset
= 0;
980 state
->flags
= search
->t2fnext
.in
.flags
;
982 /* setup for just a header in the reply */
983 TRANS2_CHECK(trans2_setup_reply(trans
, 8, 0, 0));
986 op
->send_fn
= trans2_findnext_send
;
988 return ntvfs_search_next(req
->ntvfs
, search
, state
, find_callback
);
993 backend for trans2 requests
995 static NTSTATUS
trans2_backend(struct smbsrv_request
*req
, struct trans_op
*op
)
997 struct smb_trans2
*trans
= op
->trans
;
1000 /* direct trans2 pass thru */
1001 status
= ntvfs_trans2(req
->ntvfs
, trans
);
1002 if (!NT_STATUS_EQUAL(NT_STATUS_NOT_IMPLEMENTED
, status
)) {
1006 /* must have at least one setup word */
1007 if (trans
->in
.setup_count
< 1) {
1008 return NT_STATUS_FOOBAR
;
1011 /* the trans2 command is in setup[0] */
1012 switch (trans
->in
.setup
[0]) {
1013 case TRANSACT2_FINDFIRST
:
1014 return trans2_findfirst(req
, op
);
1015 case TRANSACT2_FINDNEXT
:
1016 return trans2_findnext(req
, op
);
1017 case TRANSACT2_QPATHINFO
:
1018 return trans2_qpathinfo(req
, op
);
1019 case TRANSACT2_QFILEINFO
:
1020 return trans2_qfileinfo(req
, op
);
1021 case TRANSACT2_SETFILEINFO
:
1022 return trans2_setfileinfo(req
, op
);
1023 case TRANSACT2_SETPATHINFO
:
1024 return trans2_setpathinfo(req
, op
);
1025 case TRANSACT2_QFSINFO
:
1026 return trans2_qfsinfo(req
, op
);
1027 case TRANSACT2_OPEN
:
1028 return trans2_open(req
, op
);
1029 case TRANSACT2_MKDIR
:
1030 return trans2_mkdir(req
, op
);
1033 /* an unknown trans2 command */
1034 return NT_STATUS_FOOBAR
;
1037 int smbsrv_trans_partial_destructor(struct smbsrv_trans_partial
*tp
)
1039 DLIST_REMOVE(tp
->req
->smb_conn
->trans_partial
, tp
);
1045 send a continue request
1047 static void reply_trans_continue(struct smbsrv_request
*req
, uint8_t command
,
1048 struct smb_trans2
*trans
)
1050 struct smbsrv_request
*req2
;
1051 struct smbsrv_trans_partial
*tp
;
1054 /* make sure they don't flood us */
1055 for (count
=0,tp
=req
->smb_conn
->trans_partial
;tp
;tp
=tp
->next
) count
++;
1057 smbsrv_send_error(req
, NT_STATUS_INSUFFICIENT_RESOURCES
);
1061 tp
= talloc(req
, struct smbsrv_trans_partial
);
1064 tp
->u
.trans
= trans
;
1065 tp
->command
= command
;
1067 DLIST_ADD(req
->smb_conn
->trans_partial
, tp
);
1068 talloc_set_destructor(tp
, smbsrv_trans_partial_destructor
);
1070 req2
= smbsrv_setup_secondary_request(req
);
1072 /* send a 'please continue' reply */
1073 smbsrv_setup_reply(req2
, 0, 0);
1074 smbsrv_send_reply(req2
);
1079 answer a reconstructed trans request
1081 static void reply_trans_send(struct ntvfs_request
*ntvfs
)
1083 struct smbsrv_request
*req
;
1084 struct trans_op
*op
;
1085 struct smb_trans2
*trans
;
1086 uint16_t params_left
, data_left
;
1087 uint8_t *params
, *data
;
1090 SMBSRV_CHECK_ASYNC_STATUS_ERR(op
, struct trans_op
);
1093 /* if this function needs work to form the nttrans reply buffer, then
1095 if (op
->send_fn
!= NULL
) {
1097 status
= op
->send_fn(op
);
1098 if (!NT_STATUS_IS_OK(status
)) {
1099 smbsrv_send_error(req
, status
);
1104 params_left
= trans
->out
.params
.length
;
1105 data_left
= trans
->out
.data
.length
;
1106 params
= trans
->out
.params
.data
;
1107 data
= trans
->out
.data
.data
;
1109 smbsrv_setup_reply(req
, 10 + trans
->out
.setup_count
, 0);
1111 if (!NT_STATUS_IS_OK(req
->ntvfs
->async_states
->status
)) {
1112 smbsrv_setup_error(req
, req
->ntvfs
->async_states
->status
);
1115 /* we need to divide up the reply into chunks that fit into
1116 the negotiated buffer size */
1118 uint16_t this_data
, this_param
, max_bytes
;
1119 uint_t align1
= 1, align2
= (params_left
? 2 : 0);
1120 struct smbsrv_request
*this_req
;
1122 max_bytes
= req_max_data(req
) - (align1
+ align2
);
1124 this_param
= params_left
;
1125 if (this_param
> max_bytes
) {
1126 this_param
= max_bytes
;
1128 max_bytes
-= this_param
;
1130 this_data
= data_left
;
1131 if (this_data
> max_bytes
) {
1132 this_data
= max_bytes
;
1135 /* don't destroy unless this is the last chunk */
1136 if (params_left
- this_param
!= 0 ||
1137 data_left
- this_data
!= 0) {
1138 this_req
= smbsrv_setup_secondary_request(req
);
1143 req_grow_data(this_req
, this_param
+ this_data
+ (align1
+ align2
));
1145 SSVAL(this_req
->out
.vwv
, VWV(0), trans
->out
.params
.length
);
1146 SSVAL(this_req
->out
.vwv
, VWV(1), trans
->out
.data
.length
);
1147 SSVAL(this_req
->out
.vwv
, VWV(2), 0);
1149 SSVAL(this_req
->out
.vwv
, VWV(3), this_param
);
1150 SSVAL(this_req
->out
.vwv
, VWV(4), align1
+ PTR_DIFF(this_req
->out
.data
, this_req
->out
.hdr
));
1151 SSVAL(this_req
->out
.vwv
, VWV(5), PTR_DIFF(params
, trans
->out
.params
.data
));
1153 SSVAL(this_req
->out
.vwv
, VWV(6), this_data
);
1154 SSVAL(this_req
->out
.vwv
, VWV(7), align1
+ align2
+
1155 PTR_DIFF(this_req
->out
.data
+ this_param
, this_req
->out
.hdr
));
1156 SSVAL(this_req
->out
.vwv
, VWV(8), PTR_DIFF(data
, trans
->out
.data
.data
));
1158 SCVAL(this_req
->out
.vwv
, VWV(9), trans
->out
.setup_count
);
1159 SCVAL(this_req
->out
.vwv
, VWV(9)+1, 0); /* reserved */
1160 for (i
=0;i
<trans
->out
.setup_count
;i
++) {
1161 SSVAL(this_req
->out
.vwv
, VWV(10+i
), trans
->out
.setup
[i
]);
1164 memset(this_req
->out
.data
, 0, align1
);
1165 if (this_param
!= 0) {
1166 memcpy(this_req
->out
.data
+ align1
, params
, this_param
);
1168 memset(this_req
->out
.data
+this_param
+align1
, 0, align2
);
1169 if (this_data
!= 0) {
1170 memcpy(this_req
->out
.data
+this_param
+align1
+align2
, data
, this_data
);
1173 params_left
-= this_param
;
1174 data_left
-= this_data
;
1175 params
+= this_param
;
1178 smbsrv_send_reply(this_req
);
1179 } while (params_left
!= 0 || data_left
!= 0);
1184 answer a reconstructed trans request
1186 static void reply_trans_complete(struct smbsrv_request
*req
, uint8_t command
,
1187 struct smb_trans2
*trans
)
1189 struct trans_op
*op
;
1191 SMBSRV_TALLOC_IO_PTR(op
, struct trans_op
);
1192 SMBSRV_SETUP_NTVFS_REQUEST(reply_trans_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
1196 op
->command
= command
;
1200 /* its a full request, give it to the backend */
1201 if (command
== SMBtrans
) {
1202 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_trans(req
->ntvfs
, trans
));
1205 SMBSRV_CALL_NTVFS_BACKEND(trans2_backend(req
, op
));
1211 Reply to an SMBtrans or SMBtrans2 request
1213 static void reply_trans_generic(struct smbsrv_request
*req
, uint8_t command
)
1215 struct smb_trans2
*trans
;
1217 uint16_t param_ofs
, data_ofs
;
1218 uint16_t param_count
, data_count
;
1219 uint16_t param_total
, data_total
;
1222 if (req
->in
.wct
< 14) {
1223 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
1227 trans
= talloc(req
, struct smb_trans2
);
1228 if (trans
== NULL
) {
1229 smbsrv_send_error(req
, NT_STATUS_NO_MEMORY
);
1233 param_total
= SVAL(req
->in
.vwv
, VWV(0));
1234 data_total
= SVAL(req
->in
.vwv
, VWV(1));
1235 trans
->in
.max_param
= SVAL(req
->in
.vwv
, VWV(2));
1236 trans
->in
.max_data
= SVAL(req
->in
.vwv
, VWV(3));
1237 trans
->in
.max_setup
= CVAL(req
->in
.vwv
, VWV(4));
1238 trans
->in
.flags
= SVAL(req
->in
.vwv
, VWV(5));
1239 trans
->in
.timeout
= IVAL(req
->in
.vwv
, VWV(6));
1240 param_count
= SVAL(req
->in
.vwv
, VWV(9));
1241 param_ofs
= SVAL(req
->in
.vwv
, VWV(10));
1242 data_count
= SVAL(req
->in
.vwv
, VWV(11));
1243 data_ofs
= SVAL(req
->in
.vwv
, VWV(12));
1244 trans
->in
.setup_count
= CVAL(req
->in
.vwv
, VWV(13));
1246 if (req
->in
.wct
!= 14 + trans
->in
.setup_count
) {
1247 smbsrv_send_error(req
, NT_STATUS_DOS(ERRSRV
, ERRerror
));
1251 /* parse out the setup words */
1252 trans
->in
.setup
= talloc_array(trans
, uint16_t, trans
->in
.setup_count
);
1253 if (trans
->in
.setup_count
&& !trans
->in
.setup
) {
1254 smbsrv_send_error(req
, NT_STATUS_NO_MEMORY
);
1257 for (i
=0;i
<trans
->in
.setup_count
;i
++) {
1258 trans
->in
.setup
[i
] = SVAL(req
->in
.vwv
, VWV(14+i
));
1261 if (command
== SMBtrans
) {
1262 req_pull_string(&req
->in
.bufinfo
, &trans
->in
.trans_name
, req
->in
.data
, -1, STR_TERMINATE
);
1265 if (!req_pull_blob(&req
->in
.bufinfo
, req
->in
.hdr
+ param_ofs
, param_count
, &trans
->in
.params
) ||
1266 !req_pull_blob(&req
->in
.bufinfo
, req
->in
.hdr
+ data_ofs
, data_count
, &trans
->in
.data
)) {
1267 smbsrv_send_error(req
, NT_STATUS_FOOBAR
);
1271 /* is it a partial request? if so, then send a 'send more' message */
1272 if (param_total
> param_count
|| data_total
> data_count
) {
1273 reply_trans_continue(req
, command
, trans
);
1277 reply_trans_complete(req
, command
, trans
);
1282 Reply to an SMBtranss2 request
1284 static void reply_transs_generic(struct smbsrv_request
*req
, uint8_t command
)
1286 struct smbsrv_trans_partial
*tp
;
1287 struct smb_trans2
*trans
= NULL
;
1288 uint16_t param_ofs
, data_ofs
;
1289 uint16_t param_count
, data_count
;
1290 uint16_t param_disp
, data_disp
;
1291 uint16_t param_total
, data_total
;
1292 DATA_BLOB params
, data
;
1295 if (command
== SMBtrans2
) {
1302 if (req
->in
.wct
!= wct
) {
1304 * TODO: add some error code tests
1305 * w2k3 returns NT_STATUS_DOS(ERRSRV, ERRerror) here
1307 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
1311 for (tp
=req
->smb_conn
->trans_partial
;tp
;tp
=tp
->next
) {
1312 if (tp
->command
== command
&&
1313 SVAL(tp
->req
->in
.hdr
, HDR_MID
) == SVAL(req
->in
.hdr
, HDR_MID
)) {
1314 /* TODO: check the VUID, PID and TID too? */
1320 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
1324 trans
= tp
->u
.trans
;
1326 param_total
= SVAL(req
->in
.vwv
, VWV(0));
1327 data_total
= SVAL(req
->in
.vwv
, VWV(1));
1328 param_count
= SVAL(req
->in
.vwv
, VWV(2));
1329 param_ofs
= SVAL(req
->in
.vwv
, VWV(3));
1330 param_disp
= SVAL(req
->in
.vwv
, VWV(4));
1331 data_count
= SVAL(req
->in
.vwv
, VWV(5));
1332 data_ofs
= SVAL(req
->in
.vwv
, VWV(6));
1333 data_disp
= SVAL(req
->in
.vwv
, VWV(7));
1335 if (!req_pull_blob(&req
->in
.bufinfo
, req
->in
.hdr
+ param_ofs
, param_count
, ¶ms
) ||
1336 !req_pull_blob(&req
->in
.bufinfo
, req
->in
.hdr
+ data_ofs
, data_count
, &data
)) {
1337 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
1341 /* only allow contiguous requests */
1342 if ((param_count
!= 0 &&
1343 param_disp
!= trans
->in
.params
.length
) ||
1345 data_disp
!= trans
->in
.data
.length
)) {
1346 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
1350 /* add to the existing request */
1351 if (param_count
!= 0) {
1352 trans
->in
.params
.data
= talloc_realloc(trans
,
1353 trans
->in
.params
.data
,
1355 param_disp
+ param_count
);
1356 if (trans
->in
.params
.data
== NULL
) {
1357 smbsrv_send_error(tp
->req
, NT_STATUS_NO_MEMORY
);
1360 trans
->in
.params
.length
= param_disp
+ param_count
;
1363 if (data_count
!= 0) {
1364 trans
->in
.data
.data
= talloc_realloc(trans
,
1365 trans
->in
.data
.data
,
1367 data_disp
+ data_count
);
1368 if (trans
->in
.data
.data
== NULL
) {
1369 smbsrv_send_error(tp
->req
, NT_STATUS_NO_MEMORY
);
1372 trans
->in
.data
.length
= data_disp
+ data_count
;
1375 memcpy(trans
->in
.params
.data
+ param_disp
, params
.data
, params
.length
);
1376 memcpy(trans
->in
.data
.data
+ data_disp
, data
.data
, data
.length
);
1378 /* the sequence number of the reply is taken from the last secondary
1380 tp
->req
->seq_num
= req
->seq_num
;
1382 /* we don't reply to Transs2 requests */
1385 if (trans
->in
.params
.length
== param_total
&&
1386 trans
->in
.data
.length
== data_total
) {
1387 /* its now complete */
1390 reply_trans_complete(req
, command
, trans
);
1397 Reply to an SMBtrans2
1399 void smbsrv_reply_trans2(struct smbsrv_request
*req
)
1401 reply_trans_generic(req
, SMBtrans2
);
1405 Reply to an SMBtrans
1407 void smbsrv_reply_trans(struct smbsrv_request
*req
)
1409 reply_trans_generic(req
, SMBtrans
);
1413 Reply to an SMBtranss request
1415 void smbsrv_reply_transs(struct smbsrv_request
*req
)
1417 reply_transs_generic(req
, SMBtrans
);
1421 Reply to an SMBtranss2 request
1423 void smbsrv_reply_transs2(struct smbsrv_request
*req
)
1425 reply_transs_generic(req
, SMBtrans2
);