smb_server/smb: trans(2) setup count is uint8_t
[Samba/ekacnet.git] / source4 / smb_server / smb / trans2.c
blob6dd69de436c176c73b64a3b36a40583be980695f
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"
29 #include "libcli/raw/raw_proto.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 uint8_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->in.bufinfo, &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->in.bufinfo, &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->in.bufinfo, &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_PIPE_INFORMATION:
592 case RAW_SFILEINFO_VALID_DATA_INFORMATION:
593 case RAW_SFILEINFO_SHORT_NAME_INFORMATION:
594 case RAW_SFILEINFO_1025:
595 case RAW_SFILEINFO_1027:
596 case RAW_SFILEINFO_1029:
597 case RAW_SFILEINFO_1030:
598 case RAW_SFILEINFO_1031:
599 case RAW_SFILEINFO_1032:
600 case RAW_SFILEINFO_1036:
601 case RAW_SFILEINFO_1041:
602 case RAW_SFILEINFO_1042:
603 case RAW_SFILEINFO_1043:
604 case RAW_SFILEINFO_1044:
605 return NT_STATUS_INVALID_LEVEL;
607 default:
608 /* we need a default here to cope with invalid values on the wire */
609 return NT_STATUS_INVALID_LEVEL;
612 return smbsrv_pull_passthru_sfileinfo(st, passthru_level, st,
613 blob, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
614 &req->in.bufinfo);
618 trans2 setfileinfo implementation
620 static NTSTATUS trans2_setfileinfo(struct smbsrv_request *req, struct trans_op *op)
622 struct smb_trans2 *trans = op->trans;
623 union smb_setfileinfo *st;
624 uint16_t level;
625 struct ntvfs_handle *h;
627 /* make sure we got enough parameters */
628 if (trans->in.params.length < 4) {
629 return NT_STATUS_FOOBAR;
632 st = talloc(op, union smb_setfileinfo);
633 NT_STATUS_HAVE_NO_MEMORY(st);
635 h = smbsrv_pull_fnum(req, trans->in.params.data, 0);
636 level = SVAL(trans->in.params.data, 2);
638 st->generic.in.file.ntvfs = h;
639 /* work out the backend level - we make it 1-1 in the header */
640 st->generic.level = (enum smb_setfileinfo_level)level;
641 if (st->generic.level >= RAW_SFILEINFO_GENERIC) {
642 return NT_STATUS_INVALID_LEVEL;
645 TRANS2_CHECK(trans2_parse_sfileinfo(req, st, &trans->in.data));
647 op->op_info = st;
648 op->send_fn = trans2_simple_send;
650 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st->generic.in.file.ntvfs);
651 return ntvfs_setfileinfo(req->ntvfs, st);
655 trans2 setpathinfo implementation
657 static NTSTATUS trans2_setpathinfo(struct smbsrv_request *req, struct trans_op *op)
659 struct smb_trans2 *trans = op->trans;
660 union smb_setfileinfo *st;
661 uint16_t level;
663 /* make sure we got enough parameters */
664 if (trans->in.params.length < 4) {
665 return NT_STATUS_FOOBAR;
668 st = talloc(op, union smb_setfileinfo);
669 NT_STATUS_HAVE_NO_MEMORY(st);
671 level = SVAL(trans->in.params.data, 0);
673 smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 6, &st->generic.in.file.path, 0);
674 if (st->generic.in.file.path == NULL) {
675 return NT_STATUS_FOOBAR;
678 /* work out the backend level - we make it 1-1 in the header */
679 st->generic.level = (enum smb_setfileinfo_level)level;
680 if (st->generic.level >= RAW_SFILEINFO_GENERIC) {
681 return NT_STATUS_INVALID_LEVEL;
684 TRANS2_CHECK(trans2_parse_sfileinfo(req, st, &trans->in.data));
686 op->op_info = st;
687 op->send_fn = trans2_simple_send;
689 return ntvfs_setpathinfo(req->ntvfs, st);
693 /* a structure to encapsulate the state information about an in-progress ffirst/fnext operation */
694 struct find_state {
695 struct trans_op *op;
696 void *search;
697 enum smb_search_data_level data_level;
698 uint16_t last_entry_offset;
699 uint16_t flags;
703 fill a single entry in a trans2 find reply
705 static NTSTATUS find_fill_info(struct find_state *state,
706 const union smb_search_data *file)
708 struct smbsrv_request *req = state->op->req;
709 struct smb_trans2 *trans = state->op->trans;
710 uint8_t *data;
711 uint_t ofs = trans->out.data.length;
712 uint32_t ea_size;
714 switch (state->data_level) {
715 case RAW_SEARCH_DATA_GENERIC:
716 case RAW_SEARCH_DATA_SEARCH:
717 /* handled elsewhere */
718 return NT_STATUS_INVALID_LEVEL;
720 case RAW_SEARCH_DATA_STANDARD:
721 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
722 TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 27));
723 SIVAL(trans->out.data.data, ofs, file->standard.resume_key);
724 ofs += 4;
725 } else {
726 TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 23));
728 data = trans->out.data.data + ofs;
729 srv_push_dos_date2(req->smb_conn, data, 0, file->standard.create_time);
730 srv_push_dos_date2(req->smb_conn, data, 4, file->standard.access_time);
731 srv_push_dos_date2(req->smb_conn, data, 8, file->standard.write_time);
732 SIVAL(data, 12, file->standard.size);
733 SIVAL(data, 16, file->standard.alloc_size);
734 SSVAL(data, 20, file->standard.attrib);
735 TRANS2_CHECK(smbsrv_blob_append_string(trans, &trans->out.data, file->standard.name.s,
736 ofs + 22, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
737 STR_LEN8BIT | STR_TERMINATE | STR_LEN_NOTERM));
738 break;
740 case RAW_SEARCH_DATA_EA_SIZE:
741 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
742 TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 31));
743 SIVAL(trans->out.data.data, ofs, file->ea_size.resume_key);
744 ofs += 4;
745 } else {
746 TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 27));
748 data = trans->out.data.data + ofs;
749 srv_push_dos_date2(req->smb_conn, data, 0, file->ea_size.create_time);
750 srv_push_dos_date2(req->smb_conn, data, 4, file->ea_size.access_time);
751 srv_push_dos_date2(req->smb_conn, data, 8, file->ea_size.write_time);
752 SIVAL(data, 12, file->ea_size.size);
753 SIVAL(data, 16, file->ea_size.alloc_size);
754 SSVAL(data, 20, file->ea_size.attrib);
755 SIVAL(data, 22, file->ea_size.ea_size);
756 TRANS2_CHECK(smbsrv_blob_append_string(trans, &trans->out.data, file->ea_size.name.s,
757 ofs + 26, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
758 STR_LEN8BIT | STR_NOALIGN));
759 TRANS2_CHECK(smbsrv_blob_fill_data(trans, &trans->out.data, trans->out.data.length + 1));
760 break;
762 case RAW_SEARCH_DATA_EA_LIST:
763 ea_size = ea_list_size(file->ea_list.eas.num_eas, file->ea_list.eas.eas);
764 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
765 TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 27 + ea_size));
766 SIVAL(trans->out.data.data, ofs, file->ea_list.resume_key);
767 ofs += 4;
768 } else {
769 TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 23 + ea_size));
771 data = trans->out.data.data + ofs;
772 srv_push_dos_date2(req->smb_conn, data, 0, file->ea_list.create_time);
773 srv_push_dos_date2(req->smb_conn, data, 4, file->ea_list.access_time);
774 srv_push_dos_date2(req->smb_conn, data, 8, file->ea_list.write_time);
775 SIVAL(data, 12, file->ea_list.size);
776 SIVAL(data, 16, file->ea_list.alloc_size);
777 SSVAL(data, 20, file->ea_list.attrib);
778 ea_put_list(data+22, file->ea_list.eas.num_eas, file->ea_list.eas.eas);
779 TRANS2_CHECK(smbsrv_blob_append_string(trans, &trans->out.data, file->ea_list.name.s,
780 ofs + 22 + ea_size, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
781 STR_LEN8BIT | STR_NOALIGN));
782 TRANS2_CHECK(smbsrv_blob_fill_data(trans, &trans->out.data, trans->out.data.length + 1));
783 break;
785 case RAW_SEARCH_DATA_DIRECTORY_INFO:
786 case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO:
787 case RAW_SEARCH_DATA_NAME_INFO:
788 case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO:
789 case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO:
790 case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO:
791 return smbsrv_push_passthru_search(trans, &trans->out.data, state->data_level, file,
792 SMBSRV_REQ_DEFAULT_STR_FLAGS(req));
794 case RAW_SEARCH_DATA_UNIX_INFO:
795 case RAW_SEARCH_DATA_UNIX_INFO2:
796 return NT_STATUS_INVALID_LEVEL;
799 return NT_STATUS_OK;
802 /* callback function for trans2 findfirst/findnext */
803 static bool find_callback(void *private, const union smb_search_data *file)
805 struct find_state *state = talloc_get_type(private, struct find_state);
806 struct smb_trans2 *trans = state->op->trans;
807 uint_t old_length;
809 old_length = trans->out.data.length;
811 if (!NT_STATUS_IS_OK(find_fill_info(state, file)) ||
812 trans->out.data.length > trans->in.max_data) {
813 /* restore the old length and tell the backend to stop */
814 smbsrv_blob_grow_data(trans, &trans->out.data, old_length);
815 return false;
818 state->last_entry_offset = old_length;
819 return true;
823 trans2 findfirst send
825 static NTSTATUS trans2_findfirst_send(struct trans_op *op)
827 struct smbsrv_request *req = op->req;
828 struct smb_trans2 *trans = op->trans;
829 union smb_search_first *search;
830 struct find_state *state;
831 uint8_t *param;
833 TRANS2_CHECK_ASYNC_STATUS(state, struct find_state);
834 search = talloc_get_type(state->search, union smb_search_first);
836 /* fill in the findfirst reply header */
837 param = trans->out.params.data;
838 SSVAL(param, VWV(0), search->t2ffirst.out.handle);
839 SSVAL(param, VWV(1), search->t2ffirst.out.count);
840 SSVAL(param, VWV(2), search->t2ffirst.out.end_of_search);
841 SSVAL(param, VWV(3), 0);
842 SSVAL(param, VWV(4), state->last_entry_offset);
844 return NT_STATUS_OK;
849 trans2 findfirst implementation
851 static NTSTATUS trans2_findfirst(struct smbsrv_request *req, struct trans_op *op)
853 struct smb_trans2 *trans = op->trans;
854 union smb_search_first *search;
855 uint16_t level;
856 struct find_state *state;
858 /* make sure we got all the parameters */
859 if (trans->in.params.length < 14) {
860 return NT_STATUS_FOOBAR;
863 search = talloc(op, union smb_search_first);
864 NT_STATUS_HAVE_NO_MEMORY(search);
866 search->t2ffirst.in.search_attrib = SVAL(trans->in.params.data, 0);
867 search->t2ffirst.in.max_count = SVAL(trans->in.params.data, 2);
868 search->t2ffirst.in.flags = SVAL(trans->in.params.data, 4);
869 level = SVAL(trans->in.params.data, 6);
870 search->t2ffirst.in.storage_type = IVAL(trans->in.params.data, 8);
872 smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 12, &search->t2ffirst.in.pattern, 0);
873 if (search->t2ffirst.in.pattern == NULL) {
874 return NT_STATUS_FOOBAR;
877 search->t2ffirst.level = RAW_SEARCH_TRANS2;
878 search->t2ffirst.data_level = (enum smb_search_data_level)level;
879 if (search->t2ffirst.data_level >= RAW_SEARCH_DATA_GENERIC) {
880 return NT_STATUS_INVALID_LEVEL;
883 if (search->t2ffirst.data_level == RAW_SEARCH_DATA_EA_LIST) {
884 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
885 &search->t2ffirst.in.num_names,
886 &search->t2ffirst.in.ea_names));
889 /* setup the private state structure that the backend will
890 give us in the callback */
891 state = talloc(op, struct find_state);
892 NT_STATUS_HAVE_NO_MEMORY(state);
893 state->op = op;
894 state->search = search;
895 state->data_level = search->t2ffirst.data_level;
896 state->last_entry_offset= 0;
897 state->flags = search->t2ffirst.in.flags;
899 /* setup for just a header in the reply */
900 TRANS2_CHECK(trans2_setup_reply(trans, 10, 0, 0));
902 op->op_info = state;
903 op->send_fn = trans2_findfirst_send;
905 return ntvfs_search_first(req->ntvfs, search, state, find_callback);
910 trans2 findnext send
912 static NTSTATUS trans2_findnext_send(struct trans_op *op)
914 struct smbsrv_request *req = op->req;
915 struct smb_trans2 *trans = op->trans;
916 union smb_search_next *search;
917 struct find_state *state;
918 uint8_t *param;
920 TRANS2_CHECK_ASYNC_STATUS(state, struct find_state);
921 search = talloc_get_type(state->search, union smb_search_next);
923 /* fill in the findfirst reply header */
924 param = trans->out.params.data;
925 SSVAL(param, VWV(0), search->t2fnext.out.count);
926 SSVAL(param, VWV(1), search->t2fnext.out.end_of_search);
927 SSVAL(param, VWV(2), 0);
928 SSVAL(param, VWV(3), state->last_entry_offset);
930 return NT_STATUS_OK;
935 trans2 findnext implementation
937 static NTSTATUS trans2_findnext(struct smbsrv_request *req, struct trans_op *op)
939 struct smb_trans2 *trans = op->trans;
940 union smb_search_next *search;
941 uint16_t level;
942 struct find_state *state;
944 /* make sure we got all the parameters */
945 if (trans->in.params.length < 12) {
946 return NT_STATUS_FOOBAR;
949 search = talloc(op, union smb_search_next);
950 NT_STATUS_HAVE_NO_MEMORY(search);
952 search->t2fnext.in.handle = SVAL(trans->in.params.data, 0);
953 search->t2fnext.in.max_count = SVAL(trans->in.params.data, 2);
954 level = SVAL(trans->in.params.data, 4);
955 search->t2fnext.in.resume_key = IVAL(trans->in.params.data, 6);
956 search->t2fnext.in.flags = SVAL(trans->in.params.data, 10);
958 smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 12, &search->t2fnext.in.last_name, 0);
959 if (search->t2fnext.in.last_name == NULL) {
960 return NT_STATUS_FOOBAR;
963 search->t2fnext.level = RAW_SEARCH_TRANS2;
964 search->t2fnext.data_level = (enum smb_search_data_level)level;
965 if (search->t2fnext.data_level >= RAW_SEARCH_DATA_GENERIC) {
966 return NT_STATUS_INVALID_LEVEL;
969 if (search->t2fnext.data_level == RAW_SEARCH_DATA_EA_LIST) {
970 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
971 &search->t2fnext.in.num_names,
972 &search->t2fnext.in.ea_names));
975 /* setup the private state structure that the backend will give us in the callback */
976 state = talloc(op, struct find_state);
977 NT_STATUS_HAVE_NO_MEMORY(state);
978 state->op = op;
979 state->search = search;
980 state->data_level = search->t2fnext.data_level;
981 state->last_entry_offset= 0;
982 state->flags = search->t2fnext.in.flags;
984 /* setup for just a header in the reply */
985 TRANS2_CHECK(trans2_setup_reply(trans, 8, 0, 0));
987 op->op_info = state;
988 op->send_fn = trans2_findnext_send;
990 return ntvfs_search_next(req->ntvfs, search, state, find_callback);
995 backend for trans2 requests
997 static NTSTATUS trans2_backend(struct smbsrv_request *req, struct trans_op *op)
999 struct smb_trans2 *trans = op->trans;
1000 NTSTATUS status;
1002 /* direct trans2 pass thru */
1003 status = ntvfs_trans2(req->ntvfs, trans);
1004 if (!NT_STATUS_EQUAL(NT_STATUS_NOT_IMPLEMENTED, status)) {
1005 return status;
1008 /* must have at least one setup word */
1009 if (trans->in.setup_count < 1) {
1010 return NT_STATUS_FOOBAR;
1013 /* the trans2 command is in setup[0] */
1014 switch (trans->in.setup[0]) {
1015 case TRANSACT2_FINDFIRST:
1016 return trans2_findfirst(req, op);
1017 case TRANSACT2_FINDNEXT:
1018 return trans2_findnext(req, op);
1019 case TRANSACT2_QPATHINFO:
1020 return trans2_qpathinfo(req, op);
1021 case TRANSACT2_QFILEINFO:
1022 return trans2_qfileinfo(req, op);
1023 case TRANSACT2_SETFILEINFO:
1024 return trans2_setfileinfo(req, op);
1025 case TRANSACT2_SETPATHINFO:
1026 return trans2_setpathinfo(req, op);
1027 case TRANSACT2_QFSINFO:
1028 return trans2_qfsinfo(req, op);
1029 case TRANSACT2_OPEN:
1030 return trans2_open(req, op);
1031 case TRANSACT2_MKDIR:
1032 return trans2_mkdir(req, op);
1035 /* an unknown trans2 command */
1036 return NT_STATUS_FOOBAR;
1039 static int smbsrv_trans_partial_destructor(struct smbsrv_trans_partial *tp)
1041 DLIST_REMOVE(tp->req->smb_conn->trans_partial, tp);
1042 return 0;
1047 send a continue request
1049 static void reply_trans_continue(struct smbsrv_request *req, uint8_t command,
1050 struct smb_trans2 *trans)
1052 struct smbsrv_request *req2;
1053 struct smbsrv_trans_partial *tp;
1054 int count;
1056 /* make sure they don't flood us */
1057 for (count=0,tp=req->smb_conn->trans_partial;tp;tp=tp->next) count++;
1058 if (count > 100) {
1059 smbsrv_send_error(req, NT_STATUS_INSUFFICIENT_RESOURCES);
1060 return;
1063 tp = talloc(req, struct smbsrv_trans_partial);
1065 tp->req = req;
1066 tp->trans = trans;
1067 tp->command = command;
1069 DLIST_ADD(req->smb_conn->trans_partial, tp);
1070 talloc_set_destructor(tp, smbsrv_trans_partial_destructor);
1072 req2 = smbsrv_setup_secondary_request(req);
1074 /* send a 'please continue' reply */
1075 smbsrv_setup_reply(req2, 0, 0);
1076 smbsrv_send_reply(req2);
1081 answer a reconstructed trans request
1083 static void reply_trans_send(struct ntvfs_request *ntvfs)
1085 struct smbsrv_request *req;
1086 struct trans_op *op;
1087 struct smb_trans2 *trans;
1088 uint16_t params_left, data_left;
1089 uint8_t *params, *data;
1090 int i;
1092 SMBSRV_CHECK_ASYNC_STATUS_ERR(op, struct trans_op);
1093 trans = op->trans;
1095 /* if this function needs work to form the nttrans reply buffer, then
1096 call that now */
1097 if (op->send_fn != NULL) {
1098 NTSTATUS status;
1099 status = op->send_fn(op);
1100 if (!NT_STATUS_IS_OK(status)) {
1101 smbsrv_send_error(req, status);
1102 return;
1106 params_left = trans->out.params.length;
1107 data_left = trans->out.data.length;
1108 params = trans->out.params.data;
1109 data = trans->out.data.data;
1111 smbsrv_setup_reply(req, 10 + trans->out.setup_count, 0);
1113 if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) {
1114 smbsrv_setup_error(req, req->ntvfs->async_states->status);
1117 /* we need to divide up the reply into chunks that fit into
1118 the negotiated buffer size */
1119 do {
1120 uint16_t this_data, this_param, max_bytes;
1121 uint_t align1 = 1, align2 = (params_left ? 2 : 0);
1122 struct smbsrv_request *this_req;
1124 max_bytes = req_max_data(req) - (align1 + align2);
1126 this_param = params_left;
1127 if (this_param > max_bytes) {
1128 this_param = max_bytes;
1130 max_bytes -= this_param;
1132 this_data = data_left;
1133 if (this_data > max_bytes) {
1134 this_data = max_bytes;
1137 /* don't destroy unless this is the last chunk */
1138 if (params_left - this_param != 0 ||
1139 data_left - this_data != 0) {
1140 this_req = smbsrv_setup_secondary_request(req);
1141 } else {
1142 this_req = req;
1145 req_grow_data(this_req, this_param + this_data + (align1 + align2));
1147 SSVAL(this_req->out.vwv, VWV(0), trans->out.params.length);
1148 SSVAL(this_req->out.vwv, VWV(1), trans->out.data.length);
1149 SSVAL(this_req->out.vwv, VWV(2), 0);
1151 SSVAL(this_req->out.vwv, VWV(3), this_param);
1152 SSVAL(this_req->out.vwv, VWV(4), align1 + PTR_DIFF(this_req->out.data, this_req->out.hdr));
1153 SSVAL(this_req->out.vwv, VWV(5), PTR_DIFF(params, trans->out.params.data));
1155 SSVAL(this_req->out.vwv, VWV(6), this_data);
1156 SSVAL(this_req->out.vwv, VWV(7), align1 + align2 +
1157 PTR_DIFF(this_req->out.data + this_param, this_req->out.hdr));
1158 SSVAL(this_req->out.vwv, VWV(8), PTR_DIFF(data, trans->out.data.data));
1160 SCVAL(this_req->out.vwv, VWV(9), trans->out.setup_count);
1161 SCVAL(this_req->out.vwv, VWV(9)+1, 0); /* reserved */
1162 for (i=0;i<trans->out.setup_count;i++) {
1163 SSVAL(this_req->out.vwv, VWV(10+i), trans->out.setup[i]);
1166 memset(this_req->out.data, 0, align1);
1167 if (this_param != 0) {
1168 memcpy(this_req->out.data + align1, params, this_param);
1170 memset(this_req->out.data+this_param+align1, 0, align2);
1171 if (this_data != 0) {
1172 memcpy(this_req->out.data+this_param+align1+align2, data, this_data);
1175 params_left -= this_param;
1176 data_left -= this_data;
1177 params += this_param;
1178 data += this_data;
1180 smbsrv_send_reply(this_req);
1181 } while (params_left != 0 || data_left != 0);
1186 answer a reconstructed trans request
1188 static void reply_trans_complete(struct smbsrv_request *req, uint8_t command,
1189 struct smb_trans2 *trans)
1191 struct trans_op *op;
1193 SMBSRV_TALLOC_IO_PTR(op, struct trans_op);
1194 SMBSRV_SETUP_NTVFS_REQUEST(reply_trans_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1196 op->req = req;
1197 op->trans = trans;
1198 op->command = command;
1199 op->op_info = NULL;
1200 op->send_fn = NULL;
1202 /* its a full request, give it to the backend */
1203 if (command == SMBtrans) {
1204 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_trans(req->ntvfs, trans));
1205 return;
1206 } else {
1207 SMBSRV_CALL_NTVFS_BACKEND(trans2_backend(req, op));
1208 return;
1213 Reply to an SMBtrans or SMBtrans2 request
1215 static void reply_trans_generic(struct smbsrv_request *req, uint8_t command)
1217 struct smb_trans2 *trans;
1218 int i;
1219 uint16_t param_ofs, data_ofs;
1220 uint16_t param_count, data_count;
1221 uint16_t param_total, data_total;
1223 /* parse request */
1224 if (req->in.wct < 14) {
1225 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1226 return;
1229 trans = talloc(req, struct smb_trans2);
1230 if (trans == NULL) {
1231 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
1232 return;
1235 param_total = SVAL(req->in.vwv, VWV(0));
1236 data_total = SVAL(req->in.vwv, VWV(1));
1237 trans->in.max_param = SVAL(req->in.vwv, VWV(2));
1238 trans->in.max_data = SVAL(req->in.vwv, VWV(3));
1239 trans->in.max_setup = CVAL(req->in.vwv, VWV(4));
1240 trans->in.flags = SVAL(req->in.vwv, VWV(5));
1241 trans->in.timeout = IVAL(req->in.vwv, VWV(6));
1242 param_count = SVAL(req->in.vwv, VWV(9));
1243 param_ofs = SVAL(req->in.vwv, VWV(10));
1244 data_count = SVAL(req->in.vwv, VWV(11));
1245 data_ofs = SVAL(req->in.vwv, VWV(12));
1246 trans->in.setup_count = CVAL(req->in.vwv, VWV(13));
1248 if (req->in.wct != 14 + trans->in.setup_count) {
1249 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
1250 return;
1253 /* parse out the setup words */
1254 trans->in.setup = talloc_array(trans, uint16_t, trans->in.setup_count);
1255 if (trans->in.setup_count && !trans->in.setup) {
1256 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
1257 return;
1259 for (i=0;i<trans->in.setup_count;i++) {
1260 trans->in.setup[i] = SVAL(req->in.vwv, VWV(14+i));
1263 if (command == SMBtrans) {
1264 req_pull_string(&req->in.bufinfo, &trans->in.trans_name, req->in.data, -1, STR_TERMINATE);
1267 if (!req_pull_blob(&req->in.bufinfo, req->in.hdr + param_ofs, param_count, &trans->in.params) ||
1268 !req_pull_blob(&req->in.bufinfo, req->in.hdr + data_ofs, data_count, &trans->in.data)) {
1269 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1270 return;
1273 /* is it a partial request? if so, then send a 'send more' message */
1274 if (param_total > param_count || data_total > data_count) {
1275 reply_trans_continue(req, command, trans);
1276 return;
1279 reply_trans_complete(req, command, trans);
1284 Reply to an SMBtranss2 request
1286 static void reply_transs_generic(struct smbsrv_request *req, uint8_t command)
1288 struct smbsrv_trans_partial *tp;
1289 struct smb_trans2 *trans = NULL;
1290 uint16_t param_ofs, data_ofs;
1291 uint16_t param_count, data_count;
1292 uint16_t param_disp, data_disp;
1293 uint16_t param_total, data_total;
1294 DATA_BLOB params, data;
1295 uint8_t wct;
1297 if (command == SMBtrans2) {
1298 wct = 9;
1299 } else {
1300 wct = 8;
1303 /* parse request */
1304 if (req->in.wct != wct) {
1306 * TODO: add some error code tests
1307 * w2k3 returns NT_STATUS_DOS(ERRSRV, ERRerror) here
1309 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1310 return;
1313 for (tp=req->smb_conn->trans_partial;tp;tp=tp->next) {
1314 if (tp->command == command &&
1315 SVAL(tp->req->in.hdr, HDR_MID) == SVAL(req->in.hdr, HDR_MID)) {
1316 /* TODO: check the VUID, PID and TID too? */
1317 break;
1321 if (tp == NULL) {
1322 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1323 return;
1326 trans = tp->trans;
1328 param_total = SVAL(req->in.vwv, VWV(0));
1329 data_total = SVAL(req->in.vwv, VWV(1));
1330 param_count = SVAL(req->in.vwv, VWV(2));
1331 param_ofs = SVAL(req->in.vwv, VWV(3));
1332 param_disp = SVAL(req->in.vwv, VWV(4));
1333 data_count = SVAL(req->in.vwv, VWV(5));
1334 data_ofs = SVAL(req->in.vwv, VWV(6));
1335 data_disp = SVAL(req->in.vwv, VWV(7));
1337 if (!req_pull_blob(&req->in.bufinfo, req->in.hdr + param_ofs, param_count, &params) ||
1338 !req_pull_blob(&req->in.bufinfo, req->in.hdr + data_ofs, data_count, &data)) {
1339 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1340 return;
1343 /* only allow contiguous requests */
1344 if ((param_count != 0 &&
1345 param_disp != trans->in.params.length) ||
1346 (data_count != 0 &&
1347 data_disp != trans->in.data.length)) {
1348 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1349 return;
1352 /* add to the existing request */
1353 if (param_count != 0) {
1354 trans->in.params.data = talloc_realloc(trans,
1355 trans->in.params.data,
1356 uint8_t,
1357 param_disp + param_count);
1358 if (trans->in.params.data == NULL) {
1359 smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
1360 return;
1362 trans->in.params.length = param_disp + param_count;
1365 if (data_count != 0) {
1366 trans->in.data.data = talloc_realloc(trans,
1367 trans->in.data.data,
1368 uint8_t,
1369 data_disp + data_count);
1370 if (trans->in.data.data == NULL) {
1371 smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
1372 return;
1374 trans->in.data.length = data_disp + data_count;
1377 memcpy(trans->in.params.data + param_disp, params.data, params.length);
1378 memcpy(trans->in.data.data + data_disp, data.data, data.length);
1380 /* the sequence number of the reply is taken from the last secondary
1381 response */
1382 tp->req->seq_num = req->seq_num;
1384 /* we don't reply to Transs2 requests */
1385 talloc_free(req);
1387 if (trans->in.params.length == param_total &&
1388 trans->in.data.length == data_total) {
1389 /* its now complete */
1390 req = tp->req;
1391 talloc_free(tp);
1392 reply_trans_complete(req, command, trans);
1394 return;
1399 Reply to an SMBtrans2
1401 void smbsrv_reply_trans2(struct smbsrv_request *req)
1403 reply_trans_generic(req, SMBtrans2);
1407 Reply to an SMBtrans
1409 void smbsrv_reply_trans(struct smbsrv_request *req)
1411 reply_trans_generic(req, SMBtrans);
1415 Reply to an SMBtranss request
1417 void smbsrv_reply_transs(struct smbsrv_request *req)
1419 reply_transs_generic(req, SMBtrans);
1423 Reply to an SMBtranss2 request
1425 void smbsrv_reply_transs2(struct smbsrv_request *req)
1427 reply_transs_generic(req, SMBtrans2);