r21187: - Convert LdbBrowse to use TreeVirtual. This adds the following capabilities
[Samba/ekacnet.git] / source4 / smb_server / smb / trans2.c
blob1f34dfa4b40ccf671faf8265b67b24442fbbee3c
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 2 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, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 This file handles the parsing of transact2 requests
24 #include "includes.h"
25 #include "lib/util/dlinklist.h"
26 #include "smb_server/smb_server.h"
27 #include "librpc/gen_ndr/ndr_misc.h"
28 #include "ntvfs/ntvfs.h"
29 #include "libcli/raw/libcliraw.h"
31 #define TRANS2_CHECK_ASYNC_STATUS_SIMPLE do { \
32 if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) { \
33 trans2_setup_reply(trans, 0, 0, 0);\
34 return req->ntvfs->async_states->status; \
35 } \
36 } while (0)
37 #define TRANS2_CHECK_ASYNC_STATUS(ptr, type) do { \
38 TRANS2_CHECK_ASYNC_STATUS_SIMPLE; \
39 ptr = talloc_get_type(op->op_info, type); \
40 } while (0)
41 #define TRANS2_CHECK(cmd) do { \
42 NTSTATUS _status; \
43 _status = cmd; \
44 NT_STATUS_NOT_OK_RETURN(_status); \
45 } while (0)
48 hold the state of a nttrans op while in progress. Needed to allow for async backend
49 functions.
51 struct trans_op {
52 struct smbsrv_request *req;
53 struct smb_trans2 *trans;
54 uint8_t command;
55 NTSTATUS (*send_fn)(struct trans_op *);
56 void *op_info;
59 #define CHECK_MIN_BLOB_SIZE(blob, size) do { \
60 if ((blob)->length < (size)) { \
61 return NT_STATUS_INFO_LENGTH_MISMATCH; \
62 }} while (0)
64 /* setup a trans2 reply, given the data and params sizes */
65 static NTSTATUS trans2_setup_reply(struct smb_trans2 *trans,
66 uint16_t param_size, uint16_t data_size,
67 uint16_t setup_count)
69 trans->out.setup_count = setup_count;
70 if (setup_count > 0) {
71 trans->out.setup = talloc_zero_array(trans, uint16_t, setup_count);
72 NT_STATUS_HAVE_NO_MEMORY(trans->out.setup);
74 trans->out.params = data_blob_talloc(trans, NULL, param_size);
75 if (param_size > 0) NT_STATUS_HAVE_NO_MEMORY(trans->out.params.data);
77 trans->out.data = data_blob_talloc(trans, NULL, data_size);
78 if (data_size > 0) NT_STATUS_HAVE_NO_MEMORY(trans->out.data.data);
80 return NT_STATUS_OK;
83 static NTSTATUS trans2_push_fsinfo(struct smbsrv_connection *smb_conn,
84 TALLOC_CTX *mem_ctx,
85 DATA_BLOB *blob,
86 union smb_fsinfo *fsinfo,
87 int default_str_flags)
89 enum smb_fsinfo_level passthru_level;
91 switch (fsinfo->generic.level) {
92 case RAW_QFS_ALLOCATION:
93 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 18));
95 SIVAL(blob->data, 0, fsinfo->allocation.out.fs_id);
96 SIVAL(blob->data, 4, fsinfo->allocation.out.sectors_per_unit);
97 SIVAL(blob->data, 8, fsinfo->allocation.out.total_alloc_units);
98 SIVAL(blob->data, 12, fsinfo->allocation.out.avail_alloc_units);
99 SSVAL(blob->data, 16, fsinfo->allocation.out.bytes_per_sector);
101 return NT_STATUS_OK;
103 case RAW_QFS_VOLUME:
104 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 5));
106 SIVAL(blob->data, 0, fsinfo->volume.out.serial_number);
107 /* w2k3 implements this incorrectly for unicode - it
108 * leaves the last byte off the string */
109 TRANS2_CHECK(smbsrv_blob_append_string(mem_ctx, blob,
110 fsinfo->volume.out.volume_name.s,
111 4, default_str_flags,
112 STR_LEN8BIT|STR_NOALIGN));
114 return NT_STATUS_OK;
116 case RAW_QFS_VOLUME_INFO:
117 passthru_level = RAW_QFS_VOLUME_INFORMATION;
118 break;
120 case RAW_QFS_SIZE_INFO:
121 passthru_level = RAW_QFS_SIZE_INFORMATION;
122 break;
124 case RAW_QFS_DEVICE_INFO:
125 passthru_level = RAW_QFS_DEVICE_INFORMATION;
126 break;
128 case RAW_QFS_ATTRIBUTE_INFO:
129 passthru_level = RAW_QFS_ATTRIBUTE_INFORMATION;
130 break;
132 default:
133 passthru_level = fsinfo->generic.level;
134 break;
137 return smbsrv_push_passthru_fsinfo(mem_ctx, blob,
138 passthru_level, fsinfo,
139 default_str_flags);
143 trans2 qfsinfo implementation send
145 static NTSTATUS trans2_qfsinfo_send(struct trans_op *op)
147 struct smbsrv_request *req = op->req;
148 struct smb_trans2 *trans = op->trans;
149 union smb_fsinfo *fsinfo;
151 TRANS2_CHECK_ASYNC_STATUS(fsinfo, union smb_fsinfo);
153 TRANS2_CHECK(trans2_setup_reply(trans, 0, 0, 0));
155 TRANS2_CHECK(trans2_push_fsinfo(req->smb_conn, trans,
156 &trans->out.data, fsinfo,
157 SMBSRV_REQ_DEFAULT_STR_FLAGS(req)));
159 return NT_STATUS_OK;
163 trans2 qfsinfo implementation
165 static NTSTATUS trans2_qfsinfo(struct smbsrv_request *req, struct trans_op *op)
167 struct smb_trans2 *trans = op->trans;
168 union smb_fsinfo *fsinfo;
169 uint16_t level;
171 /* make sure we got enough parameters */
172 if (trans->in.params.length != 2) {
173 return NT_STATUS_FOOBAR;
176 fsinfo = talloc(op, union smb_fsinfo);
177 NT_STATUS_HAVE_NO_MEMORY(fsinfo);
179 level = SVAL(trans->in.params.data, 0);
181 /* work out the backend level - we make it 1-1 in the header */
182 fsinfo->generic.level = (enum smb_fsinfo_level)level;
183 if (fsinfo->generic.level >= RAW_QFS_GENERIC) {
184 return NT_STATUS_INVALID_LEVEL;
187 op->op_info = fsinfo;
188 op->send_fn = trans2_qfsinfo_send;
190 return ntvfs_fsinfo(req->ntvfs, fsinfo);
195 trans2 open implementation send
197 static NTSTATUS trans2_open_send(struct trans_op *op)
199 struct smbsrv_request *req = op->req;
200 struct smb_trans2 *trans = op->trans;
201 union smb_open *io;
203 TRANS2_CHECK_ASYNC_STATUS(io, union smb_open);
205 TRANS2_CHECK(trans2_setup_reply(trans, 30, 0, 0));
207 smbsrv_push_fnum(trans->out.params.data, VWV(0), io->t2open.out.file.ntvfs);
208 SSVAL(trans->out.params.data, VWV(1), io->t2open.out.attrib);
209 srv_push_dos_date3(req->smb_conn, trans->out.params.data,
210 VWV(2), io->t2open.out.write_time);
211 SIVAL(trans->out.params.data, VWV(4), io->t2open.out.size);
212 SSVAL(trans->out.params.data, VWV(6), io->t2open.out.access);
213 SSVAL(trans->out.params.data, VWV(7), io->t2open.out.ftype);
214 SSVAL(trans->out.params.data, VWV(8), io->t2open.out.devstate);
215 SSVAL(trans->out.params.data, VWV(9), io->t2open.out.action);
216 SIVAL(trans->out.params.data, VWV(10), 0); /* reserved */
217 SSVAL(trans->out.params.data, VWV(12), 0); /* EaErrorOffset */
218 SIVAL(trans->out.params.data, VWV(13), 0); /* EaLength */
220 return NT_STATUS_OK;
224 trans2 open implementation
226 static NTSTATUS trans2_open(struct smbsrv_request *req, struct trans_op *op)
228 struct smb_trans2 *trans = op->trans;
229 union smb_open *io;
231 /* make sure we got enough parameters */
232 if (trans->in.params.length < 29) {
233 return NT_STATUS_FOOBAR;
236 io = talloc(op, union smb_open);
237 NT_STATUS_HAVE_NO_MEMORY(io);
239 io->t2open.level = RAW_OPEN_T2OPEN;
240 io->t2open.in.flags = SVAL(trans->in.params.data, VWV(0));
241 io->t2open.in.open_mode = SVAL(trans->in.params.data, VWV(1));
242 io->t2open.in.search_attrs = SVAL(trans->in.params.data, VWV(2));
243 io->t2open.in.file_attrs = SVAL(trans->in.params.data, VWV(3));
244 io->t2open.in.write_time = srv_pull_dos_date(req->smb_conn,
245 trans->in.params.data + VWV(4));
246 io->t2open.in.open_func = SVAL(trans->in.params.data, VWV(6));
247 io->t2open.in.size = IVAL(trans->in.params.data, VWV(7));
248 io->t2open.in.timeout = IVAL(trans->in.params.data, VWV(9));
249 io->t2open.in.num_eas = 0;
250 io->t2open.in.eas = NULL;
252 smbsrv_blob_pull_string(req, &trans->in.params, 28, &io->t2open.in.fname, 0);
253 if (io->t2open.in.fname == NULL) {
254 return NT_STATUS_FOOBAR;
257 TRANS2_CHECK(ea_pull_list(&trans->in.data, io, &io->t2open.in.num_eas, &io->t2open.in.eas));
259 op->op_info = io;
260 op->send_fn = trans2_open_send;
262 return ntvfs_open(req->ntvfs, io);
267 trans2 simple send
269 static NTSTATUS trans2_simple_send(struct trans_op *op)
271 struct smbsrv_request *req = op->req;
272 struct smb_trans2 *trans = op->trans;
274 TRANS2_CHECK_ASYNC_STATUS_SIMPLE;
276 TRANS2_CHECK(trans2_setup_reply(trans, 2, 0, 0));
278 SSVAL(trans->out.params.data, VWV(0), 0);
280 return NT_STATUS_OK;
284 trans2 mkdir implementation
286 static NTSTATUS trans2_mkdir(struct smbsrv_request *req, struct trans_op *op)
288 struct smb_trans2 *trans = op->trans;
289 union smb_mkdir *io;
291 /* make sure we got enough parameters */
292 if (trans->in.params.length < 5) {
293 return NT_STATUS_FOOBAR;
296 io = talloc(op, union smb_mkdir);
297 NT_STATUS_HAVE_NO_MEMORY(io);
299 io->t2mkdir.level = RAW_MKDIR_T2MKDIR;
300 smbsrv_blob_pull_string(req, &trans->in.params, 4, &io->t2mkdir.in.path, 0);
301 if (io->t2mkdir.in.path == NULL) {
302 return NT_STATUS_FOOBAR;
305 TRANS2_CHECK(ea_pull_list(&trans->in.data, io,
306 &io->t2mkdir.in.num_eas,
307 &io->t2mkdir.in.eas));
309 op->op_info = io;
310 op->send_fn = trans2_simple_send;
312 return ntvfs_mkdir(req->ntvfs, io);
315 static NTSTATUS trans2_push_fileinfo(struct smbsrv_connection *smb_conn,
316 TALLOC_CTX *mem_ctx,
317 DATA_BLOB *blob,
318 union smb_fileinfo *st,
319 int default_str_flags)
321 uint32_t list_size;
322 enum smb_fileinfo_level passthru_level;
324 switch (st->generic.level) {
325 case RAW_FILEINFO_GENERIC:
326 case RAW_FILEINFO_GETATTR:
327 case RAW_FILEINFO_GETATTRE:
328 case RAW_FILEINFO_SEC_DESC:
329 case RAW_FILEINFO_SMB2_ALL_EAS:
330 case RAW_FILEINFO_SMB2_ALL_INFORMATION:
331 /* handled elsewhere */
332 return NT_STATUS_INVALID_LEVEL;
334 case RAW_FILEINFO_UNIX_BASIC:
335 case RAW_FILEINFO_UNIX_LINK:
336 /* not implemented yet */
337 return NT_STATUS_INVALID_LEVEL;
339 case RAW_FILEINFO_STANDARD:
340 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 22));
342 srv_push_dos_date2(smb_conn, blob->data, 0, st->standard.out.create_time);
343 srv_push_dos_date2(smb_conn, blob->data, 4, st->standard.out.access_time);
344 srv_push_dos_date2(smb_conn, blob->data, 8, st->standard.out.write_time);
345 SIVAL(blob->data, 12, st->standard.out.size);
346 SIVAL(blob->data, 16, st->standard.out.alloc_size);
347 SSVAL(blob->data, 20, st->standard.out.attrib);
348 return NT_STATUS_OK;
350 case RAW_FILEINFO_EA_SIZE:
351 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 26));
353 srv_push_dos_date2(smb_conn, blob->data, 0, st->ea_size.out.create_time);
354 srv_push_dos_date2(smb_conn, blob->data, 4, st->ea_size.out.access_time);
355 srv_push_dos_date2(smb_conn, blob->data, 8, st->ea_size.out.write_time);
356 SIVAL(blob->data, 12, st->ea_size.out.size);
357 SIVAL(blob->data, 16, st->ea_size.out.alloc_size);
358 SSVAL(blob->data, 20, st->ea_size.out.attrib);
359 SIVAL(blob->data, 22, st->ea_size.out.ea_size);
360 return NT_STATUS_OK;
362 case RAW_FILEINFO_EA_LIST:
363 list_size = ea_list_size(st->ea_list.out.num_eas,
364 st->ea_list.out.eas);
365 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, list_size));
367 ea_put_list(blob->data,
368 st->ea_list.out.num_eas, st->ea_list.out.eas);
369 return NT_STATUS_OK;
371 case RAW_FILEINFO_ALL_EAS:
372 list_size = ea_list_size(st->all_eas.out.num_eas,
373 st->all_eas.out.eas);
374 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, list_size));
376 ea_put_list(blob->data,
377 st->all_eas.out.num_eas, st->all_eas.out.eas);
378 return NT_STATUS_OK;
380 case RAW_FILEINFO_IS_NAME_VALID:
381 return NT_STATUS_OK;
383 case RAW_FILEINFO_BASIC_INFO:
384 passthru_level = RAW_FILEINFO_BASIC_INFORMATION;
385 break;
387 case RAW_FILEINFO_STANDARD_INFO:
388 passthru_level = RAW_FILEINFO_STANDARD_INFORMATION;
389 break;
391 case RAW_FILEINFO_EA_INFO:
392 passthru_level = RAW_FILEINFO_EA_INFORMATION;
393 break;
395 case RAW_FILEINFO_COMPRESSION_INFO:
396 passthru_level = RAW_FILEINFO_COMPRESSION_INFORMATION;
397 break;
399 case RAW_FILEINFO_ALL_INFO:
400 passthru_level = RAW_FILEINFO_ALL_INFORMATION;
401 break;
403 case RAW_FILEINFO_NAME_INFO:
404 passthru_level = RAW_FILEINFO_NAME_INFORMATION;
405 break;
407 case RAW_FILEINFO_ALT_NAME_INFO:
408 passthru_level = RAW_FILEINFO_ALT_NAME_INFORMATION;
409 break;
411 case RAW_FILEINFO_STREAM_INFO:
412 passthru_level = RAW_FILEINFO_STREAM_INFORMATION;
413 break;
415 default:
416 passthru_level = st->generic.level;
417 break;
420 return smbsrv_push_passthru_fileinfo(mem_ctx, blob,
421 passthru_level, st,
422 default_str_flags);
426 fill in the reply from a qpathinfo or qfileinfo call
428 static NTSTATUS trans2_fileinfo_send(struct trans_op *op)
430 struct smbsrv_request *req = op->req;
431 struct smb_trans2 *trans = op->trans;
432 union smb_fileinfo *st;
434 TRANS2_CHECK_ASYNC_STATUS(st, union smb_fileinfo);
436 TRANS2_CHECK(trans2_setup_reply(trans, 2, 0, 0));
437 SSVAL(trans->out.params.data, 0, 0);
439 TRANS2_CHECK(trans2_push_fileinfo(req->smb_conn, trans,
440 &trans->out.data, st,
441 SMBSRV_REQ_DEFAULT_STR_FLAGS(req)));
443 return NT_STATUS_OK;
447 trans2 qpathinfo implementation
449 static NTSTATUS trans2_qpathinfo(struct smbsrv_request *req, struct trans_op *op)
451 struct smb_trans2 *trans = op->trans;
452 union smb_fileinfo *st;
453 uint16_t level;
455 /* make sure we got enough parameters */
456 if (trans->in.params.length < 2) {
457 return NT_STATUS_FOOBAR;
460 st = talloc(op, union smb_fileinfo);
461 NT_STATUS_HAVE_NO_MEMORY(st);
463 level = SVAL(trans->in.params.data, 0);
465 smbsrv_blob_pull_string(req, &trans->in.params, 6, &st->generic.in.file.path, 0);
466 if (st->generic.in.file.path == NULL) {
467 return NT_STATUS_FOOBAR;
470 /* work out the backend level - we make it 1-1 in the header */
471 st->generic.level = (enum smb_fileinfo_level)level;
472 if (st->generic.level >= RAW_FILEINFO_GENERIC) {
473 return NT_STATUS_INVALID_LEVEL;
476 if (st->generic.level == RAW_FILEINFO_EA_LIST) {
477 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
478 &st->ea_list.in.num_names,
479 &st->ea_list.in.ea_names));
482 op->op_info = st;
483 op->send_fn = trans2_fileinfo_send;
485 return ntvfs_qpathinfo(req->ntvfs, st);
490 trans2 qpathinfo implementation
492 static NTSTATUS trans2_qfileinfo(struct smbsrv_request *req, struct trans_op *op)
494 struct smb_trans2 *trans = op->trans;
495 union smb_fileinfo *st;
496 uint16_t level;
497 struct ntvfs_handle *h;
499 /* make sure we got enough parameters */
500 if (trans->in.params.length < 4) {
501 return NT_STATUS_FOOBAR;
504 st = talloc(op, union smb_fileinfo);
505 NT_STATUS_HAVE_NO_MEMORY(st);
507 h = smbsrv_pull_fnum(req, trans->in.params.data, 0);
508 level = SVAL(trans->in.params.data, 2);
510 st->generic.in.file.ntvfs = h;
511 /* work out the backend level - we make it 1-1 in the header */
512 st->generic.level = (enum smb_fileinfo_level)level;
513 if (st->generic.level >= RAW_FILEINFO_GENERIC) {
514 return NT_STATUS_INVALID_LEVEL;
517 if (st->generic.level == RAW_FILEINFO_EA_LIST) {
518 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
519 &st->ea_list.in.num_names,
520 &st->ea_list.in.ea_names));
523 op->op_info = st;
524 op->send_fn = trans2_fileinfo_send;
526 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st->generic.in.file.ntvfs);
527 return ntvfs_qfileinfo(req->ntvfs, st);
532 parse a trans2 setfileinfo/setpathinfo data blob
534 static NTSTATUS trans2_parse_sfileinfo(struct smbsrv_request *req,
535 union smb_setfileinfo *st,
536 const DATA_BLOB *blob)
538 enum smb_setfileinfo_level passthru_level;
540 switch (st->generic.level) {
541 case RAW_SFILEINFO_GENERIC:
542 case RAW_SFILEINFO_SETATTR:
543 case RAW_SFILEINFO_SETATTRE:
544 case RAW_SFILEINFO_SEC_DESC:
545 /* handled elsewhere */
546 return NT_STATUS_INVALID_LEVEL;
548 case RAW_SFILEINFO_STANDARD:
549 CHECK_MIN_BLOB_SIZE(blob, 12);
551 st->standard.in.create_time = srv_pull_dos_date2(req->smb_conn, blob->data + 0);
552 st->standard.in.access_time = srv_pull_dos_date2(req->smb_conn, blob->data + 4);
553 st->standard.in.write_time = srv_pull_dos_date2(req->smb_conn, blob->data + 8);
555 return NT_STATUS_OK;
557 case RAW_SFILEINFO_EA_SET:
558 return ea_pull_list(blob, req,
559 &st->ea_set.in.num_eas,
560 &st->ea_set.in.eas);
562 case SMB_SFILEINFO_BASIC_INFO:
563 case SMB_SFILEINFO_BASIC_INFORMATION:
564 passthru_level = SMB_SFILEINFO_BASIC_INFORMATION;
565 break;
567 case SMB_SFILEINFO_DISPOSITION_INFO:
568 case SMB_SFILEINFO_DISPOSITION_INFORMATION:
569 passthru_level = SMB_SFILEINFO_DISPOSITION_INFORMATION;
570 break;
572 case SMB_SFILEINFO_ALLOCATION_INFO:
573 case SMB_SFILEINFO_ALLOCATION_INFORMATION:
574 passthru_level = SMB_SFILEINFO_ALLOCATION_INFORMATION;
575 break;
577 case RAW_SFILEINFO_END_OF_FILE_INFO:
578 case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
579 passthru_level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
580 break;
582 case RAW_SFILEINFO_RENAME_INFORMATION:
583 case RAW_SFILEINFO_POSITION_INFORMATION:
584 case RAW_SFILEINFO_MODE_INFORMATION:
585 passthru_level = st->generic.level;
586 break;
588 case RAW_SFILEINFO_UNIX_BASIC:
589 case RAW_SFILEINFO_UNIX_LINK:
590 case RAW_SFILEINFO_UNIX_HLINK:
591 case RAW_SFILEINFO_1023:
592 case RAW_SFILEINFO_1025:
593 case RAW_SFILEINFO_1029:
594 case RAW_SFILEINFO_1032:
595 case RAW_SFILEINFO_1039:
596 case RAW_SFILEINFO_1040:
597 return NT_STATUS_INVALID_LEVEL;
599 default:
600 /* we need a default here to cope with invalid values on the wire */
601 return NT_STATUS_INVALID_LEVEL;
604 return smbsrv_pull_passthru_sfileinfo(st, passthru_level, st,
605 blob, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
606 req);
610 trans2 setfileinfo implementation
612 static NTSTATUS trans2_setfileinfo(struct smbsrv_request *req, struct trans_op *op)
614 struct smb_trans2 *trans = op->trans;
615 union smb_setfileinfo *st;
616 uint16_t level;
617 struct ntvfs_handle *h;
619 /* make sure we got enough parameters */
620 if (trans->in.params.length < 4) {
621 return NT_STATUS_FOOBAR;
624 st = talloc(op, union smb_setfileinfo);
625 NT_STATUS_HAVE_NO_MEMORY(st);
627 h = smbsrv_pull_fnum(req, trans->in.params.data, 0);
628 level = SVAL(trans->in.params.data, 2);
630 st->generic.in.file.ntvfs = h;
631 /* work out the backend level - we make it 1-1 in the header */
632 st->generic.level = (enum smb_setfileinfo_level)level;
633 if (st->generic.level >= RAW_SFILEINFO_GENERIC) {
634 return NT_STATUS_INVALID_LEVEL;
637 TRANS2_CHECK(trans2_parse_sfileinfo(req, st, &trans->in.data));
639 op->op_info = st;
640 op->send_fn = trans2_simple_send;
642 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st->generic.in.file.ntvfs);
643 return ntvfs_setfileinfo(req->ntvfs, st);
647 trans2 setpathinfo implementation
649 static NTSTATUS trans2_setpathinfo(struct smbsrv_request *req, struct trans_op *op)
651 struct smb_trans2 *trans = op->trans;
652 union smb_setfileinfo *st;
653 uint16_t level;
655 /* make sure we got enough parameters */
656 if (trans->in.params.length < 4) {
657 return NT_STATUS_FOOBAR;
660 st = talloc(op, union smb_setfileinfo);
661 NT_STATUS_HAVE_NO_MEMORY(st);
663 level = SVAL(trans->in.params.data, 0);
665 smbsrv_blob_pull_string(req, &trans->in.params, 6, &st->generic.in.file.path, 0);
666 if (st->generic.in.file.path == NULL) {
667 return NT_STATUS_FOOBAR;
670 /* work out the backend level - we make it 1-1 in the header */
671 st->generic.level = (enum smb_setfileinfo_level)level;
672 if (st->generic.level >= RAW_SFILEINFO_GENERIC) {
673 return NT_STATUS_INVALID_LEVEL;
676 TRANS2_CHECK(trans2_parse_sfileinfo(req, st, &trans->in.data));
678 op->op_info = st;
679 op->send_fn = trans2_simple_send;
681 return ntvfs_setpathinfo(req->ntvfs, st);
685 /* a structure to encapsulate the state information about an in-progress ffirst/fnext operation */
686 struct find_state {
687 struct trans_op *op;
688 void *search;
689 enum smb_search_data_level data_level;
690 uint16_t last_entry_offset;
691 uint16_t flags;
695 fill a single entry in a trans2 find reply
697 static NTSTATUS find_fill_info(struct find_state *state,
698 union smb_search_data *file)
700 struct smbsrv_request *req = state->op->req;
701 struct smb_trans2 *trans = state->op->trans;
702 uint8_t *data;
703 uint_t ofs = trans->out.data.length;
704 uint32_t ea_size;
706 switch (state->data_level) {
707 case RAW_SEARCH_DATA_GENERIC:
708 case RAW_SEARCH_DATA_SEARCH:
709 /* handled elsewhere */
710 return NT_STATUS_INVALID_LEVEL;
712 case RAW_SEARCH_DATA_STANDARD:
713 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
714 TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 27));
715 SIVAL(trans->out.data.data, ofs, file->standard.resume_key);
716 ofs += 4;
717 } else {
718 TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 23));
720 data = trans->out.data.data + ofs;
721 srv_push_dos_date2(req->smb_conn, data, 0, file->standard.create_time);
722 srv_push_dos_date2(req->smb_conn, data, 4, file->standard.access_time);
723 srv_push_dos_date2(req->smb_conn, data, 8, file->standard.write_time);
724 SIVAL(data, 12, file->standard.size);
725 SIVAL(data, 16, file->standard.alloc_size);
726 SSVAL(data, 20, file->standard.attrib);
727 TRANS2_CHECK(smbsrv_blob_append_string(trans, &trans->out.data, file->standard.name.s,
728 ofs + 22, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
729 STR_LEN8BIT | STR_TERMINATE | STR_LEN_NOTERM));
730 break;
732 case RAW_SEARCH_DATA_EA_SIZE:
733 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
734 TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 31));
735 SIVAL(trans->out.data.data, ofs, file->ea_size.resume_key);
736 ofs += 4;
737 } else {
738 TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 27));
740 data = trans->out.data.data + ofs;
741 srv_push_dos_date2(req->smb_conn, data, 0, file->ea_size.create_time);
742 srv_push_dos_date2(req->smb_conn, data, 4, file->ea_size.access_time);
743 srv_push_dos_date2(req->smb_conn, data, 8, file->ea_size.write_time);
744 SIVAL(data, 12, file->ea_size.size);
745 SIVAL(data, 16, file->ea_size.alloc_size);
746 SSVAL(data, 20, file->ea_size.attrib);
747 SIVAL(data, 22, file->ea_size.ea_size);
748 TRANS2_CHECK(smbsrv_blob_append_string(trans, &trans->out.data, file->ea_size.name.s,
749 ofs + 26, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
750 STR_LEN8BIT | STR_NOALIGN));
751 TRANS2_CHECK(smbsrv_blob_fill_data(trans, &trans->out.data, trans->out.data.length + 1));
752 break;
754 case RAW_SEARCH_DATA_EA_LIST:
755 ea_size = ea_list_size(file->ea_list.eas.num_eas, file->ea_list.eas.eas);
756 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
757 TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 27 + ea_size));
758 SIVAL(trans->out.data.data, ofs, file->ea_list.resume_key);
759 ofs += 4;
760 } else {
761 TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 23 + ea_size));
763 data = trans->out.data.data + ofs;
764 srv_push_dos_date2(req->smb_conn, data, 0, file->ea_list.create_time);
765 srv_push_dos_date2(req->smb_conn, data, 4, file->ea_list.access_time);
766 srv_push_dos_date2(req->smb_conn, data, 8, file->ea_list.write_time);
767 SIVAL(data, 12, file->ea_list.size);
768 SIVAL(data, 16, file->ea_list.alloc_size);
769 SSVAL(data, 20, file->ea_list.attrib);
770 ea_put_list(data+22, file->ea_list.eas.num_eas, file->ea_list.eas.eas);
771 TRANS2_CHECK(smbsrv_blob_append_string(trans, &trans->out.data, file->ea_list.name.s,
772 ofs + 22 + ea_size, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
773 STR_LEN8BIT | STR_NOALIGN));
774 TRANS2_CHECK(smbsrv_blob_fill_data(trans, &trans->out.data, trans->out.data.length + 1));
775 break;
777 case RAW_SEARCH_DATA_DIRECTORY_INFO:
778 case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO:
779 case RAW_SEARCH_DATA_NAME_INFO:
780 case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO:
781 case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO:
782 case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO:
783 return smbsrv_push_passthru_search(trans, &trans->out.data, state->data_level, file,
784 SMBSRV_REQ_DEFAULT_STR_FLAGS(req));
786 case RAW_SEARCH_DATA_UNIX_INFO:
787 return NT_STATUS_INVALID_LEVEL;
790 return NT_STATUS_OK;
793 /* callback function for trans2 findfirst/findnext */
794 static BOOL find_callback(void *private, union smb_search_data *file)
796 struct find_state *state = talloc_get_type(private, struct find_state);
797 struct smb_trans2 *trans = state->op->trans;
798 uint_t old_length;
800 old_length = trans->out.data.length;
802 if (!NT_STATUS_IS_OK(find_fill_info(state, file)) ||
803 trans->out.data.length > trans->in.max_data) {
804 /* restore the old length and tell the backend to stop */
805 smbsrv_blob_grow_data(trans, &trans->out.data, old_length);
806 return False;
809 state->last_entry_offset = old_length;
810 return True;
814 trans2 findfirst send
816 static NTSTATUS trans2_findfirst_send(struct trans_op *op)
818 struct smbsrv_request *req = op->req;
819 struct smb_trans2 *trans = op->trans;
820 union smb_search_first *search;
821 struct find_state *state;
822 uint8_t *param;
824 TRANS2_CHECK_ASYNC_STATUS(state, struct find_state);
825 search = talloc_get_type(state->search, union smb_search_first);
827 /* fill in the findfirst reply header */
828 param = trans->out.params.data;
829 SSVAL(param, VWV(0), search->t2ffirst.out.handle);
830 SSVAL(param, VWV(1), search->t2ffirst.out.count);
831 SSVAL(param, VWV(2), search->t2ffirst.out.end_of_search);
832 SSVAL(param, VWV(3), 0);
833 SSVAL(param, VWV(4), state->last_entry_offset);
835 return NT_STATUS_OK;
840 trans2 findfirst implementation
842 static NTSTATUS trans2_findfirst(struct smbsrv_request *req, struct trans_op *op)
844 struct smb_trans2 *trans = op->trans;
845 union smb_search_first *search;
846 uint16_t level;
847 struct find_state *state;
849 /* make sure we got all the parameters */
850 if (trans->in.params.length < 14) {
851 return NT_STATUS_FOOBAR;
854 search = talloc(op, union smb_search_first);
855 NT_STATUS_HAVE_NO_MEMORY(search);
857 search->t2ffirst.in.search_attrib = SVAL(trans->in.params.data, 0);
858 search->t2ffirst.in.max_count = SVAL(trans->in.params.data, 2);
859 search->t2ffirst.in.flags = SVAL(trans->in.params.data, 4);
860 level = SVAL(trans->in.params.data, 6);
861 search->t2ffirst.in.storage_type = IVAL(trans->in.params.data, 8);
863 smbsrv_blob_pull_string(req, &trans->in.params, 12, &search->t2ffirst.in.pattern, 0);
864 if (search->t2ffirst.in.pattern == NULL) {
865 return NT_STATUS_FOOBAR;
868 search->t2ffirst.level = RAW_SEARCH_TRANS2;
869 search->t2ffirst.data_level = (enum smb_search_data_level)level;
870 if (search->t2ffirst.data_level >= RAW_SEARCH_DATA_GENERIC) {
871 return NT_STATUS_INVALID_LEVEL;
874 if (search->t2ffirst.data_level == RAW_SEARCH_DATA_EA_LIST) {
875 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
876 &search->t2ffirst.in.num_names,
877 &search->t2ffirst.in.ea_names));
880 /* setup the private state structure that the backend will
881 give us in the callback */
882 state = talloc(op, struct find_state);
883 NT_STATUS_HAVE_NO_MEMORY(state);
884 state->op = op;
885 state->search = search;
886 state->data_level = search->t2ffirst.data_level;
887 state->last_entry_offset= 0;
888 state->flags = search->t2ffirst.in.flags;
890 /* setup for just a header in the reply */
891 TRANS2_CHECK(trans2_setup_reply(trans, 10, 0, 0));
893 op->op_info = state;
894 op->send_fn = trans2_findfirst_send;
896 return ntvfs_search_first(req->ntvfs, search, state, find_callback);
901 trans2 findnext send
903 static NTSTATUS trans2_findnext_send(struct trans_op *op)
905 struct smbsrv_request *req = op->req;
906 struct smb_trans2 *trans = op->trans;
907 union smb_search_next *search;
908 struct find_state *state;
909 uint8_t *param;
911 TRANS2_CHECK_ASYNC_STATUS(state, struct find_state);
912 search = talloc_get_type(state->search, union smb_search_next);
914 /* fill in the findfirst reply header */
915 param = trans->out.params.data;
916 SSVAL(param, VWV(0), search->t2fnext.out.count);
917 SSVAL(param, VWV(1), search->t2fnext.out.end_of_search);
918 SSVAL(param, VWV(2), 0);
919 SSVAL(param, VWV(3), state->last_entry_offset);
921 return NT_STATUS_OK;
926 trans2 findnext implementation
928 static NTSTATUS trans2_findnext(struct smbsrv_request *req, struct trans_op *op)
930 struct smb_trans2 *trans = op->trans;
931 union smb_search_next *search;
932 uint16_t level;
933 struct find_state *state;
935 /* make sure we got all the parameters */
936 if (trans->in.params.length < 12) {
937 return NT_STATUS_FOOBAR;
940 search = talloc(op, union smb_search_next);
941 NT_STATUS_HAVE_NO_MEMORY(search);
943 search->t2fnext.in.handle = SVAL(trans->in.params.data, 0);
944 search->t2fnext.in.max_count = SVAL(trans->in.params.data, 2);
945 level = SVAL(trans->in.params.data, 4);
946 search->t2fnext.in.resume_key = IVAL(trans->in.params.data, 6);
947 search->t2fnext.in.flags = SVAL(trans->in.params.data, 10);
949 smbsrv_blob_pull_string(req, &trans->in.params, 12, &search->t2fnext.in.last_name, 0);
950 if (search->t2fnext.in.last_name == NULL) {
951 return NT_STATUS_FOOBAR;
954 search->t2fnext.level = RAW_SEARCH_TRANS2;
955 search->t2fnext.data_level = (enum smb_search_data_level)level;
956 if (search->t2fnext.data_level >= RAW_SEARCH_DATA_GENERIC) {
957 return NT_STATUS_INVALID_LEVEL;
960 if (search->t2fnext.data_level == RAW_SEARCH_DATA_EA_LIST) {
961 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
962 &search->t2fnext.in.num_names,
963 &search->t2fnext.in.ea_names));
966 /* setup the private state structure that the backend will give us in the callback */
967 state = talloc(op, struct find_state);
968 NT_STATUS_HAVE_NO_MEMORY(state);
969 state->op = op;
970 state->search = search;
971 state->data_level = search->t2fnext.data_level;
972 state->last_entry_offset= 0;
973 state->flags = search->t2fnext.in.flags;
975 /* setup for just a header in the reply */
976 TRANS2_CHECK(trans2_setup_reply(trans, 8, 0, 0));
978 op->op_info = state;
979 op->send_fn = trans2_findnext_send;
981 return ntvfs_search_next(req->ntvfs, search, state, find_callback);
986 backend for trans2 requests
988 static NTSTATUS trans2_backend(struct smbsrv_request *req, struct trans_op *op)
990 struct smb_trans2 *trans = op->trans;
991 NTSTATUS status;
993 /* direct trans2 pass thru */
994 status = ntvfs_trans2(req->ntvfs, trans);
995 if (!NT_STATUS_EQUAL(NT_STATUS_NOT_IMPLEMENTED, status)) {
996 return status;
999 /* must have at least one setup word */
1000 if (trans->in.setup_count < 1) {
1001 return NT_STATUS_FOOBAR;
1004 /* the trans2 command is in setup[0] */
1005 switch (trans->in.setup[0]) {
1006 case TRANSACT2_FINDFIRST:
1007 return trans2_findfirst(req, op);
1008 case TRANSACT2_FINDNEXT:
1009 return trans2_findnext(req, op);
1010 case TRANSACT2_QPATHINFO:
1011 return trans2_qpathinfo(req, op);
1012 case TRANSACT2_QFILEINFO:
1013 return trans2_qfileinfo(req, op);
1014 case TRANSACT2_SETFILEINFO:
1015 return trans2_setfileinfo(req, op);
1016 case TRANSACT2_SETPATHINFO:
1017 return trans2_setpathinfo(req, op);
1018 case TRANSACT2_QFSINFO:
1019 return trans2_qfsinfo(req, op);
1020 case TRANSACT2_OPEN:
1021 return trans2_open(req, op);
1022 case TRANSACT2_MKDIR:
1023 return trans2_mkdir(req, op);
1026 /* an unknown trans2 command */
1027 return NT_STATUS_FOOBAR;
1032 send a continue request
1034 static void reply_trans_continue(struct smbsrv_request *req, uint8_t command,
1035 struct smb_trans2 *trans)
1037 struct smbsrv_trans_partial *tp;
1038 int count;
1040 /* make sure they don't flood us */
1041 for (count=0,tp=req->smb_conn->trans_partial;tp;tp=tp->next) count++;
1042 if (count > 100) {
1043 smbsrv_send_error(req, NT_STATUS_INSUFFICIENT_RESOURCES);
1044 return;
1047 tp = talloc(req, struct smbsrv_trans_partial);
1049 tp->req = talloc_reference(tp, req);
1050 tp->trans = trans;
1051 tp->command = command;
1053 DLIST_ADD(req->smb_conn->trans_partial, tp);
1055 /* send a 'please continue' reply */
1056 smbsrv_setup_reply(req, 0, 0);
1057 smbsrv_send_reply(req);
1062 answer a reconstructed trans request
1064 static void reply_trans_send(struct ntvfs_request *ntvfs)
1066 struct smbsrv_request *req;
1067 struct trans_op *op;
1068 struct smb_trans2 *trans;
1069 uint16_t params_left, data_left;
1070 uint8_t *params, *data;
1071 int i;
1073 SMBSRV_CHECK_ASYNC_STATUS_ERR(op, struct trans_op);
1074 trans = op->trans;
1076 /* if this function needs work to form the nttrans reply buffer, then
1077 call that now */
1078 if (op->send_fn != NULL) {
1079 NTSTATUS status;
1080 status = op->send_fn(op);
1081 if (!NT_STATUS_IS_OK(status)) {
1082 smbsrv_send_error(req, status);
1083 return;
1087 params_left = trans->out.params.length;
1088 data_left = trans->out.data.length;
1089 params = trans->out.params.data;
1090 data = trans->out.data.data;
1092 smbsrv_setup_reply(req, 10 + trans->out.setup_count, 0);
1094 if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) {
1095 smbsrv_setup_error(req, req->ntvfs->async_states->status);
1098 /* we need to divide up the reply into chunks that fit into
1099 the negotiated buffer size */
1100 do {
1101 uint16_t this_data, this_param, max_bytes;
1102 uint_t align1 = 1, align2 = (params_left ? 2 : 0);
1103 struct smbsrv_request *this_req;
1105 max_bytes = req_max_data(req) - (align1 + align2);
1107 this_param = params_left;
1108 if (this_param > max_bytes) {
1109 this_param = max_bytes;
1111 max_bytes -= this_param;
1113 this_data = data_left;
1114 if (this_data > max_bytes) {
1115 this_data = max_bytes;
1118 /* don't destroy unless this is the last chunk */
1119 if (params_left - this_param != 0 ||
1120 data_left - this_data != 0) {
1121 this_req = smbsrv_setup_secondary_request(req);
1122 } else {
1123 this_req = req;
1126 req_grow_data(this_req, this_param + this_data + (align1 + align2));
1128 SSVAL(this_req->out.vwv, VWV(0), trans->out.params.length);
1129 SSVAL(this_req->out.vwv, VWV(1), trans->out.data.length);
1130 SSVAL(this_req->out.vwv, VWV(2), 0);
1132 SSVAL(this_req->out.vwv, VWV(3), this_param);
1133 SSVAL(this_req->out.vwv, VWV(4), align1 + PTR_DIFF(this_req->out.data, this_req->out.hdr));
1134 SSVAL(this_req->out.vwv, VWV(5), PTR_DIFF(params, trans->out.params.data));
1136 SSVAL(this_req->out.vwv, VWV(6), this_data);
1137 SSVAL(this_req->out.vwv, VWV(7), align1 + align2 +
1138 PTR_DIFF(this_req->out.data + this_param, this_req->out.hdr));
1139 SSVAL(this_req->out.vwv, VWV(8), PTR_DIFF(data, trans->out.data.data));
1141 SSVAL(this_req->out.vwv, VWV(9), trans->out.setup_count);
1142 for (i=0;i<trans->out.setup_count;i++) {
1143 SSVAL(this_req->out.vwv, VWV(10+i), trans->out.setup[i]);
1146 memset(this_req->out.data, 0, align1);
1147 if (this_param != 0) {
1148 memcpy(this_req->out.data + align1, params, this_param);
1150 memset(this_req->out.data+this_param+align1, 0, align2);
1151 if (this_data != 0) {
1152 memcpy(this_req->out.data+this_param+align1+align2, data, this_data);
1155 params_left -= this_param;
1156 data_left -= this_data;
1157 params += this_param;
1158 data += this_data;
1160 smbsrv_send_reply(this_req);
1161 } while (params_left != 0 || data_left != 0);
1166 answer a reconstructed trans request
1168 static void reply_trans_complete(struct smbsrv_request *req, uint8_t command,
1169 struct smb_trans2 *trans)
1171 struct trans_op *op;
1173 SMBSRV_TALLOC_IO_PTR(op, struct trans_op);
1174 SMBSRV_SETUP_NTVFS_REQUEST(reply_trans_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1176 op->req = req;
1177 op->trans = trans;
1178 op->command = command;
1179 op->op_info = NULL;
1180 op->send_fn = NULL;
1182 /* its a full request, give it to the backend */
1183 if (command == SMBtrans) {
1184 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_trans(req->ntvfs, trans));
1185 return;
1186 } else {
1187 SMBSRV_CALL_NTVFS_BACKEND(trans2_backend(req, op));
1188 return;
1193 Reply to an SMBtrans or SMBtrans2 request
1195 static void reply_trans_generic(struct smbsrv_request *req, uint8_t command)
1197 struct smb_trans2 *trans;
1198 int i;
1199 uint16_t param_ofs, data_ofs;
1200 uint16_t param_count, data_count;
1201 uint16_t param_total, data_total;
1203 /* parse request */
1204 if (req->in.wct < 14) {
1205 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1206 return;
1209 trans = talloc(req, struct smb_trans2);
1210 if (trans == NULL) {
1211 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
1212 return;
1215 param_total = SVAL(req->in.vwv, VWV(0));
1216 data_total = SVAL(req->in.vwv, VWV(1));
1217 trans->in.max_param = SVAL(req->in.vwv, VWV(2));
1218 trans->in.max_data = SVAL(req->in.vwv, VWV(3));
1219 trans->in.max_setup = CVAL(req->in.vwv, VWV(4));
1220 trans->in.flags = SVAL(req->in.vwv, VWV(5));
1221 trans->in.timeout = IVAL(req->in.vwv, VWV(6));
1222 param_count = SVAL(req->in.vwv, VWV(9));
1223 param_ofs = SVAL(req->in.vwv, VWV(10));
1224 data_count = SVAL(req->in.vwv, VWV(11));
1225 data_ofs = SVAL(req->in.vwv, VWV(12));
1226 trans->in.setup_count = CVAL(req->in.vwv, VWV(13));
1228 if (req->in.wct != 14 + trans->in.setup_count) {
1229 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
1230 return;
1233 /* parse out the setup words */
1234 trans->in.setup = talloc_array(trans, uint16_t, trans->in.setup_count);
1235 if (trans->in.setup_count && !trans->in.setup) {
1236 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
1237 return;
1239 for (i=0;i<trans->in.setup_count;i++) {
1240 trans->in.setup[i] = SVAL(req->in.vwv, VWV(14+i));
1243 if (command == SMBtrans) {
1244 req_pull_string(req, &trans->in.trans_name, req->in.data, -1, STR_TERMINATE);
1247 if (!req_pull_blob(req, req->in.hdr + param_ofs, param_count, &trans->in.params) ||
1248 !req_pull_blob(req, req->in.hdr + data_ofs, data_count, &trans->in.data)) {
1249 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1250 return;
1253 /* is it a partial request? if so, then send a 'send more' message */
1254 if (param_total > param_count || data_total > data_count) {
1255 reply_trans_continue(req, command, trans);
1256 return;
1259 reply_trans_complete(req, command, trans);
1264 Reply to an SMBtranss2 request
1266 static void reply_transs_generic(struct smbsrv_request *req, uint8_t command)
1268 struct smbsrv_trans_partial *tp;
1269 struct smb_trans2 *trans = NULL;
1270 uint16_t param_ofs, data_ofs;
1271 uint16_t param_count, data_count;
1272 uint16_t param_disp, data_disp;
1273 uint16_t param_total, data_total;
1274 DATA_BLOB params, data;
1276 /* parse request */
1277 if (req->in.wct < 8) {
1278 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1279 return;
1282 for (tp=req->smb_conn->trans_partial;tp;tp=tp->next) {
1283 if (tp->command == command &&
1284 SVAL(tp->req->in.hdr, HDR_MID) == SVAL(req->in.hdr, HDR_MID)) {
1285 /* TODO: check the VUID, PID and TID too? */
1286 break;
1290 if (tp == NULL) {
1291 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1292 return;
1295 trans = tp->trans;
1297 param_total = SVAL(req->in.vwv, VWV(0));
1298 data_total = SVAL(req->in.vwv, VWV(1));
1299 param_count = SVAL(req->in.vwv, VWV(2));
1300 param_ofs = SVAL(req->in.vwv, VWV(3));
1301 param_disp = SVAL(req->in.vwv, VWV(4));
1302 data_count = SVAL(req->in.vwv, VWV(5));
1303 data_ofs = SVAL(req->in.vwv, VWV(6));
1304 data_disp = SVAL(req->in.vwv, VWV(7));
1306 if (!req_pull_blob(req, req->in.hdr + param_ofs, param_count, &params) ||
1307 !req_pull_blob(req, req->in.hdr + data_ofs, data_count, &data)) {
1308 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1309 return;
1312 /* only allow contiguous requests */
1313 if ((param_count != 0 &&
1314 param_disp != trans->in.params.length) ||
1315 (data_count != 0 &&
1316 data_disp != trans->in.data.length)) {
1317 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1318 return;
1321 /* add to the existing request */
1322 if (param_count != 0) {
1323 trans->in.params.data = talloc_realloc(trans,
1324 trans->in.params.data,
1325 uint8_t,
1326 param_disp + param_count);
1327 if (trans->in.params.data == NULL) {
1328 goto failed;
1330 trans->in.params.length = param_disp + param_count;
1333 if (data_count != 0) {
1334 trans->in.data.data = talloc_realloc(trans,
1335 trans->in.data.data,
1336 uint8_t,
1337 data_disp + data_count);
1338 if (trans->in.data.data == NULL) {
1339 goto failed;
1341 trans->in.data.length = data_disp + data_count;
1344 memcpy(trans->in.params.data + param_disp, params.data, params.length);
1345 memcpy(trans->in.data.data + data_disp, data.data, data.length);
1347 /* the sequence number of the reply is taken from the last secondary
1348 response */
1349 tp->req->seq_num = req->seq_num;
1351 /* we don't reply to Transs2 requests */
1352 talloc_free(req);
1354 if (trans->in.params.length == param_total &&
1355 trans->in.data.length == data_total) {
1356 /* its now complete */
1357 DLIST_REMOVE(tp->req->smb_conn->trans_partial, tp);
1358 reply_trans_complete(tp->req, command, trans);
1360 return;
1362 failed:
1363 smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
1364 DLIST_REMOVE(req->smb_conn->trans_partial, tp);
1365 talloc_free(req);
1366 talloc_free(tp);
1371 Reply to an SMBtrans2
1373 void smbsrv_reply_trans2(struct smbsrv_request *req)
1375 reply_trans_generic(req, SMBtrans2);
1379 Reply to an SMBtrans
1381 void smbsrv_reply_trans(struct smbsrv_request *req)
1383 reply_trans_generic(req, SMBtrans);
1387 Reply to an SMBtranss request
1389 void smbsrv_reply_transs(struct smbsrv_request *req)
1391 reply_transs_generic(req, SMBtrans);
1395 Reply to an SMBtranss2 request
1397 void smbsrv_reply_transs2(struct smbsrv_request *req)
1399 reply_transs_generic(req, SMBtrans2);