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
= IVAL(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;
138 req_pull_string(&req
->in
.bufinfo
, &io
->ntcreatex
.in
.fname
,
140 MIN(fname_len
+1, trans
->in
.params
.length
- 53),
141 STR_NO_RANGE_CHECK
| STR_TERMINATE
);
142 if (!io
->ntcreatex
.in
.fname
) {
143 return NT_STATUS_INVALID_PARAMETER
;
146 if (sd_length
> trans
->in
.data
.length
||
147 ea_length
> trans
->in
.data
.length
||
148 (sd_length
+ea_length
) > trans
->in
.data
.length
) {
149 return NT_STATUS_INVALID_PARAMETER
;
152 /* this call has an optional security descriptor */
153 if (sd_length
!= 0) {
155 blob
.data
= trans
->in
.data
.data
;
156 blob
.length
= sd_length
;
157 io
->ntcreatex
.in
.sec_desc
= talloc(io
, struct security_descriptor
);
158 if (io
->ntcreatex
.in
.sec_desc
== NULL
) {
159 return NT_STATUS_NO_MEMORY
;
161 ndr_err
= ndr_pull_struct_blob(&blob
, io
, NULL
,
162 io
->ntcreatex
.in
.sec_desc
,
163 (ndr_pull_flags_fn_t
)ndr_pull_security_descriptor
);
164 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
165 return ndr_map_error2ntstatus(ndr_err
);
169 /* and an optional ea_list */
172 blob
.data
= trans
->in
.data
.data
+ sd_length
;
173 blob
.length
= ea_length
;
174 io
->ntcreatex
.in
.ea_list
= talloc(io
, struct smb_ea_list
);
175 if (io
->ntcreatex
.in
.ea_list
== NULL
) {
176 return NT_STATUS_NO_MEMORY
;
179 status
= ea_pull_list_chained(&blob
, io
,
180 &io
->ntcreatex
.in
.ea_list
->num_eas
,
181 &io
->ntcreatex
.in
.ea_list
->eas
);
182 if (!NT_STATUS_IS_OK(status
)) {
187 op
->send_fn
= nttrans_create_send
;
190 return ntvfs_open(req
->ntvfs
, io
);
195 send NTTRANS_QUERY_SEC_DESC reply
197 static NTSTATUS
nttrans_query_sec_desc_send(struct nttrans_op
*op
)
199 union smb_fileinfo
*io
= talloc_get_type(op
->op_info
, union smb_fileinfo
);
202 enum ndr_err_code ndr_err
;
204 status
= nttrans_setup_reply(op
, op
->trans
, 4, 0, 0);
205 NT_STATUS_NOT_OK_RETURN(status
);
206 params
= op
->trans
->out
.params
.data
;
208 ndr_err
= ndr_push_struct_blob(&op
->trans
->out
.data
, op
, NULL
,
209 io
->query_secdesc
.out
.sd
,
210 (ndr_push_flags_fn_t
)ndr_push_security_descriptor
);
211 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
212 return ndr_map_error2ntstatus(ndr_err
);
215 SIVAL(params
, 0, op
->trans
->out
.data
.length
);
221 parse NTTRANS_QUERY_SEC_DESC request
223 static NTSTATUS
nttrans_query_sec_desc(struct smbsrv_request
*req
,
224 struct nttrans_op
*op
)
226 struct smb_nttrans
*trans
= op
->trans
;
227 union smb_fileinfo
*io
;
229 if (trans
->in
.params
.length
< 8) {
230 return NT_STATUS_INVALID_PARAMETER
;
233 /* parse the request */
234 io
= talloc(op
, union smb_fileinfo
);
235 NT_STATUS_HAVE_NO_MEMORY(io
);
237 io
->query_secdesc
.level
= RAW_FILEINFO_SEC_DESC
;
238 io
->query_secdesc
.in
.file
.ntvfs
= smbsrv_pull_fnum(req
, trans
->in
.params
.data
, 0);
239 io
->query_secdesc
.in
.secinfo_flags
= IVAL(trans
->in
.params
.data
, 4);
242 op
->send_fn
= nttrans_query_sec_desc_send
;
244 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(io
->query_secdesc
.in
.file
.ntvfs
);
245 return ntvfs_qfileinfo(req
->ntvfs
, io
);
250 parse NTTRANS_SET_SEC_DESC request
252 static NTSTATUS
nttrans_set_sec_desc(struct smbsrv_request
*req
,
253 struct nttrans_op
*op
)
255 struct smb_nttrans
*trans
= op
->trans
;
256 union smb_setfileinfo
*io
;
257 enum ndr_err_code ndr_err
;
259 if (trans
->in
.params
.length
< 8) {
260 return NT_STATUS_INVALID_PARAMETER
;
263 /* parse the request */
264 io
= talloc(req
, union smb_setfileinfo
);
265 NT_STATUS_HAVE_NO_MEMORY(io
);
267 io
->set_secdesc
.level
= RAW_SFILEINFO_SEC_DESC
;
268 io
->set_secdesc
.in
.file
.ntvfs
= smbsrv_pull_fnum(req
, trans
->in
.params
.data
, 0);
269 io
->set_secdesc
.in
.secinfo_flags
= IVAL(trans
->in
.params
.data
, 4);
271 io
->set_secdesc
.in
.sd
= talloc(io
, struct security_descriptor
);
272 NT_STATUS_HAVE_NO_MEMORY(io
->set_secdesc
.in
.sd
);
274 ndr_err
= ndr_pull_struct_blob(&trans
->in
.data
, req
, NULL
,
275 io
->set_secdesc
.in
.sd
,
276 (ndr_pull_flags_fn_t
)ndr_pull_security_descriptor
);
277 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
278 return ndr_map_error2ntstatus(ndr_err
);
281 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(io
->set_secdesc
.in
.file
.ntvfs
);
282 return ntvfs_setfileinfo(req
->ntvfs
, io
);
286 /* parse NTTRANS_RENAME request
288 static NTSTATUS
nttrans_rename(struct smbsrv_request
*req
,
289 struct nttrans_op
*op
)
291 struct smb_nttrans
*trans
= op
->trans
;
292 union smb_rename
*io
;
294 if (trans
->in
.params
.length
< 5) {
295 return NT_STATUS_INVALID_PARAMETER
;
298 /* parse the request */
299 io
= talloc(req
, union smb_rename
);
300 NT_STATUS_HAVE_NO_MEMORY(io
);
302 io
->nttrans
.level
= RAW_RENAME_NTTRANS
;
303 io
->nttrans
.in
.file
.ntvfs
= smbsrv_pull_fnum(req
, trans
->in
.params
.data
, 0);
304 io
->nttrans
.in
.flags
= SVAL(trans
->in
.params
.data
, 2);
306 smbsrv_blob_pull_string(&req
->in
.bufinfo
, &trans
->in
.params
, 4,
307 &io
->nttrans
.in
.new_name
,
309 if (!io
->nttrans
.in
.new_name
) {
310 return NT_STATUS_INVALID_PARAMETER
;
313 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(io
->nttrans
.in
.file
.ntvfs
);
314 return ntvfs_rename(req
->ntvfs
, io
);
318 parse NTTRANS_IOCTL send
320 static NTSTATUS
nttrans_ioctl_send(struct nttrans_op
*op
)
322 union smb_ioctl
*info
= talloc_get_type(op
->op_info
, union smb_ioctl
);
326 * we pass 0 as data_count here,
327 * because we reuse the DATA_BLOB from the smb_ioctl
330 status
= nttrans_setup_reply(op
, op
->trans
, 0, 0, 1);
331 NT_STATUS_NOT_OK_RETURN(status
);
333 op
->trans
->out
.setup
[0] = 0;
334 op
->trans
->out
.data
= info
->ntioctl
.out
.blob
;
341 parse NTTRANS_IOCTL request
343 static NTSTATUS
nttrans_ioctl(struct smbsrv_request
*req
,
344 struct nttrans_op
*op
)
346 struct smb_nttrans
*trans
= op
->trans
;
349 /* should have at least 4 setup words */
350 if (trans
->in
.setup_count
!= 4) {
351 return NT_STATUS_INVALID_PARAMETER
;
354 nt
= talloc(op
, union smb_ioctl
);
355 NT_STATUS_HAVE_NO_MEMORY(nt
);
357 nt
->ntioctl
.level
= RAW_IOCTL_NTIOCTL
;
358 nt
->ntioctl
.in
.function
= IVAL(trans
->in
.setup
, 0);
359 nt
->ntioctl
.in
.file
.ntvfs
= smbsrv_pull_fnum(req
, (uint8_t *)trans
->in
.setup
, 4);
360 nt
->ntioctl
.in
.fsctl
= CVAL(trans
->in
.setup
, 6);
361 nt
->ntioctl
.in
.filter
= CVAL(trans
->in
.setup
, 7);
362 nt
->ntioctl
.in
.max_data
= trans
->in
.max_data
;
363 nt
->ntioctl
.in
.blob
= trans
->in
.data
;
366 op
->send_fn
= nttrans_ioctl_send
;
368 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(nt
->ntioctl
.in
.file
.ntvfs
);
369 return ntvfs_ioctl(req
->ntvfs
, nt
);
374 send NTTRANS_NOTIFY_CHANGE reply
376 static NTSTATUS
nttrans_notify_change_send(struct nttrans_op
*op
)
378 union smb_notify
*info
= talloc_get_type(op
->op_info
, union smb_notify
);
383 #define MAX_BYTES_PER_CHAR 3
385 /* work out how big the reply buffer could be */
386 for (i
=0;i
<info
->nttrans
.out
.num_changes
;i
++) {
387 size
+= 12 + 3 + (1+strlen(info
->nttrans
.out
.changes
[i
].name
.s
)) * MAX_BYTES_PER_CHAR
;
390 status
= nttrans_setup_reply(op
, op
->trans
, size
, 0, 0);
391 NT_STATUS_NOT_OK_RETURN(status
);
392 p
= op
->trans
->out
.params
.data
;
394 /* construct the changes buffer */
395 for (i
=0;i
<info
->nttrans
.out
.num_changes
;i
++) {
399 SIVAL(p
, 4, info
->nttrans
.out
.changes
[i
].action
);
400 len
= push_string(p
+ 12, info
->nttrans
.out
.changes
[i
].name
.s
,
401 op
->trans
->out
.params
.length
-
402 (p
+12 - op
->trans
->out
.params
.data
), STR_UNICODE
);
408 int pad
= 4 - (ofs
& 3);
409 memset(p
+ofs
, 0, pad
);
413 if (i
== info
->nttrans
.out
.num_changes
-1) {
422 op
->trans
->out
.params
.length
= p
- op
->trans
->out
.params
.data
;
428 parse NTTRANS_NOTIFY_CHANGE request
430 static NTSTATUS
nttrans_notify_change(struct smbsrv_request
*req
,
431 struct nttrans_op
*op
)
433 struct smb_nttrans
*trans
= op
->trans
;
434 union smb_notify
*info
;
436 /* should have at least 4 setup words */
437 if (trans
->in
.setup_count
!= 4) {
438 return NT_STATUS_INVALID_PARAMETER
;
441 info
= talloc(op
, union smb_notify
);
442 NT_STATUS_HAVE_NO_MEMORY(info
);
444 info
->nttrans
.level
= RAW_NOTIFY_NTTRANS
;
445 info
->nttrans
.in
.completion_filter
= IVAL(trans
->in
.setup
, 0);
446 info
->nttrans
.in
.file
.ntvfs
= smbsrv_pull_fnum(req
, (uint8_t *)trans
->in
.setup
, 4);
447 info
->nttrans
.in
.recursive
= SVAL(trans
->in
.setup
, 6);
448 info
->nttrans
.in
.buffer_size
= trans
->in
.max_param
;
451 op
->send_fn
= nttrans_notify_change_send
;
453 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(info
->nttrans
.in
.file
.ntvfs
);
454 return ntvfs_notify(req
->ntvfs
, info
);
458 backend for nttrans requests
460 static NTSTATUS
nttrans_backend(struct smbsrv_request
*req
,
461 struct nttrans_op
*op
)
463 /* the nttrans command is in function */
464 switch (op
->trans
->in
.function
) {
465 case NT_TRANSACT_CREATE
:
466 return nttrans_create(req
, op
);
467 case NT_TRANSACT_IOCTL
:
468 return nttrans_ioctl(req
, op
);
469 case NT_TRANSACT_RENAME
:
470 return nttrans_rename(req
, op
);
471 case NT_TRANSACT_QUERY_SECURITY_DESC
:
472 return nttrans_query_sec_desc(req
, op
);
473 case NT_TRANSACT_SET_SECURITY_DESC
:
474 return nttrans_set_sec_desc(req
, op
);
475 case NT_TRANSACT_NOTIFY_CHANGE
:
476 return nttrans_notify_change(req
, op
);
479 /* an unknown nttrans command */
480 return NT_STATUS_DOS(ERRSRV
, ERRerror
);
484 static void reply_nttrans_send(struct ntvfs_request
*ntvfs
)
486 struct smbsrv_request
*req
;
487 uint32_t params_left
, data_left
;
488 uint8_t *params
, *data
;
489 struct smb_nttrans
*trans
;
490 struct nttrans_op
*op
;
492 SMBSRV_CHECK_ASYNC_STATUS(op
, struct nttrans_op
);
496 /* if this function needs work to form the nttrans reply buffer, then
498 if (op
->send_fn
!= NULL
) {
500 status
= op
->send_fn(op
);
501 if (!NT_STATUS_IS_OK(status
)) {
502 smbsrv_send_error(req
, status
);
507 smbsrv_setup_reply(req
, 18 + trans
->out
.setup_count
, 0);
509 /* note that we don't check the max_setup count (matching w2k3
512 if (trans
->out
.params
.length
> trans
->in
.max_param
) {
513 smbsrv_setup_error(req
, NT_STATUS_BUFFER_TOO_SMALL
);
514 trans
->out
.params
.length
= trans
->in
.max_param
;
516 if (trans
->out
.data
.length
> trans
->in
.max_data
) {
517 smbsrv_setup_error(req
, NT_STATUS_BUFFER_TOO_SMALL
);
518 trans
->out
.data
.length
= trans
->in
.max_data
;
521 params_left
= trans
->out
.params
.length
;
522 data_left
= trans
->out
.data
.length
;
523 params
= trans
->out
.params
.data
;
524 data
= trans
->out
.data
.data
;
526 /* we need to divide up the reply into chunks that fit into
527 the negotiated buffer size */
529 uint32_t this_data
, this_param
, max_bytes
;
530 uint_t align1
= 1, align2
= (params_left
? 2 : 0);
531 struct smbsrv_request
*this_req
;
533 max_bytes
= req_max_data(req
) - (align1
+ align2
);
535 this_param
= params_left
;
536 if (this_param
> max_bytes
) {
537 this_param
= max_bytes
;
539 max_bytes
-= this_param
;
541 this_data
= data_left
;
542 if (this_data
> max_bytes
) {
543 this_data
= max_bytes
;
546 /* don't destroy unless this is the last chunk */
547 if (params_left
- this_param
!= 0 ||
548 data_left
- this_data
!= 0) {
549 this_req
= smbsrv_setup_secondary_request(req
);
554 req_grow_data(this_req
, this_param
+ this_data
+ (align1
+ align2
));
556 SSVAL(this_req
->out
.vwv
, 0, 0); /* reserved */
557 SCVAL(this_req
->out
.vwv
, 2, 0); /* reserved */
558 SIVAL(this_req
->out
.vwv
, 3, trans
->out
.params
.length
);
559 SIVAL(this_req
->out
.vwv
, 7, trans
->out
.data
.length
);
561 SIVAL(this_req
->out
.vwv
, 11, this_param
);
562 SIVAL(this_req
->out
.vwv
, 15, align1
+ PTR_DIFF(this_req
->out
.data
, this_req
->out
.hdr
));
563 SIVAL(this_req
->out
.vwv
, 19, PTR_DIFF(params
, trans
->out
.params
.data
));
565 SIVAL(this_req
->out
.vwv
, 23, this_data
);
566 SIVAL(this_req
->out
.vwv
, 27, align1
+ align2
+
567 PTR_DIFF(this_req
->out
.data
+ this_param
, this_req
->out
.hdr
));
568 SIVAL(this_req
->out
.vwv
, 31, PTR_DIFF(data
, trans
->out
.data
.data
));
570 SCVAL(this_req
->out
.vwv
, 35, trans
->out
.setup_count
);
571 memcpy((char *)(this_req
->out
.vwv
) + VWV(18), trans
->out
.setup
,
572 sizeof(uint16_t) * trans
->out
.setup_count
);
573 memset(this_req
->out
.data
, 0, align1
);
574 if (this_param
!= 0) {
575 memcpy(this_req
->out
.data
+ align1
, params
, this_param
);
577 memset(this_req
->out
.data
+this_param
+align1
, 0, align2
);
578 if (this_data
!= 0) {
579 memcpy(this_req
->out
.data
+this_param
+align1
+align2
,
583 params_left
-= this_param
;
584 data_left
-= this_data
;
585 params
+= this_param
;
588 smbsrv_send_reply(this_req
);
589 } while (params_left
!= 0 || data_left
!= 0);
593 send a continue request
595 static void reply_nttrans_continue(struct smbsrv_request
*req
, struct smb_nttrans
*trans
)
597 struct smbsrv_request
*req2
;
598 struct smbsrv_trans_partial
*tp
;
601 /* make sure they don't flood us */
602 for (count
=0,tp
=req
->smb_conn
->trans_partial
;tp
;tp
=tp
->next
) count
++;
604 smbsrv_send_error(req
, NT_STATUS_INSUFFICIENT_RESOURCES
);
608 tp
= talloc(req
, struct smbsrv_trans_partial
);
611 tp
->u
.nttrans
= trans
;
612 tp
->command
= SMBnttrans
;
614 DLIST_ADD(req
->smb_conn
->trans_partial
, tp
);
615 talloc_set_destructor(tp
, smbsrv_trans_partial_destructor
);
617 req2
= smbsrv_setup_secondary_request(req
);
619 /* send a 'please continue' reply */
620 smbsrv_setup_reply(req2
, 0, 0);
621 smbsrv_send_reply(req2
);
626 answer a reconstructed trans request
628 static void reply_nttrans_complete(struct smbsrv_request
*req
, struct smb_nttrans
*trans
)
630 struct nttrans_op
*op
;
632 SMBSRV_TALLOC_IO_PTR(op
, struct nttrans_op
);
633 SMBSRV_SETUP_NTVFS_REQUEST(reply_nttrans_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
639 /* its a full request, give it to the backend */
640 ZERO_STRUCT(trans
->out
);
641 SMBSRV_CALL_NTVFS_BACKEND(nttrans_backend(req
, op
));
645 /****************************************************************************
646 Reply to an SMBnttrans request
647 ****************************************************************************/
648 void smbsrv_reply_nttrans(struct smbsrv_request
*req
)
650 struct smb_nttrans
*trans
;
651 uint32_t param_ofs
, data_ofs
;
652 uint32_t param_count
, data_count
;
653 uint32_t param_total
, data_total
;
656 if (req
->in
.wct
< 19) {
657 smbsrv_send_error(req
, NT_STATUS_FOOBAR
);
661 trans
= talloc(req
, struct smb_nttrans
);
663 smbsrv_send_error(req
, NT_STATUS_NO_MEMORY
);
667 trans
->in
.max_setup
= CVAL(req
->in
.vwv
, 0);
668 param_total
= IVAL(req
->in
.vwv
, 3);
669 data_total
= IVAL(req
->in
.vwv
, 7);
670 trans
->in
.max_param
= IVAL(req
->in
.vwv
, 11);
671 trans
->in
.max_data
= IVAL(req
->in
.vwv
, 15);
672 param_count
= IVAL(req
->in
.vwv
, 19);
673 param_ofs
= IVAL(req
->in
.vwv
, 23);
674 data_count
= IVAL(req
->in
.vwv
, 27);
675 data_ofs
= IVAL(req
->in
.vwv
, 31);
676 trans
->in
.setup_count
= CVAL(req
->in
.vwv
, 35);
677 trans
->in
.function
= SVAL(req
->in
.vwv
, 36);
679 if (req
->in
.wct
!= 19 + trans
->in
.setup_count
) {
680 smbsrv_send_error(req
, NT_STATUS_DOS(ERRSRV
, ERRerror
));
684 /* parse out the setup words */
685 trans
->in
.setup
= talloc_array(req
, uint8_t, trans
->in
.setup_count
*2);
686 if (!trans
->in
.setup
) {
687 smbsrv_send_error(req
, NT_STATUS_NO_MEMORY
);
690 memcpy(trans
->in
.setup
, (char *)(req
->in
.vwv
) + VWV(19),
691 sizeof(uint16_t) * trans
->in
.setup_count
);
693 if (!req_pull_blob(&req
->in
.bufinfo
, req
->in
.hdr
+ param_ofs
, param_count
, &trans
->in
.params
) ||
694 !req_pull_blob(&req
->in
.bufinfo
, req
->in
.hdr
+ data_ofs
, data_count
, &trans
->in
.data
)) {
695 smbsrv_send_error(req
, NT_STATUS_FOOBAR
);
699 /* is it a partial request? if so, then send a 'send more' message */
700 if (param_total
> param_count
|| data_total
> data_count
) {
701 reply_nttrans_continue(req
, trans
);
705 reply_nttrans_complete(req
, trans
);
709 /****************************************************************************
710 Reply to an SMBnttranss request
711 ****************************************************************************/
712 void smbsrv_reply_nttranss(struct smbsrv_request
*req
)
714 struct smbsrv_trans_partial
*tp
;
715 struct smb_nttrans
*trans
= NULL
;
716 uint32_t param_ofs
, data_ofs
;
717 uint32_t param_count
, data_count
;
718 uint32_t param_disp
, data_disp
;
719 uint32_t param_total
, data_total
;
720 DATA_BLOB params
, data
;
723 if (req
->in
.wct
!= 18) {
724 smbsrv_send_error(req
, NT_STATUS_DOS(ERRSRV
, ERRerror
));
728 for (tp
=req
->smb_conn
->trans_partial
;tp
;tp
=tp
->next
) {
729 if (tp
->command
== SMBnttrans
&&
730 SVAL(tp
->req
->in
.hdr
, HDR_MID
) == SVAL(req
->in
.hdr
, HDR_MID
)) {
731 /* TODO: check the VUID, PID and TID too? */
737 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
741 trans
= tp
->u
.nttrans
;
743 param_total
= IVAL(req
->in
.vwv
, 3);
744 data_total
= IVAL(req
->in
.vwv
, 7);
745 param_count
= IVAL(req
->in
.vwv
, 11);
746 param_ofs
= IVAL(req
->in
.vwv
, 15);
747 param_disp
= IVAL(req
->in
.vwv
, 19);
748 data_count
= IVAL(req
->in
.vwv
, 23);
749 data_ofs
= IVAL(req
->in
.vwv
, 27);
750 data_disp
= IVAL(req
->in
.vwv
, 31);
752 if (!req_pull_blob(&req
->in
.bufinfo
, req
->in
.hdr
+ param_ofs
, param_count
, ¶ms
) ||
753 !req_pull_blob(&req
->in
.bufinfo
, req
->in
.hdr
+ data_ofs
, data_count
, &data
)) {
754 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
758 /* only allow contiguous requests */
759 if ((param_count
!= 0 &&
760 param_disp
!= trans
->in
.params
.length
) ||
762 data_disp
!= trans
->in
.data
.length
)) {
763 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
767 /* add to the existing request */
768 if (param_count
!= 0) {
769 trans
->in
.params
.data
= talloc_realloc(trans
,
770 trans
->in
.params
.data
,
772 param_disp
+ param_count
);
773 if (trans
->in
.params
.data
== NULL
) {
774 smbsrv_send_error(tp
->req
, NT_STATUS_NO_MEMORY
);
777 trans
->in
.params
.length
= param_disp
+ param_count
;
780 if (data_count
!= 0) {
781 trans
->in
.data
.data
= talloc_realloc(trans
,
784 data_disp
+ data_count
);
785 if (trans
->in
.data
.data
== NULL
) {
786 smbsrv_send_error(tp
->req
, NT_STATUS_NO_MEMORY
);
789 trans
->in
.data
.length
= data_disp
+ data_count
;
792 memcpy(trans
->in
.params
.data
+ param_disp
, params
.data
, params
.length
);
793 memcpy(trans
->in
.data
.data
+ data_disp
, data
.data
, data
.length
);
795 /* the sequence number of the reply is taken from the last secondary
797 tp
->req
->seq_num
= req
->seq_num
;
799 /* we don't reply to Transs2 requests */
802 if (trans
->in
.params
.length
== param_total
&&
803 trans
->in
.data
.length
== data_total
) {
804 /* its now complete */
807 reply_nttrans_complete(req
, trans
);