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