2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 2003
5 Copyright Matthieu Patou <mat@matws.net> 2010-2011
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 This file handles the parsing of transact2 requests
25 #include "samba/service_stream.h"
26 #include "smb_server/smb_server.h"
27 #include "ntvfs/ntvfs.h"
28 #include "libcli/raw/libcliraw.h"
29 #include "libcli/raw/raw_proto.h"
30 #include "librpc/gen_ndr/dfsblobs.h"
31 #include "librpc/gen_ndr/ndr_dfsblobs.h"
32 #include "dsdb/samdb/samdb.h"
33 #include "auth/session.h"
34 #include "param/param.h"
35 #include "lib/tsocket/tsocket.h"
36 #include "dfs_server/dfs_server_ad.h"
38 #define MAX_DFS_RESPONSE 56*1024 /* 56 Kb */
40 #define TRANS2_CHECK_ASYNC_STATUS_SIMPLE do { \
41 if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) { \
42 trans2_setup_reply(trans, 0, 0, 0);\
43 return req->ntvfs->async_states->status; \
46 #define TRANS2_CHECK_ASYNC_STATUS(ptr, type) do { \
47 TRANS2_CHECK_ASYNC_STATUS_SIMPLE; \
48 ptr = talloc_get_type(op->op_info, type); \
50 #define TRANS2_CHECK(cmd) do { \
53 NT_STATUS_NOT_OK_RETURN(_status); \
57 hold the state of a nttrans op while in progress. Needed to allow for async backend
61 struct smbsrv_request
*req
;
62 struct smb_trans2
*trans
;
64 NTSTATUS (*send_fn
)(struct trans_op
*);
68 #define CHECK_MIN_BLOB_SIZE(blob, size) do { \
69 if ((blob)->length < (size)) { \
70 return NT_STATUS_INFO_LENGTH_MISMATCH; \
73 /* setup a trans2 reply, given the data and params sizes */
74 static NTSTATUS
trans2_setup_reply(struct smb_trans2
*trans
,
75 uint16_t param_size
, uint16_t data_size
,
78 trans
->out
.setup_count
= setup_count
;
79 if (setup_count
> 0) {
80 trans
->out
.setup
= talloc_zero_array(trans
, uint16_t, setup_count
);
81 NT_STATUS_HAVE_NO_MEMORY(trans
->out
.setup
);
83 trans
->out
.params
= data_blob_talloc(trans
, NULL
, param_size
);
84 if (param_size
> 0) NT_STATUS_HAVE_NO_MEMORY(trans
->out
.params
.data
);
86 trans
->out
.data
= data_blob_talloc(trans
, NULL
, data_size
);
87 if (data_size
> 0) NT_STATUS_HAVE_NO_MEMORY(trans
->out
.data
.data
);
92 static NTSTATUS
trans2_push_fsinfo(struct smbsrv_connection
*smb_conn
,
95 union smb_fsinfo
*fsinfo
,
96 int default_str_flags
)
98 enum smb_fsinfo_level passthru_level
;
100 switch (fsinfo
->generic
.level
) {
101 case RAW_QFS_ALLOCATION
:
102 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx
, blob
, 18));
104 SIVAL(blob
->data
, 0, fsinfo
->allocation
.out
.fs_id
);
105 SIVAL(blob
->data
, 4, fsinfo
->allocation
.out
.sectors_per_unit
);
106 SIVAL(blob
->data
, 8, fsinfo
->allocation
.out
.total_alloc_units
);
107 SIVAL(blob
->data
, 12, fsinfo
->allocation
.out
.avail_alloc_units
);
108 SSVAL(blob
->data
, 16, fsinfo
->allocation
.out
.bytes_per_sector
);
113 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx
, blob
, 5));
115 SIVAL(blob
->data
, 0, fsinfo
->volume
.out
.serial_number
);
116 /* w2k3 implements this incorrectly for unicode - it
117 * leaves the last byte off the string */
118 TRANS2_CHECK(smbsrv_blob_append_string(mem_ctx
, blob
,
119 fsinfo
->volume
.out
.volume_name
.s
,
120 4, default_str_flags
,
121 STR_LEN8BIT
|STR_NOALIGN
));
125 case RAW_QFS_VOLUME_INFO
:
126 passthru_level
= RAW_QFS_VOLUME_INFORMATION
;
129 case RAW_QFS_SIZE_INFO
:
130 passthru_level
= RAW_QFS_SIZE_INFORMATION
;
133 case RAW_QFS_DEVICE_INFO
:
134 passthru_level
= RAW_QFS_DEVICE_INFORMATION
;
137 case RAW_QFS_ATTRIBUTE_INFO
:
138 passthru_level
= RAW_QFS_ATTRIBUTE_INFORMATION
;
142 passthru_level
= fsinfo
->generic
.level
;
146 return smbsrv_push_passthru_fsinfo(mem_ctx
, blob
,
147 passthru_level
, fsinfo
,
152 trans2 qfsinfo implementation send
154 static NTSTATUS
trans2_qfsinfo_send(struct trans_op
*op
)
156 struct smbsrv_request
*req
= op
->req
;
157 struct smb_trans2
*trans
= op
->trans
;
158 union smb_fsinfo
*fsinfo
;
160 TRANS2_CHECK_ASYNC_STATUS(fsinfo
, union smb_fsinfo
);
162 TRANS2_CHECK(trans2_setup_reply(trans
, 0, 0, 0));
164 TRANS2_CHECK(trans2_push_fsinfo(req
->smb_conn
, trans
,
165 &trans
->out
.data
, fsinfo
,
166 SMBSRV_REQ_DEFAULT_STR_FLAGS(req
)));
172 trans2 qfsinfo implementation
174 static NTSTATUS
trans2_qfsinfo(struct smbsrv_request
*req
, struct trans_op
*op
)
176 struct smb_trans2
*trans
= op
->trans
;
177 union smb_fsinfo
*fsinfo
;
180 /* make sure we got enough parameters */
181 if (trans
->in
.params
.length
!= 2) {
182 return NT_STATUS_FOOBAR
;
185 fsinfo
= talloc(op
, union smb_fsinfo
);
186 NT_STATUS_HAVE_NO_MEMORY(fsinfo
);
188 level
= SVAL(trans
->in
.params
.data
, 0);
190 /* work out the backend level - we make it 1-1 in the header */
191 fsinfo
->generic
.level
= (enum smb_fsinfo_level
)level
;
192 if (fsinfo
->generic
.level
>= RAW_QFS_GENERIC
) {
193 return NT_STATUS_INVALID_LEVEL
;
196 op
->op_info
= fsinfo
;
197 op
->send_fn
= trans2_qfsinfo_send
;
199 return ntvfs_fsinfo(req
->ntvfs
, fsinfo
);
204 trans2 open implementation send
206 static NTSTATUS
trans2_open_send(struct trans_op
*op
)
208 struct smbsrv_request
*req
= op
->req
;
209 struct smb_trans2
*trans
= op
->trans
;
212 TRANS2_CHECK_ASYNC_STATUS(io
, union smb_open
);
214 TRANS2_CHECK(trans2_setup_reply(trans
, 30, 0, 0));
216 smbsrv_push_fnum(trans
->out
.params
.data
, VWV(0), io
->t2open
.out
.file
.ntvfs
);
217 SSVAL(trans
->out
.params
.data
, VWV(1), io
->t2open
.out
.attrib
);
218 srv_push_dos_date3(req
->smb_conn
, trans
->out
.params
.data
,
219 VWV(2), io
->t2open
.out
.write_time
);
220 SIVAL(trans
->out
.params
.data
, VWV(4), io
->t2open
.out
.size
);
221 SSVAL(trans
->out
.params
.data
, VWV(6), io
->t2open
.out
.access
);
222 SSVAL(trans
->out
.params
.data
, VWV(7), io
->t2open
.out
.ftype
);
223 SSVAL(trans
->out
.params
.data
, VWV(8), io
->t2open
.out
.devstate
);
224 SSVAL(trans
->out
.params
.data
, VWV(9), io
->t2open
.out
.action
);
225 SIVAL(trans
->out
.params
.data
, VWV(10), 0); /* reserved */
226 SSVAL(trans
->out
.params
.data
, VWV(12), 0); /* EaErrorOffset */
227 SIVAL(trans
->out
.params
.data
, VWV(13), 0); /* EaLength */
233 trans2 open implementation
235 static NTSTATUS
trans2_open(struct smbsrv_request
*req
, struct trans_op
*op
)
237 struct smb_trans2
*trans
= op
->trans
;
240 /* make sure we got enough parameters */
241 if (trans
->in
.params
.length
< 29) {
242 return NT_STATUS_FOOBAR
;
245 io
= talloc(op
, union smb_open
);
246 NT_STATUS_HAVE_NO_MEMORY(io
);
248 io
->t2open
.level
= RAW_OPEN_T2OPEN
;
249 io
->t2open
.in
.flags
= SVAL(trans
->in
.params
.data
, VWV(0));
250 io
->t2open
.in
.open_mode
= SVAL(trans
->in
.params
.data
, VWV(1));
251 io
->t2open
.in
.search_attrs
= SVAL(trans
->in
.params
.data
, VWV(2));
252 io
->t2open
.in
.file_attrs
= SVAL(trans
->in
.params
.data
, VWV(3));
253 io
->t2open
.in
.write_time
= srv_pull_dos_date(req
->smb_conn
,
254 trans
->in
.params
.data
+ VWV(4));
255 io
->t2open
.in
.open_func
= SVAL(trans
->in
.params
.data
, VWV(6));
256 io
->t2open
.in
.size
= IVAL(trans
->in
.params
.data
, VWV(7));
257 io
->t2open
.in
.timeout
= IVAL(trans
->in
.params
.data
, VWV(9));
258 io
->t2open
.in
.num_eas
= 0;
259 io
->t2open
.in
.eas
= NULL
;
261 smbsrv_blob_pull_string(&req
->in
.bufinfo
, &trans
->in
.params
, 28, &io
->t2open
.in
.fname
, 0);
262 if (io
->t2open
.in
.fname
== NULL
) {
263 return NT_STATUS_FOOBAR
;
266 TRANS2_CHECK(ea_pull_list(&trans
->in
.data
, io
, &io
->t2open
.in
.num_eas
, &io
->t2open
.in
.eas
));
269 op
->send_fn
= trans2_open_send
;
271 return ntvfs_open(req
->ntvfs
, io
);
278 static NTSTATUS
trans2_simple_send(struct trans_op
*op
)
280 struct smbsrv_request
*req
= op
->req
;
281 struct smb_trans2
*trans
= op
->trans
;
283 TRANS2_CHECK_ASYNC_STATUS_SIMPLE
;
285 TRANS2_CHECK(trans2_setup_reply(trans
, 2, 0, 0));
287 SSVAL(trans
->out
.params
.data
, VWV(0), 0);
293 trans2 mkdir implementation
295 static NTSTATUS
trans2_mkdir(struct smbsrv_request
*req
, struct trans_op
*op
)
297 struct smb_trans2
*trans
= op
->trans
;
300 /* make sure we got enough parameters */
301 if (trans
->in
.params
.length
< 5) {
302 return NT_STATUS_FOOBAR
;
305 io
= talloc(op
, union smb_mkdir
);
306 NT_STATUS_HAVE_NO_MEMORY(io
);
308 io
->t2mkdir
.level
= RAW_MKDIR_T2MKDIR
;
309 smbsrv_blob_pull_string(&req
->in
.bufinfo
, &trans
->in
.params
, 4, &io
->t2mkdir
.in
.path
, 0);
310 if (io
->t2mkdir
.in
.path
== NULL
) {
311 return NT_STATUS_FOOBAR
;
314 TRANS2_CHECK(ea_pull_list(&trans
->in
.data
, io
,
315 &io
->t2mkdir
.in
.num_eas
,
316 &io
->t2mkdir
.in
.eas
));
319 op
->send_fn
= trans2_simple_send
;
321 return ntvfs_mkdir(req
->ntvfs
, io
);
324 static NTSTATUS
trans2_push_fileinfo(struct smbsrv_connection
*smb_conn
,
327 union smb_fileinfo
*st
,
328 int default_str_flags
)
331 enum smb_fileinfo_level passthru_level
;
333 switch (st
->generic
.level
) {
334 case RAW_FILEINFO_GENERIC
:
335 case RAW_FILEINFO_GETATTR
:
336 case RAW_FILEINFO_GETATTRE
:
337 case RAW_FILEINFO_SEC_DESC
:
338 case RAW_FILEINFO_SMB2_ALL_EAS
:
339 case RAW_FILEINFO_SMB2_ALL_INFORMATION
:
340 /* handled elsewhere */
341 return NT_STATUS_INVALID_LEVEL
;
343 case RAW_FILEINFO_UNIX_BASIC
:
344 case RAW_FILEINFO_UNIX_LINK
:
345 /* not implemented yet */
346 return NT_STATUS_INVALID_LEVEL
;
348 case RAW_FILEINFO_STANDARD
:
349 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx
, blob
, 22));
351 srv_push_dos_date2(smb_conn
, blob
->data
, 0, st
->standard
.out
.create_time
);
352 srv_push_dos_date2(smb_conn
, blob
->data
, 4, st
->standard
.out
.access_time
);
353 srv_push_dos_date2(smb_conn
, blob
->data
, 8, st
->standard
.out
.write_time
);
354 SIVAL(blob
->data
, 12, st
->standard
.out
.size
);
355 SIVAL(blob
->data
, 16, st
->standard
.out
.alloc_size
);
356 SSVAL(blob
->data
, 20, st
->standard
.out
.attrib
);
359 case RAW_FILEINFO_EA_SIZE
:
360 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx
, blob
, 26));
362 srv_push_dos_date2(smb_conn
, blob
->data
, 0, st
->ea_size
.out
.create_time
);
363 srv_push_dos_date2(smb_conn
, blob
->data
, 4, st
->ea_size
.out
.access_time
);
364 srv_push_dos_date2(smb_conn
, blob
->data
, 8, st
->ea_size
.out
.write_time
);
365 SIVAL(blob
->data
, 12, st
->ea_size
.out
.size
);
366 SIVAL(blob
->data
, 16, st
->ea_size
.out
.alloc_size
);
367 SSVAL(blob
->data
, 20, st
->ea_size
.out
.attrib
);
368 SIVAL(blob
->data
, 22, st
->ea_size
.out
.ea_size
);
371 case RAW_FILEINFO_EA_LIST
:
372 list_size
= ea_list_size(st
->ea_list
.out
.num_eas
,
373 st
->ea_list
.out
.eas
);
374 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx
, blob
, list_size
));
376 ea_put_list(blob
->data
,
377 st
->ea_list
.out
.num_eas
, st
->ea_list
.out
.eas
);
380 case RAW_FILEINFO_ALL_EAS
:
381 list_size
= ea_list_size(st
->all_eas
.out
.num_eas
,
382 st
->all_eas
.out
.eas
);
383 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx
, blob
, list_size
));
385 ea_put_list(blob
->data
,
386 st
->all_eas
.out
.num_eas
, st
->all_eas
.out
.eas
);
389 case RAW_FILEINFO_IS_NAME_VALID
:
392 case RAW_FILEINFO_BASIC_INFO
:
393 passthru_level
= RAW_FILEINFO_BASIC_INFORMATION
;
396 case RAW_FILEINFO_STANDARD_INFO
:
397 passthru_level
= RAW_FILEINFO_STANDARD_INFORMATION
;
400 case RAW_FILEINFO_EA_INFO
:
401 passthru_level
= RAW_FILEINFO_EA_INFORMATION
;
404 case RAW_FILEINFO_COMPRESSION_INFO
:
405 passthru_level
= RAW_FILEINFO_COMPRESSION_INFORMATION
;
408 case RAW_FILEINFO_ALL_INFO
:
409 passthru_level
= RAW_FILEINFO_ALL_INFORMATION
;
412 case RAW_FILEINFO_NAME_INFO
:
413 passthru_level
= RAW_FILEINFO_NAME_INFORMATION
;
416 case RAW_FILEINFO_ALT_NAME_INFO
:
417 passthru_level
= RAW_FILEINFO_ALT_NAME_INFORMATION
;
420 case RAW_FILEINFO_STREAM_INFO
:
421 passthru_level
= RAW_FILEINFO_STREAM_INFORMATION
;
425 passthru_level
= st
->generic
.level
;
429 return smbsrv_push_passthru_fileinfo(mem_ctx
, blob
,
435 fill in the reply from a qpathinfo or qfileinfo call
437 static NTSTATUS
trans2_fileinfo_send(struct trans_op
*op
)
439 struct smbsrv_request
*req
= op
->req
;
440 struct smb_trans2
*trans
= op
->trans
;
441 union smb_fileinfo
*st
;
443 TRANS2_CHECK_ASYNC_STATUS(st
, union smb_fileinfo
);
445 TRANS2_CHECK(trans2_setup_reply(trans
, 2, 0, 0));
446 SSVAL(trans
->out
.params
.data
, 0, 0);
448 TRANS2_CHECK(trans2_push_fileinfo(req
->smb_conn
, trans
,
449 &trans
->out
.data
, st
,
450 SMBSRV_REQ_DEFAULT_STR_FLAGS(req
)));
456 trans2 qpathinfo implementation
458 static NTSTATUS
trans2_qpathinfo(struct smbsrv_request
*req
, struct trans_op
*op
)
460 struct smb_trans2
*trans
= op
->trans
;
461 union smb_fileinfo
*st
;
464 /* make sure we got enough parameters */
465 if (trans
->in
.params
.length
< 2) {
466 return NT_STATUS_FOOBAR
;
469 st
= talloc(op
, union smb_fileinfo
);
470 NT_STATUS_HAVE_NO_MEMORY(st
);
472 level
= SVAL(trans
->in
.params
.data
, 0);
474 smbsrv_blob_pull_string(&req
->in
.bufinfo
, &trans
->in
.params
, 6, &st
->generic
.in
.file
.path
, 0);
475 if (st
->generic
.in
.file
.path
== NULL
) {
476 return NT_STATUS_FOOBAR
;
479 /* work out the backend level - we make it 1-1 in the header */
480 st
->generic
.level
= (enum smb_fileinfo_level
)level
;
481 if (st
->generic
.level
>= RAW_FILEINFO_GENERIC
) {
482 return NT_STATUS_INVALID_LEVEL
;
485 if (st
->generic
.level
== RAW_FILEINFO_EA_LIST
) {
486 TRANS2_CHECK(ea_pull_name_list(&trans
->in
.data
, req
,
487 &st
->ea_list
.in
.num_names
,
488 &st
->ea_list
.in
.ea_names
));
492 op
->send_fn
= trans2_fileinfo_send
;
494 return ntvfs_qpathinfo(req
->ntvfs
, st
);
499 trans2 qpathinfo implementation
501 static NTSTATUS
trans2_qfileinfo(struct smbsrv_request
*req
, struct trans_op
*op
)
503 struct smb_trans2
*trans
= op
->trans
;
504 union smb_fileinfo
*st
;
506 struct ntvfs_handle
*h
;
508 /* make sure we got enough parameters */
509 if (trans
->in
.params
.length
< 4) {
510 return NT_STATUS_FOOBAR
;
513 st
= talloc(op
, union smb_fileinfo
);
514 NT_STATUS_HAVE_NO_MEMORY(st
);
516 h
= smbsrv_pull_fnum(req
, trans
->in
.params
.data
, 0);
517 level
= SVAL(trans
->in
.params
.data
, 2);
519 st
->generic
.in
.file
.ntvfs
= h
;
520 /* work out the backend level - we make it 1-1 in the header */
521 st
->generic
.level
= (enum smb_fileinfo_level
)level
;
522 if (st
->generic
.level
>= RAW_FILEINFO_GENERIC
) {
523 return NT_STATUS_INVALID_LEVEL
;
526 if (st
->generic
.level
== RAW_FILEINFO_EA_LIST
) {
527 TRANS2_CHECK(ea_pull_name_list(&trans
->in
.data
, req
,
528 &st
->ea_list
.in
.num_names
,
529 &st
->ea_list
.in
.ea_names
));
533 op
->send_fn
= trans2_fileinfo_send
;
535 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st
->generic
.in
.file
.ntvfs
);
536 return ntvfs_qfileinfo(req
->ntvfs
, st
);
541 parse a trans2 setfileinfo/setpathinfo data blob
543 static NTSTATUS
trans2_parse_sfileinfo(struct smbsrv_request
*req
,
544 union smb_setfileinfo
*st
,
545 const DATA_BLOB
*blob
)
547 enum smb_setfileinfo_level passthru_level
;
549 switch (st
->generic
.level
) {
550 case RAW_SFILEINFO_GENERIC
:
551 case RAW_SFILEINFO_SETATTR
:
552 case RAW_SFILEINFO_SETATTRE
:
553 case RAW_SFILEINFO_SEC_DESC
:
554 /* handled elsewhere */
555 return NT_STATUS_INVALID_LEVEL
;
557 case RAW_SFILEINFO_STANDARD
:
558 CHECK_MIN_BLOB_SIZE(blob
, 12);
560 st
->standard
.in
.create_time
= srv_pull_dos_date2(req
->smb_conn
, blob
->data
+ 0);
561 st
->standard
.in
.access_time
= srv_pull_dos_date2(req
->smb_conn
, blob
->data
+ 4);
562 st
->standard
.in
.write_time
= srv_pull_dos_date2(req
->smb_conn
, blob
->data
+ 8);
566 case RAW_SFILEINFO_EA_SET
:
567 return ea_pull_list(blob
, req
,
568 &st
->ea_set
.in
.num_eas
,
571 case SMB_SFILEINFO_BASIC_INFO
:
572 case SMB_SFILEINFO_BASIC_INFORMATION
:
573 passthru_level
= SMB_SFILEINFO_BASIC_INFORMATION
;
576 case SMB_SFILEINFO_DISPOSITION_INFO
:
577 case SMB_SFILEINFO_DISPOSITION_INFORMATION
:
578 passthru_level
= SMB_SFILEINFO_DISPOSITION_INFORMATION
;
581 case SMB_SFILEINFO_ALLOCATION_INFO
:
582 case SMB_SFILEINFO_ALLOCATION_INFORMATION
:
583 passthru_level
= SMB_SFILEINFO_ALLOCATION_INFORMATION
;
586 case RAW_SFILEINFO_END_OF_FILE_INFO
:
587 case RAW_SFILEINFO_END_OF_FILE_INFORMATION
:
588 passthru_level
= RAW_SFILEINFO_END_OF_FILE_INFORMATION
;
591 case RAW_SFILEINFO_RENAME_INFORMATION
:
592 case RAW_SFILEINFO_POSITION_INFORMATION
:
593 case RAW_SFILEINFO_MODE_INFORMATION
:
594 passthru_level
= st
->generic
.level
;
597 case RAW_SFILEINFO_UNIX_BASIC
:
598 case RAW_SFILEINFO_UNIX_LINK
:
599 case RAW_SFILEINFO_UNIX_HLINK
:
600 case RAW_SFILEINFO_PIPE_INFORMATION
:
601 case RAW_SFILEINFO_VALID_DATA_INFORMATION
:
602 case RAW_SFILEINFO_SHORT_NAME_INFORMATION
:
603 case RAW_SFILEINFO_1025
:
604 case RAW_SFILEINFO_1027
:
605 case RAW_SFILEINFO_1029
:
606 case RAW_SFILEINFO_1030
:
607 case RAW_SFILEINFO_1031
:
608 case RAW_SFILEINFO_1032
:
609 case RAW_SFILEINFO_1036
:
610 case RAW_SFILEINFO_1041
:
611 case RAW_SFILEINFO_1042
:
612 case RAW_SFILEINFO_1043
:
613 case RAW_SFILEINFO_1044
:
614 return NT_STATUS_INVALID_LEVEL
;
617 /* we need a default here to cope with invalid values on the wire */
618 return NT_STATUS_INVALID_LEVEL
;
621 return smbsrv_pull_passthru_sfileinfo(st
, passthru_level
, st
,
622 blob
, SMBSRV_REQ_DEFAULT_STR_FLAGS(req
),
627 trans2 setfileinfo implementation
629 static NTSTATUS
trans2_setfileinfo(struct smbsrv_request
*req
, struct trans_op
*op
)
631 struct smb_trans2
*trans
= op
->trans
;
632 union smb_setfileinfo
*st
;
634 struct ntvfs_handle
*h
;
636 /* make sure we got enough parameters */
637 if (trans
->in
.params
.length
< 4) {
638 return NT_STATUS_FOOBAR
;
641 st
= talloc(op
, union smb_setfileinfo
);
642 NT_STATUS_HAVE_NO_MEMORY(st
);
644 h
= smbsrv_pull_fnum(req
, trans
->in
.params
.data
, 0);
645 level
= SVAL(trans
->in
.params
.data
, 2);
647 st
->generic
.in
.file
.ntvfs
= h
;
648 /* work out the backend level - we make it 1-1 in the header */
649 st
->generic
.level
= (enum smb_setfileinfo_level
)level
;
650 if (st
->generic
.level
>= RAW_SFILEINFO_GENERIC
) {
651 return NT_STATUS_INVALID_LEVEL
;
654 TRANS2_CHECK(trans2_parse_sfileinfo(req
, st
, &trans
->in
.data
));
657 op
->send_fn
= trans2_simple_send
;
659 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st
->generic
.in
.file
.ntvfs
);
660 return ntvfs_setfileinfo(req
->ntvfs
, st
);
664 trans2 setpathinfo implementation
666 static NTSTATUS
trans2_setpathinfo(struct smbsrv_request
*req
, struct trans_op
*op
)
668 struct smb_trans2
*trans
= op
->trans
;
669 union smb_setfileinfo
*st
;
672 /* make sure we got enough parameters */
673 if (trans
->in
.params
.length
< 4) {
674 return NT_STATUS_FOOBAR
;
677 st
= talloc(op
, union smb_setfileinfo
);
678 NT_STATUS_HAVE_NO_MEMORY(st
);
680 level
= SVAL(trans
->in
.params
.data
, 0);
682 smbsrv_blob_pull_string(&req
->in
.bufinfo
, &trans
->in
.params
, 6, &st
->generic
.in
.file
.path
, 0);
683 if (st
->generic
.in
.file
.path
== NULL
) {
684 return NT_STATUS_FOOBAR
;
687 /* work out the backend level - we make it 1-1 in the header */
688 st
->generic
.level
= (enum smb_setfileinfo_level
)level
;
689 if (st
->generic
.level
>= RAW_SFILEINFO_GENERIC
) {
690 return NT_STATUS_INVALID_LEVEL
;
693 TRANS2_CHECK(trans2_parse_sfileinfo(req
, st
, &trans
->in
.data
));
696 op
->send_fn
= trans2_simple_send
;
698 return ntvfs_setpathinfo(req
->ntvfs
, st
);
702 /* a structure to encapsulate the state information about an in-progress ffirst/fnext operation */
706 enum smb_search_data_level data_level
;
707 uint16_t last_entry_offset
;
712 fill a single entry in a trans2 find reply
714 static NTSTATUS
find_fill_info(struct find_state
*state
,
715 const union smb_search_data
*file
)
717 struct smbsrv_request
*req
= state
->op
->req
;
718 struct smb_trans2
*trans
= state
->op
->trans
;
720 unsigned int ofs
= trans
->out
.data
.length
;
723 switch (state
->data_level
) {
724 case RAW_SEARCH_DATA_GENERIC
:
725 case RAW_SEARCH_DATA_SEARCH
:
726 /* handled elsewhere */
727 return NT_STATUS_INVALID_LEVEL
;
729 case RAW_SEARCH_DATA_STANDARD
:
730 if (state
->flags
& FLAG_TRANS2_FIND_REQUIRE_RESUME
) {
731 TRANS2_CHECK(smbsrv_blob_grow_data(trans
, &trans
->out
.data
, ofs
+ 27));
732 SIVAL(trans
->out
.data
.data
, ofs
, file
->standard
.resume_key
);
735 TRANS2_CHECK(smbsrv_blob_grow_data(trans
, &trans
->out
.data
, ofs
+ 23));
737 data
= trans
->out
.data
.data
+ ofs
;
738 srv_push_dos_date2(req
->smb_conn
, data
, 0, file
->standard
.create_time
);
739 srv_push_dos_date2(req
->smb_conn
, data
, 4, file
->standard
.access_time
);
740 srv_push_dos_date2(req
->smb_conn
, data
, 8, file
->standard
.write_time
);
741 SIVAL(data
, 12, file
->standard
.size
);
742 SIVAL(data
, 16, file
->standard
.alloc_size
);
743 SSVAL(data
, 20, file
->standard
.attrib
);
744 TRANS2_CHECK(smbsrv_blob_append_string(trans
, &trans
->out
.data
, file
->standard
.name
.s
,
745 ofs
+ 22, SMBSRV_REQ_DEFAULT_STR_FLAGS(req
),
746 STR_LEN8BIT
| STR_TERMINATE
| STR_LEN_NOTERM
));
749 case RAW_SEARCH_DATA_EA_SIZE
:
750 if (state
->flags
& FLAG_TRANS2_FIND_REQUIRE_RESUME
) {
751 TRANS2_CHECK(smbsrv_blob_grow_data(trans
, &trans
->out
.data
, ofs
+ 31));
752 SIVAL(trans
->out
.data
.data
, ofs
, file
->ea_size
.resume_key
);
755 TRANS2_CHECK(smbsrv_blob_grow_data(trans
, &trans
->out
.data
, ofs
+ 27));
757 data
= trans
->out
.data
.data
+ ofs
;
758 srv_push_dos_date2(req
->smb_conn
, data
, 0, file
->ea_size
.create_time
);
759 srv_push_dos_date2(req
->smb_conn
, data
, 4, file
->ea_size
.access_time
);
760 srv_push_dos_date2(req
->smb_conn
, data
, 8, file
->ea_size
.write_time
);
761 SIVAL(data
, 12, file
->ea_size
.size
);
762 SIVAL(data
, 16, file
->ea_size
.alloc_size
);
763 SSVAL(data
, 20, file
->ea_size
.attrib
);
764 SIVAL(data
, 22, file
->ea_size
.ea_size
);
765 TRANS2_CHECK(smbsrv_blob_append_string(trans
, &trans
->out
.data
, file
->ea_size
.name
.s
,
766 ofs
+ 26, SMBSRV_REQ_DEFAULT_STR_FLAGS(req
),
767 STR_LEN8BIT
| STR_NOALIGN
));
768 TRANS2_CHECK(smbsrv_blob_fill_data(trans
, &trans
->out
.data
, trans
->out
.data
.length
+ 1));
771 case RAW_SEARCH_DATA_EA_LIST
:
772 ea_size
= ea_list_size(file
->ea_list
.eas
.num_eas
, file
->ea_list
.eas
.eas
);
773 if (state
->flags
& FLAG_TRANS2_FIND_REQUIRE_RESUME
) {
774 TRANS2_CHECK(smbsrv_blob_grow_data(trans
, &trans
->out
.data
, ofs
+ 27 + ea_size
));
775 SIVAL(trans
->out
.data
.data
, ofs
, file
->ea_list
.resume_key
);
778 TRANS2_CHECK(smbsrv_blob_grow_data(trans
, &trans
->out
.data
, ofs
+ 23 + ea_size
));
780 data
= trans
->out
.data
.data
+ ofs
;
781 srv_push_dos_date2(req
->smb_conn
, data
, 0, file
->ea_list
.create_time
);
782 srv_push_dos_date2(req
->smb_conn
, data
, 4, file
->ea_list
.access_time
);
783 srv_push_dos_date2(req
->smb_conn
, data
, 8, file
->ea_list
.write_time
);
784 SIVAL(data
, 12, file
->ea_list
.size
);
785 SIVAL(data
, 16, file
->ea_list
.alloc_size
);
786 SSVAL(data
, 20, file
->ea_list
.attrib
);
787 ea_put_list(data
+22, file
->ea_list
.eas
.num_eas
, file
->ea_list
.eas
.eas
);
788 TRANS2_CHECK(smbsrv_blob_append_string(trans
, &trans
->out
.data
, file
->ea_list
.name
.s
,
789 ofs
+ 22 + ea_size
, SMBSRV_REQ_DEFAULT_STR_FLAGS(req
),
790 STR_LEN8BIT
| STR_NOALIGN
));
791 TRANS2_CHECK(smbsrv_blob_fill_data(trans
, &trans
->out
.data
, trans
->out
.data
.length
+ 1));
794 case RAW_SEARCH_DATA_DIRECTORY_INFO
:
795 case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO
:
796 case RAW_SEARCH_DATA_NAME_INFO
:
797 case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
:
798 case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO
:
799 case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO
:
800 return smbsrv_push_passthru_search(trans
, &trans
->out
.data
, state
->data_level
, file
,
801 SMBSRV_REQ_DEFAULT_STR_FLAGS(req
));
803 case RAW_SEARCH_DATA_UNIX_INFO
:
804 case RAW_SEARCH_DATA_UNIX_INFO2
:
805 return NT_STATUS_INVALID_LEVEL
;
811 /* callback function for trans2 findfirst/findnext */
812 static bool find_callback(void *private_data
, const union smb_search_data
*file
)
814 struct find_state
*state
= talloc_get_type(private_data
, struct find_state
);
815 struct smb_trans2
*trans
= state
->op
->trans
;
816 unsigned int old_length
;
818 old_length
= trans
->out
.data
.length
;
820 if (!NT_STATUS_IS_OK(find_fill_info(state
, file
)) ||
821 trans
->out
.data
.length
> trans
->in
.max_data
) {
822 /* restore the old length and tell the backend to stop */
823 smbsrv_blob_grow_data(trans
, &trans
->out
.data
, old_length
);
827 state
->last_entry_offset
= old_length
;
832 trans2 findfirst send
834 static NTSTATUS
trans2_findfirst_send(struct trans_op
*op
)
836 struct smbsrv_request
*req
= op
->req
;
837 struct smb_trans2
*trans
= op
->trans
;
838 union smb_search_first
*search
;
839 struct find_state
*state
;
842 TRANS2_CHECK_ASYNC_STATUS(state
, struct find_state
);
843 search
= talloc_get_type(state
->search
, union smb_search_first
);
845 /* fill in the findfirst reply header */
846 param
= trans
->out
.params
.data
;
847 SSVAL(param
, VWV(0), search
->t2ffirst
.out
.handle
);
848 SSVAL(param
, VWV(1), search
->t2ffirst
.out
.count
);
849 SSVAL(param
, VWV(2), search
->t2ffirst
.out
.end_of_search
);
850 SSVAL(param
, VWV(3), 0);
851 SSVAL(param
, VWV(4), state
->last_entry_offset
);
857 trans2 getdfsreferral implementation
859 static NTSTATUS
trans2_getdfsreferral(struct smbsrv_request
*req
,
862 enum ndr_err_code ndr_err
;
863 struct smb_trans2
*trans
= op
->trans
;
864 struct ldb_context
*ldb
;
865 struct loadparm_context
*lp_ctx
;
867 struct dfs_GetDFSReferral
*r
;
868 DATA_BLOB outblob
= data_blob_null
;
869 uint16_t nb_referrals
= 0;
871 lp_ctx
= req
->tcon
->ntvfs
->lp_ctx
;
872 if (!lpcfg_host_msdfs(lp_ctx
)) {
873 return NT_STATUS_NOT_IMPLEMENTED
;
876 r
= talloc_zero(req
, struct dfs_GetDFSReferral
);
877 NT_STATUS_HAVE_NO_MEMORY(r
);
879 ldb
= samdb_connect(r
,
880 req
->tcon
->ntvfs
->event_ctx
,
882 system_session(lp_ctx
),
886 DEBUG(2,(__location__
": Failed to open samdb\n"));
888 return NT_STATUS_INTERNAL_ERROR
;
891 ndr_err
= ndr_pull_struct_blob(&trans
->in
.params
, r
,
893 (ndr_pull_flags_fn_t
)ndr_pull_dfs_GetDFSReferral_in
);
894 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
895 status
= ndr_map_error2ntstatus(ndr_err
);
896 DEBUG(2,(__location__
": Failed to parse GetDFSReferral_in - %s\n",
902 DEBUG(8, ("Requested DFS name: %s length: %u\n",
903 r
->in
.req
.servername
,
904 (unsigned int)strlen_m(r
->in
.req
.servername
)*2));
906 status
= dfs_server_ad_get_referrals(lp_ctx
, ldb
,
907 req
->smb_conn
->connection
->remote_address
, r
);
908 if (!NT_STATUS_IS_OK(status
)) {
913 ndr_err
= ndr_push_struct_blob(&outblob
, trans
,
915 (ndr_push_flags_fn_t
)ndr_push_dfs_referral_resp
);
916 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
917 DEBUG(2,(__location__
":NDR marshalling of domain referral response failed\n"));
919 return NT_STATUS_INTERNAL_ERROR
;
922 nb_referrals
= r
->out
.resp
->nb_referrals
;
924 if (outblob
.length
> trans
->in
.max_data
) {
927 DEBUG(3, ("Blob is too big for the output buffer "
929 (unsigned int)outblob
.length
, trans
->in
.max_data
));
931 if (trans
->in
.max_data
!= MAX_DFS_RESPONSE
) {
932 /* As specified in MS-DFSC.pdf 3.3.5.2 */
934 return STATUS_BUFFER_OVERFLOW
;
938 * The answer is too big, so let's remove some answers
940 while (!ok
&& r
->out
.resp
->nb_referrals
> 2) {
941 data_blob_free(&outblob
);
944 * Let's scrap the last referral (for now)
946 r
->out
.resp
->nb_referrals
-= 1;
948 ndr_err
= ndr_push_struct_blob(&outblob
, trans
,
950 (ndr_push_flags_fn_t
)ndr_push_dfs_referral_resp
);
951 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
953 return NT_STATUS_INTERNAL_ERROR
;
956 if (outblob
.length
<= MAX_DFS_RESPONSE
) {
957 DEBUG(10,("DFS: managed to reduce the size of referral initial "
958 "number of referral %d, actual count: %d\n",
959 nb_referrals
, r
->out
.resp
->nb_referrals
));
965 if (!ok
&& r
->out
.resp
->nb_referrals
<= 2) {
966 DEBUG(8, (__location__
"; Not able to fit the domain and realm in DFS a "
967 " 56K buffer, something must be broken\n"));
969 return NT_STATUS_INTERNAL_ERROR
;
973 TRANS2_CHECK(trans2_setup_reply(trans
, 0, outblob
.length
, 0));
975 trans
->out
.data
= outblob
;
981 trans2 findfirst implementation
983 static NTSTATUS
trans2_findfirst(struct smbsrv_request
*req
, struct trans_op
*op
)
985 struct smb_trans2
*trans
= op
->trans
;
986 union smb_search_first
*search
;
988 struct find_state
*state
;
990 /* make sure we got all the parameters */
991 if (trans
->in
.params
.length
< 14) {
992 return NT_STATUS_FOOBAR
;
995 search
= talloc(op
, union smb_search_first
);
996 NT_STATUS_HAVE_NO_MEMORY(search
);
998 search
->t2ffirst
.in
.search_attrib
= SVAL(trans
->in
.params
.data
, 0);
999 search
->t2ffirst
.in
.max_count
= SVAL(trans
->in
.params
.data
, 2);
1000 search
->t2ffirst
.in
.flags
= SVAL(trans
->in
.params
.data
, 4);
1001 level
= SVAL(trans
->in
.params
.data
, 6);
1002 search
->t2ffirst
.in
.storage_type
= IVAL(trans
->in
.params
.data
, 8);
1004 smbsrv_blob_pull_string(&req
->in
.bufinfo
, &trans
->in
.params
, 12, &search
->t2ffirst
.in
.pattern
, 0);
1005 if (search
->t2ffirst
.in
.pattern
== NULL
) {
1006 return NT_STATUS_FOOBAR
;
1009 search
->t2ffirst
.level
= RAW_SEARCH_TRANS2
;
1010 search
->t2ffirst
.data_level
= (enum smb_search_data_level
)level
;
1011 if (search
->t2ffirst
.data_level
>= RAW_SEARCH_DATA_GENERIC
) {
1012 return NT_STATUS_INVALID_LEVEL
;
1015 if (search
->t2ffirst
.data_level
== RAW_SEARCH_DATA_EA_LIST
) {
1016 TRANS2_CHECK(ea_pull_name_list(&trans
->in
.data
, req
,
1017 &search
->t2ffirst
.in
.num_names
,
1018 &search
->t2ffirst
.in
.ea_names
));
1021 /* setup the private state structure that the backend will
1022 give us in the callback */
1023 state
= talloc(op
, struct find_state
);
1024 NT_STATUS_HAVE_NO_MEMORY(state
);
1026 state
->search
= search
;
1027 state
->data_level
= search
->t2ffirst
.data_level
;
1028 state
->last_entry_offset
= 0;
1029 state
->flags
= search
->t2ffirst
.in
.flags
;
1031 /* setup for just a header in the reply */
1032 TRANS2_CHECK(trans2_setup_reply(trans
, 10, 0, 0));
1034 op
->op_info
= state
;
1035 op
->send_fn
= trans2_findfirst_send
;
1037 return ntvfs_search_first(req
->ntvfs
, search
, state
, find_callback
);
1042 trans2 findnext send
1044 static NTSTATUS
trans2_findnext_send(struct trans_op
*op
)
1046 struct smbsrv_request
*req
= op
->req
;
1047 struct smb_trans2
*trans
= op
->trans
;
1048 union smb_search_next
*search
;
1049 struct find_state
*state
;
1052 TRANS2_CHECK_ASYNC_STATUS(state
, struct find_state
);
1053 search
= talloc_get_type(state
->search
, union smb_search_next
);
1055 /* fill in the findfirst reply header */
1056 param
= trans
->out
.params
.data
;
1057 SSVAL(param
, VWV(0), search
->t2fnext
.out
.count
);
1058 SSVAL(param
, VWV(1), search
->t2fnext
.out
.end_of_search
);
1059 SSVAL(param
, VWV(2), 0);
1060 SSVAL(param
, VWV(3), state
->last_entry_offset
);
1062 return NT_STATUS_OK
;
1067 trans2 findnext implementation
1069 static NTSTATUS
trans2_findnext(struct smbsrv_request
*req
, struct trans_op
*op
)
1071 struct smb_trans2
*trans
= op
->trans
;
1072 union smb_search_next
*search
;
1074 struct find_state
*state
;
1076 /* make sure we got all the parameters */
1077 if (trans
->in
.params
.length
< 12) {
1078 return NT_STATUS_FOOBAR
;
1081 search
= talloc(op
, union smb_search_next
);
1082 NT_STATUS_HAVE_NO_MEMORY(search
);
1084 search
->t2fnext
.in
.handle
= SVAL(trans
->in
.params
.data
, 0);
1085 search
->t2fnext
.in
.max_count
= SVAL(trans
->in
.params
.data
, 2);
1086 level
= SVAL(trans
->in
.params
.data
, 4);
1087 search
->t2fnext
.in
.resume_key
= IVAL(trans
->in
.params
.data
, 6);
1088 search
->t2fnext
.in
.flags
= SVAL(trans
->in
.params
.data
, 10);
1090 smbsrv_blob_pull_string(&req
->in
.bufinfo
, &trans
->in
.params
, 12, &search
->t2fnext
.in
.last_name
, 0);
1091 if (search
->t2fnext
.in
.last_name
== NULL
) {
1092 return NT_STATUS_FOOBAR
;
1095 search
->t2fnext
.level
= RAW_SEARCH_TRANS2
;
1096 search
->t2fnext
.data_level
= (enum smb_search_data_level
)level
;
1097 if (search
->t2fnext
.data_level
>= RAW_SEARCH_DATA_GENERIC
) {
1098 return NT_STATUS_INVALID_LEVEL
;
1101 if (search
->t2fnext
.data_level
== RAW_SEARCH_DATA_EA_LIST
) {
1102 TRANS2_CHECK(ea_pull_name_list(&trans
->in
.data
, req
,
1103 &search
->t2fnext
.in
.num_names
,
1104 &search
->t2fnext
.in
.ea_names
));
1107 /* setup the private state structure that the backend will give us in the callback */
1108 state
= talloc(op
, struct find_state
);
1109 NT_STATUS_HAVE_NO_MEMORY(state
);
1111 state
->search
= search
;
1112 state
->data_level
= search
->t2fnext
.data_level
;
1113 state
->last_entry_offset
= 0;
1114 state
->flags
= search
->t2fnext
.in
.flags
;
1116 /* setup for just a header in the reply */
1117 TRANS2_CHECK(trans2_setup_reply(trans
, 8, 0, 0));
1119 op
->op_info
= state
;
1120 op
->send_fn
= trans2_findnext_send
;
1122 return ntvfs_search_next(req
->ntvfs
, search
, state
, find_callback
);
1127 backend for trans2 requests
1129 static NTSTATUS
trans2_backend(struct smbsrv_request
*req
, struct trans_op
*op
)
1131 struct smb_trans2
*trans
= op
->trans
;
1134 /* direct trans2 pass thru */
1135 status
= ntvfs_trans2(req
->ntvfs
, trans
);
1136 if (!NT_STATUS_EQUAL(NT_STATUS_NOT_IMPLEMENTED
, status
)) {
1140 /* must have at least one setup word */
1141 if (trans
->in
.setup_count
< 1) {
1142 return NT_STATUS_FOOBAR
;
1145 /* the trans2 command is in setup[0] */
1146 switch (trans
->in
.setup
[0]) {
1147 case TRANSACT2_GET_DFS_REFERRAL
:
1148 return trans2_getdfsreferral(req
, op
);
1149 case TRANSACT2_FINDFIRST
:
1150 return trans2_findfirst(req
, op
);
1151 case TRANSACT2_FINDNEXT
:
1152 return trans2_findnext(req
, op
);
1153 case TRANSACT2_QPATHINFO
:
1154 return trans2_qpathinfo(req
, op
);
1155 case TRANSACT2_QFILEINFO
:
1156 return trans2_qfileinfo(req
, op
);
1157 case TRANSACT2_SETFILEINFO
:
1158 return trans2_setfileinfo(req
, op
);
1159 case TRANSACT2_SETPATHINFO
:
1160 return trans2_setpathinfo(req
, op
);
1161 case TRANSACT2_QFSINFO
:
1162 return trans2_qfsinfo(req
, op
);
1163 case TRANSACT2_OPEN
:
1164 return trans2_open(req
, op
);
1165 case TRANSACT2_MKDIR
:
1166 return trans2_mkdir(req
, op
);
1169 /* an unknown trans2 command */
1170 return NT_STATUS_FOOBAR
;
1173 int smbsrv_trans_partial_destructor(struct smbsrv_trans_partial
*tp
)
1175 DLIST_REMOVE(tp
->req
->smb_conn
->trans_partial
, tp
);
1181 send a continue request
1183 static void reply_trans_continue(struct smbsrv_request
*req
, uint8_t command
,
1184 struct smb_trans2
*trans
)
1186 struct smbsrv_request
*req2
;
1187 struct smbsrv_trans_partial
*tp
;
1190 /* make sure they don't flood us */
1191 for (count
=0,tp
=req
->smb_conn
->trans_partial
;tp
;tp
=tp
->next
) count
++;
1193 smbsrv_send_error(req
, NT_STATUS_INSUFFICIENT_RESOURCES
);
1197 tp
= talloc(req
, struct smbsrv_trans_partial
);
1200 tp
->u
.trans
= trans
;
1201 tp
->command
= command
;
1203 DLIST_ADD(req
->smb_conn
->trans_partial
, tp
);
1204 talloc_set_destructor(tp
, smbsrv_trans_partial_destructor
);
1206 req2
= smbsrv_setup_secondary_request(req
);
1208 /* send a 'please continue' reply */
1209 smbsrv_setup_reply(req2
, 0, 0);
1210 smbsrv_send_reply(req2
);
1215 answer a reconstructed trans request
1217 static void reply_trans_send(struct ntvfs_request
*ntvfs
)
1219 struct smbsrv_request
*req
;
1220 struct trans_op
*op
;
1221 struct smb_trans2
*trans
;
1222 uint16_t params_left
, data_left
;
1223 uint8_t *params
, *data
;
1226 SMBSRV_CHECK_ASYNC_STATUS_ERR(op
, struct trans_op
);
1229 /* if this function needs work to form the nttrans reply buffer, then
1231 if (op
->send_fn
!= NULL
) {
1233 status
= op
->send_fn(op
);
1234 if (!NT_STATUS_IS_OK(status
)) {
1235 smbsrv_send_error(req
, status
);
1240 params_left
= trans
->out
.params
.length
;
1241 data_left
= trans
->out
.data
.length
;
1242 params
= trans
->out
.params
.data
;
1243 data
= trans
->out
.data
.data
;
1245 smbsrv_setup_reply(req
, 10 + trans
->out
.setup_count
, 0);
1247 if (!NT_STATUS_IS_OK(req
->ntvfs
->async_states
->status
)) {
1248 smbsrv_setup_error(req
, req
->ntvfs
->async_states
->status
);
1251 /* we need to divide up the reply into chunks that fit into
1252 the negotiated buffer size */
1254 uint16_t this_data
, this_param
, max_bytes
;
1255 unsigned int align1
= 1, align2
= (params_left
? 2 : 0);
1256 struct smbsrv_request
*this_req
;
1258 max_bytes
= req_max_data(req
) - (align1
+ align2
);
1260 this_param
= params_left
;
1261 if (this_param
> max_bytes
) {
1262 this_param
= max_bytes
;
1264 max_bytes
-= this_param
;
1266 this_data
= data_left
;
1267 if (this_data
> max_bytes
) {
1268 this_data
= max_bytes
;
1271 /* don't destroy unless this is the last chunk */
1272 if (params_left
- this_param
!= 0 ||
1273 data_left
- this_data
!= 0) {
1274 this_req
= smbsrv_setup_secondary_request(req
);
1279 req_grow_data(this_req
, this_param
+ this_data
+ (align1
+ align2
));
1281 SSVAL(this_req
->out
.vwv
, VWV(0), trans
->out
.params
.length
);
1282 SSVAL(this_req
->out
.vwv
, VWV(1), trans
->out
.data
.length
);
1283 SSVAL(this_req
->out
.vwv
, VWV(2), 0);
1285 SSVAL(this_req
->out
.vwv
, VWV(3), this_param
);
1286 SSVAL(this_req
->out
.vwv
, VWV(4), align1
+ PTR_DIFF(this_req
->out
.data
, this_req
->out
.hdr
));
1287 SSVAL(this_req
->out
.vwv
, VWV(5), PTR_DIFF(params
, trans
->out
.params
.data
));
1289 SSVAL(this_req
->out
.vwv
, VWV(6), this_data
);
1290 SSVAL(this_req
->out
.vwv
, VWV(7), align1
+ align2
+
1291 PTR_DIFF(this_req
->out
.data
+ this_param
, this_req
->out
.hdr
));
1292 SSVAL(this_req
->out
.vwv
, VWV(8), PTR_DIFF(data
, trans
->out
.data
.data
));
1294 SCVAL(this_req
->out
.vwv
, VWV(9), trans
->out
.setup_count
);
1295 SCVAL(this_req
->out
.vwv
, VWV(9)+1, 0); /* reserved */
1296 for (i
=0;i
<trans
->out
.setup_count
;i
++) {
1297 SSVAL(this_req
->out
.vwv
, VWV(10+i
), trans
->out
.setup
[i
]);
1300 memset(this_req
->out
.data
, 0, align1
);
1301 if (this_param
!= 0) {
1302 memcpy(this_req
->out
.data
+ align1
, params
, this_param
);
1304 memset(this_req
->out
.data
+this_param
+align1
, 0, align2
);
1305 if (this_data
!= 0) {
1306 memcpy(this_req
->out
.data
+this_param
+align1
+align2
, data
, this_data
);
1309 params_left
-= this_param
;
1310 data_left
-= this_data
;
1311 params
+= this_param
;
1314 smbsrv_send_reply(this_req
);
1315 } while (params_left
!= 0 || data_left
!= 0);
1320 answer a reconstructed trans request
1322 static void reply_trans_complete(struct smbsrv_request
*req
, uint8_t command
,
1323 struct smb_trans2
*trans
)
1325 struct trans_op
*op
;
1327 SMBSRV_TALLOC_IO_PTR(op
, struct trans_op
);
1328 SMBSRV_SETUP_NTVFS_REQUEST(reply_trans_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
1332 op
->command
= command
;
1336 /* its a full request, give it to the backend */
1337 if (command
== SMBtrans
) {
1338 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_trans(req
->ntvfs
, trans
));
1341 SMBSRV_CALL_NTVFS_BACKEND(trans2_backend(req
, op
));
1347 Reply to an SMBtrans or SMBtrans2 request
1349 static void reply_trans_generic(struct smbsrv_request
*req
, uint8_t command
)
1351 struct smb_trans2
*trans
;
1353 uint16_t param_ofs
, data_ofs
;
1354 uint16_t param_count
, data_count
;
1355 uint16_t param_total
, data_total
;
1358 if (req
->in
.wct
< 14) {
1359 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
1363 trans
= talloc(req
, struct smb_trans2
);
1364 if (trans
== NULL
) {
1365 smbsrv_send_error(req
, NT_STATUS_NO_MEMORY
);
1369 param_total
= SVAL(req
->in
.vwv
, VWV(0));
1370 data_total
= SVAL(req
->in
.vwv
, VWV(1));
1371 trans
->in
.max_param
= SVAL(req
->in
.vwv
, VWV(2));
1372 trans
->in
.max_data
= SVAL(req
->in
.vwv
, VWV(3));
1373 trans
->in
.max_setup
= CVAL(req
->in
.vwv
, VWV(4));
1374 trans
->in
.flags
= SVAL(req
->in
.vwv
, VWV(5));
1375 trans
->in
.timeout
= IVAL(req
->in
.vwv
, VWV(6));
1376 param_count
= SVAL(req
->in
.vwv
, VWV(9));
1377 param_ofs
= SVAL(req
->in
.vwv
, VWV(10));
1378 data_count
= SVAL(req
->in
.vwv
, VWV(11));
1379 data_ofs
= SVAL(req
->in
.vwv
, VWV(12));
1380 trans
->in
.setup_count
= CVAL(req
->in
.vwv
, VWV(13));
1382 if (req
->in
.wct
!= 14 + trans
->in
.setup_count
) {
1383 smbsrv_send_error(req
, NT_STATUS_DOS(ERRSRV
, ERRerror
));
1387 /* parse out the setup words */
1388 trans
->in
.setup
= talloc_array(trans
, uint16_t, trans
->in
.setup_count
);
1389 if (trans
->in
.setup_count
&& !trans
->in
.setup
) {
1390 smbsrv_send_error(req
, NT_STATUS_NO_MEMORY
);
1393 for (i
=0;i
<trans
->in
.setup_count
;i
++) {
1394 trans
->in
.setup
[i
] = SVAL(req
->in
.vwv
, VWV(14+i
));
1397 if (command
== SMBtrans
) {
1398 req_pull_string(&req
->in
.bufinfo
, &trans
->in
.trans_name
, req
->in
.data
, -1, STR_TERMINATE
);
1401 if (!req_pull_blob(&req
->in
.bufinfo
, req
->in
.hdr
+ param_ofs
, param_count
, &trans
->in
.params
) ||
1402 !req_pull_blob(&req
->in
.bufinfo
, req
->in
.hdr
+ data_ofs
, data_count
, &trans
->in
.data
)) {
1403 smbsrv_send_error(req
, NT_STATUS_FOOBAR
);
1407 /* is it a partial request? if so, then send a 'send more' message */
1408 if (param_total
> param_count
|| data_total
> data_count
) {
1409 reply_trans_continue(req
, command
, trans
);
1413 reply_trans_complete(req
, command
, trans
);
1418 Reply to an SMBtranss2 request
1420 static void reply_transs_generic(struct smbsrv_request
*req
, uint8_t command
)
1422 struct smbsrv_trans_partial
*tp
;
1423 struct smb_trans2
*trans
= NULL
;
1424 uint16_t param_ofs
, data_ofs
;
1425 uint16_t param_count
, data_count
;
1426 uint16_t param_disp
, data_disp
;
1427 uint16_t param_total
, data_total
;
1428 DATA_BLOB params
, data
;
1431 if (command
== SMBtrans2
) {
1438 if (req
->in
.wct
!= wct
) {
1440 * TODO: add some error code tests
1441 * w2k3 returns NT_STATUS_DOS(ERRSRV, ERRerror) here
1443 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
1447 for (tp
=req
->smb_conn
->trans_partial
;tp
;tp
=tp
->next
) {
1448 if (tp
->command
== command
&&
1449 SVAL(tp
->req
->in
.hdr
, HDR_MID
) == SVAL(req
->in
.hdr
, HDR_MID
)) {
1450 /* TODO: check the VUID, PID and TID too? */
1456 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
1460 trans
= tp
->u
.trans
;
1462 param_total
= SVAL(req
->in
.vwv
, VWV(0));
1463 data_total
= SVAL(req
->in
.vwv
, VWV(1));
1464 param_count
= SVAL(req
->in
.vwv
, VWV(2));
1465 param_ofs
= SVAL(req
->in
.vwv
, VWV(3));
1466 param_disp
= SVAL(req
->in
.vwv
, VWV(4));
1467 data_count
= SVAL(req
->in
.vwv
, VWV(5));
1468 data_ofs
= SVAL(req
->in
.vwv
, VWV(6));
1469 data_disp
= SVAL(req
->in
.vwv
, VWV(7));
1471 if (!req_pull_blob(&req
->in
.bufinfo
, req
->in
.hdr
+ param_ofs
, param_count
, ¶ms
) ||
1472 !req_pull_blob(&req
->in
.bufinfo
, req
->in
.hdr
+ data_ofs
, data_count
, &data
)) {
1473 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
1477 /* only allow contiguous requests */
1478 if ((param_count
!= 0 &&
1479 param_disp
!= trans
->in
.params
.length
) ||
1481 data_disp
!= trans
->in
.data
.length
)) {
1482 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
1486 /* add to the existing request */
1487 if (param_count
!= 0) {
1488 trans
->in
.params
.data
= talloc_realloc(trans
,
1489 trans
->in
.params
.data
,
1491 param_disp
+ param_count
);
1492 if (trans
->in
.params
.data
== NULL
) {
1493 smbsrv_send_error(tp
->req
, NT_STATUS_NO_MEMORY
);
1496 trans
->in
.params
.length
= param_disp
+ param_count
;
1499 if (data_count
!= 0) {
1500 trans
->in
.data
.data
= talloc_realloc(trans
,
1501 trans
->in
.data
.data
,
1503 data_disp
+ data_count
);
1504 if (trans
->in
.data
.data
== NULL
) {
1505 smbsrv_send_error(tp
->req
, NT_STATUS_NO_MEMORY
);
1508 trans
->in
.data
.length
= data_disp
+ data_count
;
1511 memcpy(trans
->in
.params
.data
+ param_disp
, params
.data
, params
.length
);
1512 memcpy(trans
->in
.data
.data
+ data_disp
, data
.data
, data
.length
);
1514 /* the sequence number of the reply is taken from the last secondary
1516 tp
->req
->seq_num
= req
->seq_num
;
1518 /* we don't reply to Transs2 requests */
1521 if (trans
->in
.params
.length
== param_total
&&
1522 trans
->in
.data
.length
== data_total
) {
1523 /* its now complete */
1526 reply_trans_complete(req
, command
, trans
);
1533 Reply to an SMBtrans2
1535 void smbsrv_reply_trans2(struct smbsrv_request
*req
)
1537 reply_trans_generic(req
, SMBtrans2
);
1541 Reply to an SMBtrans
1543 void smbsrv_reply_trans(struct smbsrv_request
*req
)
1545 reply_trans_generic(req
, SMBtrans
);
1549 Reply to an SMBtranss request
1551 void smbsrv_reply_transs(struct smbsrv_request
*req
)
1553 reply_transs_generic(req
, SMBtrans
);
1557 Reply to an SMBtranss2 request
1559 void smbsrv_reply_transs2(struct smbsrv_request
*req
)
1561 reply_transs_generic(req
, SMBtrans2
);