2 Unix SMB/CIFS implementation.
3 NT transaction handling
4 Copyright (C) Andrew Tridgell 2003
5 Copyright (C) James J Myers 2003 <myersjj@samba.org>
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 "smb_server/smb_server.h"
26 #include "ntvfs/ntvfs.h"
27 #include "libcli/raw/libcliraw.h"
28 #include "libcli/raw/raw_proto.h"
29 #include "librpc/gen_ndr/ndr_security.h"
32 hold the state of a nttrans op while in progress. Needed to allow for async backend
36 struct smb_nttrans
*trans
;
37 NTSTATUS (*send_fn
)(struct nttrans_op
*);
42 /* setup a nttrans reply, given the data and params sizes */
43 static NTSTATUS
nttrans_setup_reply(struct nttrans_op
*op
,
44 struct smb_nttrans
*trans
,
45 uint32_t param_size
, uint32_t data_size
,
48 trans
->out
.setup_count
= setup_count
;
49 if (setup_count
!= 0) {
50 trans
->out
.setup
= talloc_zero_array(op
, uint8_t, setup_count
*2);
51 NT_STATUS_HAVE_NO_MEMORY(trans
->out
.setup
);
53 trans
->out
.params
= data_blob_talloc(op
, NULL
, param_size
);
54 if (param_size
!= 0) {
55 NT_STATUS_HAVE_NO_MEMORY(trans
->out
.params
.data
);
57 trans
->out
.data
= data_blob_talloc(op
, NULL
, data_size
);
59 NT_STATUS_HAVE_NO_MEMORY(trans
->out
.data
.data
);
65 send a nttrans create reply
67 static NTSTATUS
nttrans_create_send(struct nttrans_op
*op
)
69 union smb_open
*io
= talloc_get_type(op
->op_info
, union smb_open
);
73 status
= nttrans_setup_reply(op
, op
->trans
, 69, 0, 0);
74 NT_STATUS_NOT_OK_RETURN(status
);
75 params
= op
->trans
->out
.params
.data
;
77 SSVAL(params
, 0, io
->ntcreatex
.out
.oplock_level
);
78 smbsrv_push_fnum(params
, 2, io
->ntcreatex
.out
.file
.ntvfs
);
79 SIVAL(params
, 4, io
->ntcreatex
.out
.create_action
);
80 SIVAL(params
, 8, 0); /* ea error offset */
81 push_nttime(params
, 12, io
->ntcreatex
.out
.create_time
);
82 push_nttime(params
, 20, io
->ntcreatex
.out
.access_time
);
83 push_nttime(params
, 28, io
->ntcreatex
.out
.write_time
);
84 push_nttime(params
, 36, io
->ntcreatex
.out
.change_time
);
85 SIVAL(params
, 44, io
->ntcreatex
.out
.attrib
);
86 SBVAL(params
, 48, io
->ntcreatex
.out
.alloc_size
);
87 SBVAL(params
, 56, io
->ntcreatex
.out
.size
);
88 SSVAL(params
, 64, io
->ntcreatex
.out
.file_type
);
89 SSVAL(params
, 66, io
->ntcreatex
.out
.ipc_state
);
90 SCVAL(params
, 68, io
->ntcreatex
.out
.is_directory
);
96 parse NTTRANS_CREATE request
98 static NTSTATUS
nttrans_create(struct smbsrv_request
*req
,
99 struct nttrans_op
*op
)
101 struct smb_nttrans
*trans
= op
->trans
;
104 uint32_t sd_length
, ea_length
;
107 enum ndr_err_code ndr_err
;
109 if (trans
->in
.params
.length
< 54) {
110 return NT_STATUS_INVALID_PARAMETER
;
113 /* parse the request */
114 io
= talloc(op
, union smb_open
);
115 NT_STATUS_HAVE_NO_MEMORY(io
);
117 io
->ntcreatex
.level
= RAW_OPEN_NTTRANS_CREATE
;
119 params
= trans
->in
.params
.data
;
121 io
->ntcreatex
.in
.flags
= IVAL(params
, 0);
122 io
->ntcreatex
.in
.root_fid
.ntvfs
= smbsrv_pull_fnum(req
, params
, 4);
123 io
->ntcreatex
.in
.access_mask
= IVAL(params
, 8);
124 io
->ntcreatex
.in
.alloc_size
= BVAL(params
, 12);
125 io
->ntcreatex
.in
.file_attr
= IVAL(params
, 20);
126 io
->ntcreatex
.in
.share_access
= IVAL(params
, 24);
127 io
->ntcreatex
.in
.open_disposition
= IVAL(params
, 28);
128 io
->ntcreatex
.in
.create_options
= IVAL(params
, 32);
129 sd_length
= IVAL(params
, 36);
130 ea_length
= IVAL(params
, 40);
131 fname_len
= IVAL(params
, 44);
132 io
->ntcreatex
.in
.impersonation
= IVAL(params
, 48);
133 io
->ntcreatex
.in
.security_flags
= CVAL(params
, 52);
134 io
->ntcreatex
.in
.sec_desc
= NULL
;
135 io
->ntcreatex
.in
.ea_list
= NULL
;
136 io
->ntcreatex
.in
.query_maximal_access
= false;
137 io
->ntcreatex
.in
.query_on_disk_id
= false;
138 io
->ntcreatex
.in
.private_flags
= 0;
140 req_pull_string(&req
->in
.bufinfo
, &io
->ntcreatex
.in
.fname
,
142 MIN(fname_len
+1, trans
->in
.params
.length
- 53),
143 STR_NO_RANGE_CHECK
| STR_TERMINATE
);
144 if (!io
->ntcreatex
.in
.fname
) {
145 return NT_STATUS_INVALID_PARAMETER
;
148 if (sd_length
> trans
->in
.data
.length
||
149 ea_length
> trans
->in
.data
.length
||
150 (sd_length
+ea_length
) > trans
->in
.data
.length
) {
151 return NT_STATUS_INVALID_PARAMETER
;
154 /* this call has an optional security descriptor */
155 if (sd_length
!= 0) {
157 blob
.data
= trans
->in
.data
.data
;
158 blob
.length
= sd_length
;
159 io
->ntcreatex
.in
.sec_desc
= talloc(io
, struct security_descriptor
);
160 if (io
->ntcreatex
.in
.sec_desc
== NULL
) {
161 return NT_STATUS_NO_MEMORY
;
163 ndr_err
= ndr_pull_struct_blob(&blob
, io
,
164 io
->ntcreatex
.in
.sec_desc
,
165 (ndr_pull_flags_fn_t
)ndr_pull_security_descriptor
);
166 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
167 return ndr_map_error2ntstatus(ndr_err
);
171 /* and an optional ea_list */
174 blob
.data
= trans
->in
.data
.data
+ sd_length
;
175 blob
.length
= ea_length
;
176 io
->ntcreatex
.in
.ea_list
= talloc(io
, struct smb_ea_list
);
177 if (io
->ntcreatex
.in
.ea_list
== NULL
) {
178 return NT_STATUS_NO_MEMORY
;
181 status
= ea_pull_list_chained(&blob
, io
,
182 &io
->ntcreatex
.in
.ea_list
->num_eas
,
183 &io
->ntcreatex
.in
.ea_list
->eas
);
184 if (!NT_STATUS_IS_OK(status
)) {
189 op
->send_fn
= nttrans_create_send
;
192 return ntvfs_open(req
->ntvfs
, io
);
197 send NTTRANS_QUERY_SEC_DESC reply
199 static NTSTATUS
nttrans_query_sec_desc_send(struct nttrans_op
*op
)
201 union smb_fileinfo
*io
= talloc_get_type(op
->op_info
, union smb_fileinfo
);
204 enum ndr_err_code ndr_err
;
206 status
= nttrans_setup_reply(op
, op
->trans
, 4, 0, 0);
207 NT_STATUS_NOT_OK_RETURN(status
);
208 params
= op
->trans
->out
.params
.data
;
210 ndr_err
= ndr_push_struct_blob(&op
->trans
->out
.data
, op
,
211 io
->query_secdesc
.out
.sd
,
212 (ndr_push_flags_fn_t
)ndr_push_security_descriptor
);
213 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
214 return ndr_map_error2ntstatus(ndr_err
);
217 SIVAL(params
, 0, op
->trans
->out
.data
.length
);
223 parse NTTRANS_QUERY_SEC_DESC request
225 static NTSTATUS
nttrans_query_sec_desc(struct smbsrv_request
*req
,
226 struct nttrans_op
*op
)
228 struct smb_nttrans
*trans
= op
->trans
;
229 union smb_fileinfo
*io
;
231 if (trans
->in
.params
.length
< 8) {
232 return NT_STATUS_INVALID_PARAMETER
;
235 /* parse the request */
236 io
= talloc(op
, union smb_fileinfo
);
237 NT_STATUS_HAVE_NO_MEMORY(io
);
239 io
->query_secdesc
.level
= RAW_FILEINFO_SEC_DESC
;
240 io
->query_secdesc
.in
.file
.ntvfs
= smbsrv_pull_fnum(req
, trans
->in
.params
.data
, 0);
241 io
->query_secdesc
.in
.secinfo_flags
= IVAL(trans
->in
.params
.data
, 4);
244 op
->send_fn
= nttrans_query_sec_desc_send
;
246 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(io
->query_secdesc
.in
.file
.ntvfs
);
247 return ntvfs_qfileinfo(req
->ntvfs
, io
);
252 parse NTTRANS_SET_SEC_DESC request
254 static NTSTATUS
nttrans_set_sec_desc(struct smbsrv_request
*req
,
255 struct nttrans_op
*op
)
257 struct smb_nttrans
*trans
= op
->trans
;
258 union smb_setfileinfo
*io
;
259 enum ndr_err_code ndr_err
;
261 if (trans
->in
.params
.length
< 8) {
262 return NT_STATUS_INVALID_PARAMETER
;
265 /* parse the request */
266 io
= talloc(req
, union smb_setfileinfo
);
267 NT_STATUS_HAVE_NO_MEMORY(io
);
269 io
->set_secdesc
.level
= RAW_SFILEINFO_SEC_DESC
;
270 io
->set_secdesc
.in
.file
.ntvfs
= smbsrv_pull_fnum(req
, trans
->in
.params
.data
, 0);
271 io
->set_secdesc
.in
.secinfo_flags
= IVAL(trans
->in
.params
.data
, 4);
273 io
->set_secdesc
.in
.sd
= talloc(io
, struct security_descriptor
);
274 NT_STATUS_HAVE_NO_MEMORY(io
->set_secdesc
.in
.sd
);
276 ndr_err
= ndr_pull_struct_blob(&trans
->in
.data
, req
,
277 io
->set_secdesc
.in
.sd
,
278 (ndr_pull_flags_fn_t
)ndr_pull_security_descriptor
);
279 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
280 return ndr_map_error2ntstatus(ndr_err
);
283 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(io
->set_secdesc
.in
.file
.ntvfs
);
284 return ntvfs_setfileinfo(req
->ntvfs
, io
);
288 /* parse NTTRANS_RENAME request
290 static NTSTATUS
nttrans_rename(struct smbsrv_request
*req
,
291 struct nttrans_op
*op
)
293 struct smb_nttrans
*trans
= op
->trans
;
294 union smb_rename
*io
;
296 if (trans
->in
.params
.length
< 5) {
297 return NT_STATUS_INVALID_PARAMETER
;
300 /* parse the request */
301 io
= talloc(req
, union smb_rename
);
302 NT_STATUS_HAVE_NO_MEMORY(io
);
304 io
->nttrans
.level
= RAW_RENAME_NTTRANS
;
305 io
->nttrans
.in
.file
.ntvfs
= smbsrv_pull_fnum(req
, trans
->in
.params
.data
, 0);
306 io
->nttrans
.in
.flags
= SVAL(trans
->in
.params
.data
, 2);
308 smbsrv_blob_pull_string(&req
->in
.bufinfo
, &trans
->in
.params
, 4,
309 &io
->nttrans
.in
.new_name
,
311 if (!io
->nttrans
.in
.new_name
) {
312 return NT_STATUS_INVALID_PARAMETER
;
315 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(io
->nttrans
.in
.file
.ntvfs
);
316 return ntvfs_rename(req
->ntvfs
, io
);
320 parse NTTRANS_IOCTL send
322 static NTSTATUS
nttrans_ioctl_send(struct nttrans_op
*op
)
324 union smb_ioctl
*info
= talloc_get_type(op
->op_info
, union smb_ioctl
);
328 * we pass 0 as data_count here,
329 * because we reuse the DATA_BLOB from the smb_ioctl
332 status
= nttrans_setup_reply(op
, op
->trans
, 0, 0, 1);
333 NT_STATUS_NOT_OK_RETURN(status
);
335 op
->trans
->out
.setup
[0] = 0;
336 op
->trans
->out
.data
= info
->ntioctl
.out
.blob
;
343 parse NTTRANS_IOCTL request
345 static NTSTATUS
nttrans_ioctl(struct smbsrv_request
*req
,
346 struct nttrans_op
*op
)
348 struct smb_nttrans
*trans
= op
->trans
;
351 /* should have at least 4 setup words */
352 if (trans
->in
.setup_count
!= 4) {
353 return NT_STATUS_INVALID_PARAMETER
;
356 nt
= talloc(op
, union smb_ioctl
);
357 NT_STATUS_HAVE_NO_MEMORY(nt
);
359 nt
->ntioctl
.level
= RAW_IOCTL_NTIOCTL
;
360 nt
->ntioctl
.in
.function
= IVAL(trans
->in
.setup
, 0);
361 nt
->ntioctl
.in
.file
.ntvfs
= smbsrv_pull_fnum(req
, (uint8_t *)trans
->in
.setup
, 4);
362 nt
->ntioctl
.in
.fsctl
= CVAL(trans
->in
.setup
, 6);
363 nt
->ntioctl
.in
.filter
= CVAL(trans
->in
.setup
, 7);
364 nt
->ntioctl
.in
.max_data
= trans
->in
.max_data
;
365 nt
->ntioctl
.in
.blob
= trans
->in
.data
;
368 op
->send_fn
= nttrans_ioctl_send
;
370 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(nt
->ntioctl
.in
.file
.ntvfs
);
371 return ntvfs_ioctl(req
->ntvfs
, nt
);
376 send NTTRANS_NOTIFY_CHANGE reply
378 static NTSTATUS
nttrans_notify_change_send(struct nttrans_op
*op
)
380 union smb_notify
*info
= talloc_get_type(op
->op_info
, union smb_notify
);
385 #define MAX_BYTES_PER_CHAR 3
387 /* work out how big the reply buffer could be */
388 for (i
=0;i
<info
->nttrans
.out
.num_changes
;i
++) {
389 size
+= 12 + 3 + (1+strlen(info
->nttrans
.out
.changes
[i
].name
.s
)) * MAX_BYTES_PER_CHAR
;
392 status
= nttrans_setup_reply(op
, op
->trans
, size
, 0, 0);
393 NT_STATUS_NOT_OK_RETURN(status
);
394 p
= op
->trans
->out
.params
.data
;
396 /* construct the changes buffer */
397 for (i
=0;i
<info
->nttrans
.out
.num_changes
;i
++) {
401 SIVAL(p
, 4, info
->nttrans
.out
.changes
[i
].action
);
402 len
= push_string(p
+ 12, info
->nttrans
.out
.changes
[i
].name
.s
,
403 op
->trans
->out
.params
.length
-
404 (p
+12 - op
->trans
->out
.params
.data
), STR_UNICODE
);
410 int pad
= 4 - (ofs
& 3);
411 memset(p
+ofs
, 0, pad
);
415 if (i
== info
->nttrans
.out
.num_changes
-1) {
424 op
->trans
->out
.params
.length
= p
- op
->trans
->out
.params
.data
;
430 parse NTTRANS_NOTIFY_CHANGE request
432 static NTSTATUS
nttrans_notify_change(struct smbsrv_request
*req
,
433 struct nttrans_op
*op
)
435 struct smb_nttrans
*trans
= op
->trans
;
436 union smb_notify
*info
;
438 /* should have at least 4 setup words */
439 if (trans
->in
.setup_count
!= 4) {
440 return NT_STATUS_INVALID_PARAMETER
;
443 info
= talloc(op
, union smb_notify
);
444 NT_STATUS_HAVE_NO_MEMORY(info
);
446 info
->nttrans
.level
= RAW_NOTIFY_NTTRANS
;
447 info
->nttrans
.in
.completion_filter
= IVAL(trans
->in
.setup
, 0);
448 info
->nttrans
.in
.file
.ntvfs
= smbsrv_pull_fnum(req
, (uint8_t *)trans
->in
.setup
, 4);
449 info
->nttrans
.in
.recursive
= SVAL(trans
->in
.setup
, 6);
450 info
->nttrans
.in
.buffer_size
= trans
->in
.max_param
;
453 op
->send_fn
= nttrans_notify_change_send
;
455 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(info
->nttrans
.in
.file
.ntvfs
);
456 return ntvfs_notify(req
->ntvfs
, info
);
460 backend for nttrans requests
462 static NTSTATUS
nttrans_backend(struct smbsrv_request
*req
,
463 struct nttrans_op
*op
)
465 /* the nttrans command is in function */
466 switch (op
->trans
->in
.function
) {
467 case NT_TRANSACT_CREATE
:
468 return nttrans_create(req
, op
);
469 case NT_TRANSACT_IOCTL
:
470 return nttrans_ioctl(req
, op
);
471 case NT_TRANSACT_RENAME
:
472 return nttrans_rename(req
, op
);
473 case NT_TRANSACT_QUERY_SECURITY_DESC
:
474 return nttrans_query_sec_desc(req
, op
);
475 case NT_TRANSACT_SET_SECURITY_DESC
:
476 return nttrans_set_sec_desc(req
, op
);
477 case NT_TRANSACT_NOTIFY_CHANGE
:
478 return nttrans_notify_change(req
, op
);
481 /* an unknown nttrans command */
482 return NT_STATUS_DOS(ERRSRV
, ERRerror
);
486 static void reply_nttrans_send(struct ntvfs_request
*ntvfs
)
488 struct smbsrv_request
*req
;
489 uint32_t params_left
, data_left
;
490 uint8_t *params
, *data
;
491 struct smb_nttrans
*trans
;
492 struct nttrans_op
*op
;
494 SMBSRV_CHECK_ASYNC_STATUS(op
, struct nttrans_op
);
498 /* if this function needs work to form the nttrans reply buffer, then
500 if (op
->send_fn
!= NULL
) {
502 status
= op
->send_fn(op
);
503 if (!NT_STATUS_IS_OK(status
)) {
504 smbsrv_send_error(req
, status
);
509 smbsrv_setup_reply(req
, 18 + trans
->out
.setup_count
, 0);
511 /* note that we don't check the max_setup count (matching w2k3
514 if (trans
->out
.params
.length
> trans
->in
.max_param
) {
515 smbsrv_setup_error(req
, NT_STATUS_BUFFER_TOO_SMALL
);
516 trans
->out
.params
.length
= trans
->in
.max_param
;
518 if (trans
->out
.data
.length
> trans
->in
.max_data
) {
519 smbsrv_setup_error(req
, NT_STATUS_BUFFER_TOO_SMALL
);
520 trans
->out
.data
.length
= trans
->in
.max_data
;
523 params_left
= trans
->out
.params
.length
;
524 data_left
= trans
->out
.data
.length
;
525 params
= trans
->out
.params
.data
;
526 data
= trans
->out
.data
.data
;
528 /* we need to divide up the reply into chunks that fit into
529 the negotiated buffer size */
531 uint32_t this_data
, this_param
, max_bytes
;
532 unsigned int align1
= 1, align2
= (params_left
? 2 : 0);
533 struct smbsrv_request
*this_req
;
535 max_bytes
= req_max_data(req
) - (align1
+ align2
);
537 this_param
= params_left
;
538 if (this_param
> max_bytes
) {
539 this_param
= max_bytes
;
541 max_bytes
-= this_param
;
543 this_data
= data_left
;
544 if (this_data
> max_bytes
) {
545 this_data
= max_bytes
;
548 /* don't destroy unless this is the last chunk */
549 if (params_left
- this_param
!= 0 ||
550 data_left
- this_data
!= 0) {
551 this_req
= smbsrv_setup_secondary_request(req
);
556 req_grow_data(this_req
, this_param
+ this_data
+ (align1
+ align2
));
558 SSVAL(this_req
->out
.vwv
, 0, 0); /* reserved */
559 SCVAL(this_req
->out
.vwv
, 2, 0); /* reserved */
560 SIVAL(this_req
->out
.vwv
, 3, trans
->out
.params
.length
);
561 SIVAL(this_req
->out
.vwv
, 7, trans
->out
.data
.length
);
563 SIVAL(this_req
->out
.vwv
, 11, this_param
);
564 SIVAL(this_req
->out
.vwv
, 15, align1
+ PTR_DIFF(this_req
->out
.data
, this_req
->out
.hdr
));
565 SIVAL(this_req
->out
.vwv
, 19, PTR_DIFF(params
, trans
->out
.params
.data
));
567 SIVAL(this_req
->out
.vwv
, 23, this_data
);
568 SIVAL(this_req
->out
.vwv
, 27, align1
+ align2
+
569 PTR_DIFF(this_req
->out
.data
+ this_param
, this_req
->out
.hdr
));
570 SIVAL(this_req
->out
.vwv
, 31, PTR_DIFF(data
, trans
->out
.data
.data
));
572 SCVAL(this_req
->out
.vwv
, 35, trans
->out
.setup_count
);
573 if (trans
->out
.setup_count
> 0) {
574 memcpy((char *)(this_req
->out
.vwv
) + VWV(18),
576 sizeof(uint16_t) * trans
->out
.setup_count
);
578 memset(this_req
->out
.data
, 0, align1
);
579 if (this_param
!= 0) {
580 memcpy(this_req
->out
.data
+ align1
, params
, this_param
);
582 memset(this_req
->out
.data
+this_param
+align1
, 0, align2
);
583 if (this_data
!= 0) {
584 memcpy(this_req
->out
.data
+this_param
+align1
+align2
,
588 params_left
-= this_param
;
589 data_left
-= this_data
;
590 params
+= this_param
;
593 smbsrv_send_reply(this_req
);
594 } while (params_left
!= 0 || data_left
!= 0);
598 send a continue request
600 static void reply_nttrans_continue(struct smbsrv_request
*req
, struct smb_nttrans
*trans
)
602 struct smbsrv_request
*req2
;
603 struct smbsrv_trans_partial
*tp
;
606 /* make sure they don't flood us */
607 for (count
=0,tp
=req
->smb_conn
->trans_partial
;tp
;tp
=tp
->next
) count
++;
609 smbsrv_send_error(req
, NT_STATUS_INSUFFICIENT_RESOURCES
);
613 tp
= talloc(req
, struct smbsrv_trans_partial
);
616 tp
->u
.nttrans
= trans
;
617 tp
->command
= SMBnttrans
;
619 DLIST_ADD(req
->smb_conn
->trans_partial
, tp
);
620 talloc_set_destructor(tp
, smbsrv_trans_partial_destructor
);
622 req2
= smbsrv_setup_secondary_request(req
);
624 /* send a 'please continue' reply */
625 smbsrv_setup_reply(req2
, 0, 0);
626 smbsrv_send_reply(req2
);
631 answer a reconstructed trans request
633 static void reply_nttrans_complete(struct smbsrv_request
*req
, struct smb_nttrans
*trans
)
635 struct nttrans_op
*op
;
637 SMBSRV_TALLOC_IO_PTR(op
, struct nttrans_op
);
638 SMBSRV_SETUP_NTVFS_REQUEST(reply_nttrans_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
644 /* its a full request, give it to the backend */
645 ZERO_STRUCT(trans
->out
);
646 SMBSRV_CALL_NTVFS_BACKEND(nttrans_backend(req
, op
));
650 /****************************************************************************
651 Reply to an SMBnttrans request
652 ****************************************************************************/
653 void smbsrv_reply_nttrans(struct smbsrv_request
*req
)
655 struct smb_nttrans
*trans
;
656 uint32_t param_ofs
, data_ofs
;
657 uint32_t param_count
, data_count
;
658 uint32_t param_total
, data_total
;
661 if (req
->in
.wct
< 19) {
662 smbsrv_send_error(req
, NT_STATUS_FOOBAR
);
666 trans
= talloc(req
, struct smb_nttrans
);
668 smbsrv_send_error(req
, NT_STATUS_NO_MEMORY
);
672 trans
->in
.max_setup
= CVAL(req
->in
.vwv
, 0);
673 param_total
= IVAL(req
->in
.vwv
, 3);
674 data_total
= IVAL(req
->in
.vwv
, 7);
675 trans
->in
.max_param
= IVAL(req
->in
.vwv
, 11);
676 trans
->in
.max_data
= IVAL(req
->in
.vwv
, 15);
677 param_count
= IVAL(req
->in
.vwv
, 19);
678 param_ofs
= IVAL(req
->in
.vwv
, 23);
679 data_count
= IVAL(req
->in
.vwv
, 27);
680 data_ofs
= IVAL(req
->in
.vwv
, 31);
681 trans
->in
.setup_count
= CVAL(req
->in
.vwv
, 35);
682 trans
->in
.function
= SVAL(req
->in
.vwv
, 36);
684 if (req
->in
.wct
!= 19 + trans
->in
.setup_count
) {
685 smbsrv_send_error(req
, NT_STATUS_DOS(ERRSRV
, ERRerror
));
689 /* parse out the setup words */
690 trans
->in
.setup
= talloc_array(req
, uint8_t, trans
->in
.setup_count
*2);
691 if (!trans
->in
.setup
) {
692 smbsrv_send_error(req
, NT_STATUS_NO_MEMORY
);
695 memcpy(trans
->in
.setup
, (char *)(req
->in
.vwv
) + VWV(19),
696 sizeof(uint16_t) * trans
->in
.setup_count
);
698 if (!req_pull_blob(&req
->in
.bufinfo
, req
->in
.hdr
+ param_ofs
, param_count
, &trans
->in
.params
) ||
699 !req_pull_blob(&req
->in
.bufinfo
, req
->in
.hdr
+ data_ofs
, data_count
, &trans
->in
.data
)) {
700 smbsrv_send_error(req
, NT_STATUS_FOOBAR
);
704 /* is it a partial request? if so, then send a 'send more' message */
705 if (param_total
> param_count
|| data_total
> data_count
) {
706 reply_nttrans_continue(req
, trans
);
710 reply_nttrans_complete(req
, trans
);
714 /****************************************************************************
715 Reply to an SMBnttranss request
716 ****************************************************************************/
717 void smbsrv_reply_nttranss(struct smbsrv_request
*req
)
719 struct smbsrv_trans_partial
*tp
;
720 struct smb_nttrans
*trans
= NULL
;
721 uint32_t param_ofs
, data_ofs
;
722 uint32_t param_count
, data_count
;
723 uint32_t param_disp
, data_disp
;
724 uint32_t param_total
, data_total
;
725 DATA_BLOB params
, data
;
728 if (req
->in
.wct
!= 18) {
729 smbsrv_send_error(req
, NT_STATUS_DOS(ERRSRV
, ERRerror
));
733 for (tp
=req
->smb_conn
->trans_partial
;tp
;tp
=tp
->next
) {
734 if (tp
->command
== SMBnttrans
&&
735 SVAL(tp
->req
->in
.hdr
, HDR_MID
) == SVAL(req
->in
.hdr
, HDR_MID
)) {
736 /* TODO: check the VUID, PID and TID too? */
742 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
746 trans
= tp
->u
.nttrans
;
748 param_total
= IVAL(req
->in
.vwv
, 3);
749 data_total
= IVAL(req
->in
.vwv
, 7);
750 param_count
= IVAL(req
->in
.vwv
, 11);
751 param_ofs
= IVAL(req
->in
.vwv
, 15);
752 param_disp
= IVAL(req
->in
.vwv
, 19);
753 data_count
= IVAL(req
->in
.vwv
, 23);
754 data_ofs
= IVAL(req
->in
.vwv
, 27);
755 data_disp
= IVAL(req
->in
.vwv
, 31);
757 if (!req_pull_blob(&req
->in
.bufinfo
, req
->in
.hdr
+ param_ofs
, param_count
, ¶ms
) ||
758 !req_pull_blob(&req
->in
.bufinfo
, req
->in
.hdr
+ data_ofs
, data_count
, &data
)) {
759 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
763 /* only allow contiguous requests */
764 if ((param_count
!= 0 &&
765 param_disp
!= trans
->in
.params
.length
) ||
767 data_disp
!= trans
->in
.data
.length
)) {
768 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
772 /* add to the existing request */
773 if (param_count
!= 0) {
774 trans
->in
.params
.data
= talloc_realloc(trans
,
775 trans
->in
.params
.data
,
777 param_disp
+ param_count
);
778 if (trans
->in
.params
.data
== NULL
) {
779 smbsrv_send_error(tp
->req
, NT_STATUS_NO_MEMORY
);
782 trans
->in
.params
.length
= param_disp
+ param_count
;
785 if (data_count
!= 0) {
786 trans
->in
.data
.data
= talloc_realloc(trans
,
789 data_disp
+ data_count
);
790 if (trans
->in
.data
.data
== NULL
) {
791 smbsrv_send_error(tp
->req
, NT_STATUS_NO_MEMORY
);
794 trans
->in
.data
.length
= data_disp
+ data_count
;
797 memcpy(trans
->in
.params
.data
+ param_disp
, params
.data
, params
.length
);
798 memcpy(trans
->in
.data
.data
+ data_disp
, data
.data
, data
.length
);
800 /* the sequence number of the reply is taken from the last secondary
802 tp
->req
->seq_num
= req
->seq_num
;
804 /* we don't reply to Transs2 requests */
807 if (trans
->in
.params
.length
== param_total
&&
808 trans
->in
.data
.length
== data_total
) {
809 /* its now complete */
812 reply_nttrans_complete(req
, trans
);