s3-libnet: allow to use default krb5 ccache in libnet_Join/libnet_Unjoin.
[Samba.git] / source4 / smb_server / smb / trans2.c
bloba9445860f16f420bd79cfc8f859e7dc18aa6821e
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 "smb_server/smb_server.h"
25 #include "ntvfs/ntvfs.h"
26 #include "libcli/raw/libcliraw.h"
27 #include "libcli/raw/raw_proto.h"
29 #define TRANS2_CHECK_ASYNC_STATUS_SIMPLE do { \
30 if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) { \
31 trans2_setup_reply(trans, 0, 0, 0);\
32 return req->ntvfs->async_states->status; \
33 } \
34 } while (0)
35 #define TRANS2_CHECK_ASYNC_STATUS(ptr, type) do { \
36 TRANS2_CHECK_ASYNC_STATUS_SIMPLE; \
37 ptr = talloc_get_type(op->op_info, type); \
38 } while (0)
39 #define TRANS2_CHECK(cmd) do { \
40 NTSTATUS _status; \
41 _status = cmd; \
42 NT_STATUS_NOT_OK_RETURN(_status); \
43 } while (0)
46 hold the state of a nttrans op while in progress. Needed to allow for async backend
47 functions.
49 struct trans_op {
50 struct smbsrv_request *req;
51 struct smb_trans2 *trans;
52 uint8_t command;
53 NTSTATUS (*send_fn)(struct trans_op *);
54 void *op_info;
57 #define CHECK_MIN_BLOB_SIZE(blob, size) do { \
58 if ((blob)->length < (size)) { \
59 return NT_STATUS_INFO_LENGTH_MISMATCH; \
60 }} while (0)
62 /* setup a trans2 reply, given the data and params sizes */
63 static NTSTATUS trans2_setup_reply(struct smb_trans2 *trans,
64 uint16_t param_size, uint16_t data_size,
65 uint8_t setup_count)
67 trans->out.setup_count = setup_count;
68 if (setup_count > 0) {
69 trans->out.setup = talloc_zero_array(trans, uint16_t, setup_count);
70 NT_STATUS_HAVE_NO_MEMORY(trans->out.setup);
72 trans->out.params = data_blob_talloc(trans, NULL, param_size);
73 if (param_size > 0) NT_STATUS_HAVE_NO_MEMORY(trans->out.params.data);
75 trans->out.data = data_blob_talloc(trans, NULL, data_size);
76 if (data_size > 0) NT_STATUS_HAVE_NO_MEMORY(trans->out.data.data);
78 return NT_STATUS_OK;
81 static NTSTATUS trans2_push_fsinfo(struct smbsrv_connection *smb_conn,
82 TALLOC_CTX *mem_ctx,
83 DATA_BLOB *blob,
84 union smb_fsinfo *fsinfo,
85 int default_str_flags)
87 enum smb_fsinfo_level passthru_level;
89 switch (fsinfo->generic.level) {
90 case RAW_QFS_ALLOCATION:
91 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 18));
93 SIVAL(blob->data, 0, fsinfo->allocation.out.fs_id);
94 SIVAL(blob->data, 4, fsinfo->allocation.out.sectors_per_unit);
95 SIVAL(blob->data, 8, fsinfo->allocation.out.total_alloc_units);
96 SIVAL(blob->data, 12, fsinfo->allocation.out.avail_alloc_units);
97 SSVAL(blob->data, 16, fsinfo->allocation.out.bytes_per_sector);
99 return NT_STATUS_OK;
101 case RAW_QFS_VOLUME:
102 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 5));
104 SIVAL(blob->data, 0, fsinfo->volume.out.serial_number);
105 /* w2k3 implements this incorrectly for unicode - it
106 * leaves the last byte off the string */
107 TRANS2_CHECK(smbsrv_blob_append_string(mem_ctx, blob,
108 fsinfo->volume.out.volume_name.s,
109 4, default_str_flags,
110 STR_LEN8BIT|STR_NOALIGN));
112 return NT_STATUS_OK;
114 case RAW_QFS_VOLUME_INFO:
115 passthru_level = RAW_QFS_VOLUME_INFORMATION;
116 break;
118 case RAW_QFS_SIZE_INFO:
119 passthru_level = RAW_QFS_SIZE_INFORMATION;
120 break;
122 case RAW_QFS_DEVICE_INFO:
123 passthru_level = RAW_QFS_DEVICE_INFORMATION;
124 break;
126 case RAW_QFS_ATTRIBUTE_INFO:
127 passthru_level = RAW_QFS_ATTRIBUTE_INFORMATION;
128 break;
130 default:
131 passthru_level = fsinfo->generic.level;
132 break;
135 return smbsrv_push_passthru_fsinfo(mem_ctx, blob,
136 passthru_level, fsinfo,
137 default_str_flags);
141 trans2 qfsinfo implementation send
143 static NTSTATUS trans2_qfsinfo_send(struct trans_op *op)
145 struct smbsrv_request *req = op->req;
146 struct smb_trans2 *trans = op->trans;
147 union smb_fsinfo *fsinfo;
149 TRANS2_CHECK_ASYNC_STATUS(fsinfo, union smb_fsinfo);
151 TRANS2_CHECK(trans2_setup_reply(trans, 0, 0, 0));
153 TRANS2_CHECK(trans2_push_fsinfo(req->smb_conn, trans,
154 &trans->out.data, fsinfo,
155 SMBSRV_REQ_DEFAULT_STR_FLAGS(req)));
157 return NT_STATUS_OK;
161 trans2 qfsinfo implementation
163 static NTSTATUS trans2_qfsinfo(struct smbsrv_request *req, struct trans_op *op)
165 struct smb_trans2 *trans = op->trans;
166 union smb_fsinfo *fsinfo;
167 uint16_t level;
169 /* make sure we got enough parameters */
170 if (trans->in.params.length != 2) {
171 return NT_STATUS_FOOBAR;
174 fsinfo = talloc(op, union smb_fsinfo);
175 NT_STATUS_HAVE_NO_MEMORY(fsinfo);
177 level = SVAL(trans->in.params.data, 0);
179 /* work out the backend level - we make it 1-1 in the header */
180 fsinfo->generic.level = (enum smb_fsinfo_level)level;
181 if (fsinfo->generic.level >= RAW_QFS_GENERIC) {
182 return NT_STATUS_INVALID_LEVEL;
185 op->op_info = fsinfo;
186 op->send_fn = trans2_qfsinfo_send;
188 return ntvfs_fsinfo(req->ntvfs, fsinfo);
193 trans2 open implementation send
195 static NTSTATUS trans2_open_send(struct trans_op *op)
197 struct smbsrv_request *req = op->req;
198 struct smb_trans2 *trans = op->trans;
199 union smb_open *io;
201 TRANS2_CHECK_ASYNC_STATUS(io, union smb_open);
203 TRANS2_CHECK(trans2_setup_reply(trans, 30, 0, 0));
205 smbsrv_push_fnum(trans->out.params.data, VWV(0), io->t2open.out.file.ntvfs);
206 SSVAL(trans->out.params.data, VWV(1), io->t2open.out.attrib);
207 srv_push_dos_date3(req->smb_conn, trans->out.params.data,
208 VWV(2), io->t2open.out.write_time);
209 SIVAL(trans->out.params.data, VWV(4), io->t2open.out.size);
210 SSVAL(trans->out.params.data, VWV(6), io->t2open.out.access);
211 SSVAL(trans->out.params.data, VWV(7), io->t2open.out.ftype);
212 SSVAL(trans->out.params.data, VWV(8), io->t2open.out.devstate);
213 SSVAL(trans->out.params.data, VWV(9), io->t2open.out.action);
214 SIVAL(trans->out.params.data, VWV(10), 0); /* reserved */
215 SSVAL(trans->out.params.data, VWV(12), 0); /* EaErrorOffset */
216 SIVAL(trans->out.params.data, VWV(13), 0); /* EaLength */
218 return NT_STATUS_OK;
222 trans2 open implementation
224 static NTSTATUS trans2_open(struct smbsrv_request *req, struct trans_op *op)
226 struct smb_trans2 *trans = op->trans;
227 union smb_open *io;
229 /* make sure we got enough parameters */
230 if (trans->in.params.length < 29) {
231 return NT_STATUS_FOOBAR;
234 io = talloc(op, union smb_open);
235 NT_STATUS_HAVE_NO_MEMORY(io);
237 io->t2open.level = RAW_OPEN_T2OPEN;
238 io->t2open.in.flags = SVAL(trans->in.params.data, VWV(0));
239 io->t2open.in.open_mode = SVAL(trans->in.params.data, VWV(1));
240 io->t2open.in.search_attrs = SVAL(trans->in.params.data, VWV(2));
241 io->t2open.in.file_attrs = SVAL(trans->in.params.data, VWV(3));
242 io->t2open.in.write_time = srv_pull_dos_date(req->smb_conn,
243 trans->in.params.data + VWV(4));
244 io->t2open.in.open_func = SVAL(trans->in.params.data, VWV(6));
245 io->t2open.in.size = IVAL(trans->in.params.data, VWV(7));
246 io->t2open.in.timeout = IVAL(trans->in.params.data, VWV(9));
247 io->t2open.in.num_eas = 0;
248 io->t2open.in.eas = NULL;
250 smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 28, &io->t2open.in.fname, 0);
251 if (io->t2open.in.fname == NULL) {
252 return NT_STATUS_FOOBAR;
255 TRANS2_CHECK(ea_pull_list(&trans->in.data, io, &io->t2open.in.num_eas, &io->t2open.in.eas));
257 op->op_info = io;
258 op->send_fn = trans2_open_send;
260 return ntvfs_open(req->ntvfs, io);
265 trans2 simple send
267 static NTSTATUS trans2_simple_send(struct trans_op *op)
269 struct smbsrv_request *req = op->req;
270 struct smb_trans2 *trans = op->trans;
272 TRANS2_CHECK_ASYNC_STATUS_SIMPLE;
274 TRANS2_CHECK(trans2_setup_reply(trans, 2, 0, 0));
276 SSVAL(trans->out.params.data, VWV(0), 0);
278 return NT_STATUS_OK;
282 trans2 mkdir implementation
284 static NTSTATUS trans2_mkdir(struct smbsrv_request *req, struct trans_op *op)
286 struct smb_trans2 *trans = op->trans;
287 union smb_mkdir *io;
289 /* make sure we got enough parameters */
290 if (trans->in.params.length < 5) {
291 return NT_STATUS_FOOBAR;
294 io = talloc(op, union smb_mkdir);
295 NT_STATUS_HAVE_NO_MEMORY(io);
297 io->t2mkdir.level = RAW_MKDIR_T2MKDIR;
298 smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 4, &io->t2mkdir.in.path, 0);
299 if (io->t2mkdir.in.path == NULL) {
300 return NT_STATUS_FOOBAR;
303 TRANS2_CHECK(ea_pull_list(&trans->in.data, io,
304 &io->t2mkdir.in.num_eas,
305 &io->t2mkdir.in.eas));
307 op->op_info = io;
308 op->send_fn = trans2_simple_send;
310 return ntvfs_mkdir(req->ntvfs, io);
313 static NTSTATUS trans2_push_fileinfo(struct smbsrv_connection *smb_conn,
314 TALLOC_CTX *mem_ctx,
315 DATA_BLOB *blob,
316 union smb_fileinfo *st,
317 int default_str_flags)
319 uint32_t list_size;
320 enum smb_fileinfo_level passthru_level;
322 switch (st->generic.level) {
323 case RAW_FILEINFO_GENERIC:
324 case RAW_FILEINFO_GETATTR:
325 case RAW_FILEINFO_GETATTRE:
326 case RAW_FILEINFO_SEC_DESC:
327 case RAW_FILEINFO_SMB2_ALL_EAS:
328 case RAW_FILEINFO_SMB2_ALL_INFORMATION:
329 /* handled elsewhere */
330 return NT_STATUS_INVALID_LEVEL;
332 case RAW_FILEINFO_UNIX_BASIC:
333 case RAW_FILEINFO_UNIX_LINK:
334 /* not implemented yet */
335 return NT_STATUS_INVALID_LEVEL;
337 case RAW_FILEINFO_STANDARD:
338 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 22));
340 srv_push_dos_date2(smb_conn, blob->data, 0, st->standard.out.create_time);
341 srv_push_dos_date2(smb_conn, blob->data, 4, st->standard.out.access_time);
342 srv_push_dos_date2(smb_conn, blob->data, 8, st->standard.out.write_time);
343 SIVAL(blob->data, 12, st->standard.out.size);
344 SIVAL(blob->data, 16, st->standard.out.alloc_size);
345 SSVAL(blob->data, 20, st->standard.out.attrib);
346 return NT_STATUS_OK;
348 case RAW_FILEINFO_EA_SIZE:
349 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 26));
351 srv_push_dos_date2(smb_conn, blob->data, 0, st->ea_size.out.create_time);
352 srv_push_dos_date2(smb_conn, blob->data, 4, st->ea_size.out.access_time);
353 srv_push_dos_date2(smb_conn, blob->data, 8, st->ea_size.out.write_time);
354 SIVAL(blob->data, 12, st->ea_size.out.size);
355 SIVAL(blob->data, 16, st->ea_size.out.alloc_size);
356 SSVAL(blob->data, 20, st->ea_size.out.attrib);
357 SIVAL(blob->data, 22, st->ea_size.out.ea_size);
358 return NT_STATUS_OK;
360 case RAW_FILEINFO_EA_LIST:
361 list_size = ea_list_size(st->ea_list.out.num_eas,
362 st->ea_list.out.eas);
363 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, list_size));
365 ea_put_list(blob->data,
366 st->ea_list.out.num_eas, st->ea_list.out.eas);
367 return NT_STATUS_OK;
369 case RAW_FILEINFO_ALL_EAS:
370 list_size = ea_list_size(st->all_eas.out.num_eas,
371 st->all_eas.out.eas);
372 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, list_size));
374 ea_put_list(blob->data,
375 st->all_eas.out.num_eas, st->all_eas.out.eas);
376 return NT_STATUS_OK;
378 case RAW_FILEINFO_IS_NAME_VALID:
379 return NT_STATUS_OK;
381 case RAW_FILEINFO_BASIC_INFO:
382 passthru_level = RAW_FILEINFO_BASIC_INFORMATION;
383 break;
385 case RAW_FILEINFO_STANDARD_INFO:
386 passthru_level = RAW_FILEINFO_STANDARD_INFORMATION;
387 break;
389 case RAW_FILEINFO_EA_INFO:
390 passthru_level = RAW_FILEINFO_EA_INFORMATION;
391 break;
393 case RAW_FILEINFO_COMPRESSION_INFO:
394 passthru_level = RAW_FILEINFO_COMPRESSION_INFORMATION;
395 break;
397 case RAW_FILEINFO_ALL_INFO:
398 passthru_level = RAW_FILEINFO_ALL_INFORMATION;
399 break;
401 case RAW_FILEINFO_NAME_INFO:
402 passthru_level = RAW_FILEINFO_NAME_INFORMATION;
403 break;
405 case RAW_FILEINFO_ALT_NAME_INFO:
406 passthru_level = RAW_FILEINFO_ALT_NAME_INFORMATION;
407 break;
409 case RAW_FILEINFO_STREAM_INFO:
410 passthru_level = RAW_FILEINFO_STREAM_INFORMATION;
411 break;
413 default:
414 passthru_level = st->generic.level;
415 break;
418 return smbsrv_push_passthru_fileinfo(mem_ctx, blob,
419 passthru_level, st,
420 default_str_flags);
424 fill in the reply from a qpathinfo or qfileinfo call
426 static NTSTATUS trans2_fileinfo_send(struct trans_op *op)
428 struct smbsrv_request *req = op->req;
429 struct smb_trans2 *trans = op->trans;
430 union smb_fileinfo *st;
432 TRANS2_CHECK_ASYNC_STATUS(st, union smb_fileinfo);
434 TRANS2_CHECK(trans2_setup_reply(trans, 2, 0, 0));
435 SSVAL(trans->out.params.data, 0, 0);
437 TRANS2_CHECK(trans2_push_fileinfo(req->smb_conn, trans,
438 &trans->out.data, st,
439 SMBSRV_REQ_DEFAULT_STR_FLAGS(req)));
441 return NT_STATUS_OK;
445 trans2 qpathinfo implementation
447 static NTSTATUS trans2_qpathinfo(struct smbsrv_request *req, struct trans_op *op)
449 struct smb_trans2 *trans = op->trans;
450 union smb_fileinfo *st;
451 uint16_t level;
453 /* make sure we got enough parameters */
454 if (trans->in.params.length < 2) {
455 return NT_STATUS_FOOBAR;
458 st = talloc(op, union smb_fileinfo);
459 NT_STATUS_HAVE_NO_MEMORY(st);
461 level = SVAL(trans->in.params.data, 0);
463 smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 6, &st->generic.in.file.path, 0);
464 if (st->generic.in.file.path == NULL) {
465 return NT_STATUS_FOOBAR;
468 /* work out the backend level - we make it 1-1 in the header */
469 st->generic.level = (enum smb_fileinfo_level)level;
470 if (st->generic.level >= RAW_FILEINFO_GENERIC) {
471 return NT_STATUS_INVALID_LEVEL;
474 if (st->generic.level == RAW_FILEINFO_EA_LIST) {
475 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
476 &st->ea_list.in.num_names,
477 &st->ea_list.in.ea_names));
480 op->op_info = st;
481 op->send_fn = trans2_fileinfo_send;
483 return ntvfs_qpathinfo(req->ntvfs, st);
488 trans2 qpathinfo implementation
490 static NTSTATUS trans2_qfileinfo(struct smbsrv_request *req, struct trans_op *op)
492 struct smb_trans2 *trans = op->trans;
493 union smb_fileinfo *st;
494 uint16_t level;
495 struct ntvfs_handle *h;
497 /* make sure we got enough parameters */
498 if (trans->in.params.length < 4) {
499 return NT_STATUS_FOOBAR;
502 st = talloc(op, union smb_fileinfo);
503 NT_STATUS_HAVE_NO_MEMORY(st);
505 h = smbsrv_pull_fnum(req, trans->in.params.data, 0);
506 level = SVAL(trans->in.params.data, 2);
508 st->generic.in.file.ntvfs = h;
509 /* work out the backend level - we make it 1-1 in the header */
510 st->generic.level = (enum smb_fileinfo_level)level;
511 if (st->generic.level >= RAW_FILEINFO_GENERIC) {
512 return NT_STATUS_INVALID_LEVEL;
515 if (st->generic.level == RAW_FILEINFO_EA_LIST) {
516 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
517 &st->ea_list.in.num_names,
518 &st->ea_list.in.ea_names));
521 op->op_info = st;
522 op->send_fn = trans2_fileinfo_send;
524 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st->generic.in.file.ntvfs);
525 return ntvfs_qfileinfo(req->ntvfs, st);
530 parse a trans2 setfileinfo/setpathinfo data blob
532 static NTSTATUS trans2_parse_sfileinfo(struct smbsrv_request *req,
533 union smb_setfileinfo *st,
534 const DATA_BLOB *blob)
536 enum smb_setfileinfo_level passthru_level;
538 switch (st->generic.level) {
539 case RAW_SFILEINFO_GENERIC:
540 case RAW_SFILEINFO_SETATTR:
541 case RAW_SFILEINFO_SETATTRE:
542 case RAW_SFILEINFO_SEC_DESC:
543 /* handled elsewhere */
544 return NT_STATUS_INVALID_LEVEL;
546 case RAW_SFILEINFO_STANDARD:
547 CHECK_MIN_BLOB_SIZE(blob, 12);
549 st->standard.in.create_time = srv_pull_dos_date2(req->smb_conn, blob->data + 0);
550 st->standard.in.access_time = srv_pull_dos_date2(req->smb_conn, blob->data + 4);
551 st->standard.in.write_time = srv_pull_dos_date2(req->smb_conn, blob->data + 8);
553 return NT_STATUS_OK;
555 case RAW_SFILEINFO_EA_SET:
556 return ea_pull_list(blob, req,
557 &st->ea_set.in.num_eas,
558 &st->ea_set.in.eas);
560 case SMB_SFILEINFO_BASIC_INFO:
561 case SMB_SFILEINFO_BASIC_INFORMATION:
562 passthru_level = SMB_SFILEINFO_BASIC_INFORMATION;
563 break;
565 case SMB_SFILEINFO_DISPOSITION_INFO:
566 case SMB_SFILEINFO_DISPOSITION_INFORMATION:
567 passthru_level = SMB_SFILEINFO_DISPOSITION_INFORMATION;
568 break;
570 case SMB_SFILEINFO_ALLOCATION_INFO:
571 case SMB_SFILEINFO_ALLOCATION_INFORMATION:
572 passthru_level = SMB_SFILEINFO_ALLOCATION_INFORMATION;
573 break;
575 case RAW_SFILEINFO_END_OF_FILE_INFO:
576 case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
577 passthru_level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
578 break;
580 case RAW_SFILEINFO_RENAME_INFORMATION:
581 case RAW_SFILEINFO_POSITION_INFORMATION:
582 case RAW_SFILEINFO_MODE_INFORMATION:
583 passthru_level = st->generic.level;
584 break;
586 case RAW_SFILEINFO_UNIX_BASIC:
587 case RAW_SFILEINFO_UNIX_LINK:
588 case RAW_SFILEINFO_UNIX_HLINK:
589 case RAW_SFILEINFO_PIPE_INFORMATION:
590 case RAW_SFILEINFO_VALID_DATA_INFORMATION:
591 case RAW_SFILEINFO_SHORT_NAME_INFORMATION:
592 case RAW_SFILEINFO_1025:
593 case RAW_SFILEINFO_1027:
594 case RAW_SFILEINFO_1029:
595 case RAW_SFILEINFO_1030:
596 case RAW_SFILEINFO_1031:
597 case RAW_SFILEINFO_1032:
598 case RAW_SFILEINFO_1036:
599 case RAW_SFILEINFO_1041:
600 case RAW_SFILEINFO_1042:
601 case RAW_SFILEINFO_1043:
602 case RAW_SFILEINFO_1044:
603 return NT_STATUS_INVALID_LEVEL;
605 default:
606 /* we need a default here to cope with invalid values on the wire */
607 return NT_STATUS_INVALID_LEVEL;
610 return smbsrv_pull_passthru_sfileinfo(st, passthru_level, st,
611 blob, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
612 &req->in.bufinfo);
616 trans2 setfileinfo implementation
618 static NTSTATUS trans2_setfileinfo(struct smbsrv_request *req, struct trans_op *op)
620 struct smb_trans2 *trans = op->trans;
621 union smb_setfileinfo *st;
622 uint16_t level;
623 struct ntvfs_handle *h;
625 /* make sure we got enough parameters */
626 if (trans->in.params.length < 4) {
627 return NT_STATUS_FOOBAR;
630 st = talloc(op, union smb_setfileinfo);
631 NT_STATUS_HAVE_NO_MEMORY(st);
633 h = smbsrv_pull_fnum(req, trans->in.params.data, 0);
634 level = SVAL(trans->in.params.data, 2);
636 st->generic.in.file.ntvfs = h;
637 /* work out the backend level - we make it 1-1 in the header */
638 st->generic.level = (enum smb_setfileinfo_level)level;
639 if (st->generic.level >= RAW_SFILEINFO_GENERIC) {
640 return NT_STATUS_INVALID_LEVEL;
643 TRANS2_CHECK(trans2_parse_sfileinfo(req, st, &trans->in.data));
645 op->op_info = st;
646 op->send_fn = trans2_simple_send;
648 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st->generic.in.file.ntvfs);
649 return ntvfs_setfileinfo(req->ntvfs, st);
653 trans2 setpathinfo implementation
655 static NTSTATUS trans2_setpathinfo(struct smbsrv_request *req, struct trans_op *op)
657 struct smb_trans2 *trans = op->trans;
658 union smb_setfileinfo *st;
659 uint16_t level;
661 /* make sure we got enough parameters */
662 if (trans->in.params.length < 4) {
663 return NT_STATUS_FOOBAR;
666 st = talloc(op, union smb_setfileinfo);
667 NT_STATUS_HAVE_NO_MEMORY(st);
669 level = SVAL(trans->in.params.data, 0);
671 smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 6, &st->generic.in.file.path, 0);
672 if (st->generic.in.file.path == NULL) {
673 return NT_STATUS_FOOBAR;
676 /* work out the backend level - we make it 1-1 in the header */
677 st->generic.level = (enum smb_setfileinfo_level)level;
678 if (st->generic.level >= RAW_SFILEINFO_GENERIC) {
679 return NT_STATUS_INVALID_LEVEL;
682 TRANS2_CHECK(trans2_parse_sfileinfo(req, st, &trans->in.data));
684 op->op_info = st;
685 op->send_fn = trans2_simple_send;
687 return ntvfs_setpathinfo(req->ntvfs, st);
691 /* a structure to encapsulate the state information about an in-progress ffirst/fnext operation */
692 struct find_state {
693 struct trans_op *op;
694 void *search;
695 enum smb_search_data_level data_level;
696 uint16_t last_entry_offset;
697 uint16_t flags;
701 fill a single entry in a trans2 find reply
703 static NTSTATUS find_fill_info(struct find_state *state,
704 const union smb_search_data *file)
706 struct smbsrv_request *req = state->op->req;
707 struct smb_trans2 *trans = state->op->trans;
708 uint8_t *data;
709 uint_t ofs = trans->out.data.length;
710 uint32_t ea_size;
712 switch (state->data_level) {
713 case RAW_SEARCH_DATA_GENERIC:
714 case RAW_SEARCH_DATA_SEARCH:
715 /* handled elsewhere */
716 return NT_STATUS_INVALID_LEVEL;
718 case RAW_SEARCH_DATA_STANDARD:
719 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
720 TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 27));
721 SIVAL(trans->out.data.data, ofs, file->standard.resume_key);
722 ofs += 4;
723 } else {
724 TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 23));
726 data = trans->out.data.data + ofs;
727 srv_push_dos_date2(req->smb_conn, data, 0, file->standard.create_time);
728 srv_push_dos_date2(req->smb_conn, data, 4, file->standard.access_time);
729 srv_push_dos_date2(req->smb_conn, data, 8, file->standard.write_time);
730 SIVAL(data, 12, file->standard.size);
731 SIVAL(data, 16, file->standard.alloc_size);
732 SSVAL(data, 20, file->standard.attrib);
733 TRANS2_CHECK(smbsrv_blob_append_string(trans, &trans->out.data, file->standard.name.s,
734 ofs + 22, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
735 STR_LEN8BIT | STR_TERMINATE | STR_LEN_NOTERM));
736 break;
738 case RAW_SEARCH_DATA_EA_SIZE:
739 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
740 TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 31));
741 SIVAL(trans->out.data.data, ofs, file->ea_size.resume_key);
742 ofs += 4;
743 } else {
744 TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 27));
746 data = trans->out.data.data + ofs;
747 srv_push_dos_date2(req->smb_conn, data, 0, file->ea_size.create_time);
748 srv_push_dos_date2(req->smb_conn, data, 4, file->ea_size.access_time);
749 srv_push_dos_date2(req->smb_conn, data, 8, file->ea_size.write_time);
750 SIVAL(data, 12, file->ea_size.size);
751 SIVAL(data, 16, file->ea_size.alloc_size);
752 SSVAL(data, 20, file->ea_size.attrib);
753 SIVAL(data, 22, file->ea_size.ea_size);
754 TRANS2_CHECK(smbsrv_blob_append_string(trans, &trans->out.data, file->ea_size.name.s,
755 ofs + 26, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
756 STR_LEN8BIT | STR_NOALIGN));
757 TRANS2_CHECK(smbsrv_blob_fill_data(trans, &trans->out.data, trans->out.data.length + 1));
758 break;
760 case RAW_SEARCH_DATA_EA_LIST:
761 ea_size = ea_list_size(file->ea_list.eas.num_eas, file->ea_list.eas.eas);
762 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
763 TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 27 + ea_size));
764 SIVAL(trans->out.data.data, ofs, file->ea_list.resume_key);
765 ofs += 4;
766 } else {
767 TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 23 + ea_size));
769 data = trans->out.data.data + ofs;
770 srv_push_dos_date2(req->smb_conn, data, 0, file->ea_list.create_time);
771 srv_push_dos_date2(req->smb_conn, data, 4, file->ea_list.access_time);
772 srv_push_dos_date2(req->smb_conn, data, 8, file->ea_list.write_time);
773 SIVAL(data, 12, file->ea_list.size);
774 SIVAL(data, 16, file->ea_list.alloc_size);
775 SSVAL(data, 20, file->ea_list.attrib);
776 ea_put_list(data+22, file->ea_list.eas.num_eas, file->ea_list.eas.eas);
777 TRANS2_CHECK(smbsrv_blob_append_string(trans, &trans->out.data, file->ea_list.name.s,
778 ofs + 22 + ea_size, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
779 STR_LEN8BIT | STR_NOALIGN));
780 TRANS2_CHECK(smbsrv_blob_fill_data(trans, &trans->out.data, trans->out.data.length + 1));
781 break;
783 case RAW_SEARCH_DATA_DIRECTORY_INFO:
784 case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO:
785 case RAW_SEARCH_DATA_NAME_INFO:
786 case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO:
787 case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO:
788 case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO:
789 return smbsrv_push_passthru_search(trans, &trans->out.data, state->data_level, file,
790 SMBSRV_REQ_DEFAULT_STR_FLAGS(req));
792 case RAW_SEARCH_DATA_UNIX_INFO:
793 case RAW_SEARCH_DATA_UNIX_INFO2:
794 return NT_STATUS_INVALID_LEVEL;
797 return NT_STATUS_OK;
800 /* callback function for trans2 findfirst/findnext */
801 static bool find_callback(void *private_data, const union smb_search_data *file)
803 struct find_state *state = talloc_get_type(private_data, struct find_state);
804 struct smb_trans2 *trans = state->op->trans;
805 uint_t old_length;
807 old_length = trans->out.data.length;
809 if (!NT_STATUS_IS_OK(find_fill_info(state, file)) ||
810 trans->out.data.length > trans->in.max_data) {
811 /* restore the old length and tell the backend to stop */
812 smbsrv_blob_grow_data(trans, &trans->out.data, old_length);
813 return false;
816 state->last_entry_offset = old_length;
817 return true;
821 trans2 findfirst send
823 static NTSTATUS trans2_findfirst_send(struct trans_op *op)
825 struct smbsrv_request *req = op->req;
826 struct smb_trans2 *trans = op->trans;
827 union smb_search_first *search;
828 struct find_state *state;
829 uint8_t *param;
831 TRANS2_CHECK_ASYNC_STATUS(state, struct find_state);
832 search = talloc_get_type(state->search, union smb_search_first);
834 /* fill in the findfirst reply header */
835 param = trans->out.params.data;
836 SSVAL(param, VWV(0), search->t2ffirst.out.handle);
837 SSVAL(param, VWV(1), search->t2ffirst.out.count);
838 SSVAL(param, VWV(2), search->t2ffirst.out.end_of_search);
839 SSVAL(param, VWV(3), 0);
840 SSVAL(param, VWV(4), state->last_entry_offset);
842 return NT_STATUS_OK;
847 trans2 findfirst implementation
849 static NTSTATUS trans2_findfirst(struct smbsrv_request *req, struct trans_op *op)
851 struct smb_trans2 *trans = op->trans;
852 union smb_search_first *search;
853 uint16_t level;
854 struct find_state *state;
856 /* make sure we got all the parameters */
857 if (trans->in.params.length < 14) {
858 return NT_STATUS_FOOBAR;
861 search = talloc(op, union smb_search_first);
862 NT_STATUS_HAVE_NO_MEMORY(search);
864 search->t2ffirst.in.search_attrib = SVAL(trans->in.params.data, 0);
865 search->t2ffirst.in.max_count = SVAL(trans->in.params.data, 2);
866 search->t2ffirst.in.flags = SVAL(trans->in.params.data, 4);
867 level = SVAL(trans->in.params.data, 6);
868 search->t2ffirst.in.storage_type = IVAL(trans->in.params.data, 8);
870 smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 12, &search->t2ffirst.in.pattern, 0);
871 if (search->t2ffirst.in.pattern == NULL) {
872 return NT_STATUS_FOOBAR;
875 search->t2ffirst.level = RAW_SEARCH_TRANS2;
876 search->t2ffirst.data_level = (enum smb_search_data_level)level;
877 if (search->t2ffirst.data_level >= RAW_SEARCH_DATA_GENERIC) {
878 return NT_STATUS_INVALID_LEVEL;
881 if (search->t2ffirst.data_level == RAW_SEARCH_DATA_EA_LIST) {
882 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
883 &search->t2ffirst.in.num_names,
884 &search->t2ffirst.in.ea_names));
887 /* setup the private state structure that the backend will
888 give us in the callback */
889 state = talloc(op, struct find_state);
890 NT_STATUS_HAVE_NO_MEMORY(state);
891 state->op = op;
892 state->search = search;
893 state->data_level = search->t2ffirst.data_level;
894 state->last_entry_offset= 0;
895 state->flags = search->t2ffirst.in.flags;
897 /* setup for just a header in the reply */
898 TRANS2_CHECK(trans2_setup_reply(trans, 10, 0, 0));
900 op->op_info = state;
901 op->send_fn = trans2_findfirst_send;
903 return ntvfs_search_first(req->ntvfs, search, state, find_callback);
908 trans2 findnext send
910 static NTSTATUS trans2_findnext_send(struct trans_op *op)
912 struct smbsrv_request *req = op->req;
913 struct smb_trans2 *trans = op->trans;
914 union smb_search_next *search;
915 struct find_state *state;
916 uint8_t *param;
918 TRANS2_CHECK_ASYNC_STATUS(state, struct find_state);
919 search = talloc_get_type(state->search, union smb_search_next);
921 /* fill in the findfirst reply header */
922 param = trans->out.params.data;
923 SSVAL(param, VWV(0), search->t2fnext.out.count);
924 SSVAL(param, VWV(1), search->t2fnext.out.end_of_search);
925 SSVAL(param, VWV(2), 0);
926 SSVAL(param, VWV(3), state->last_entry_offset);
928 return NT_STATUS_OK;
933 trans2 findnext implementation
935 static NTSTATUS trans2_findnext(struct smbsrv_request *req, struct trans_op *op)
937 struct smb_trans2 *trans = op->trans;
938 union smb_search_next *search;
939 uint16_t level;
940 struct find_state *state;
942 /* make sure we got all the parameters */
943 if (trans->in.params.length < 12) {
944 return NT_STATUS_FOOBAR;
947 search = talloc(op, union smb_search_next);
948 NT_STATUS_HAVE_NO_MEMORY(search);
950 search->t2fnext.in.handle = SVAL(trans->in.params.data, 0);
951 search->t2fnext.in.max_count = SVAL(trans->in.params.data, 2);
952 level = SVAL(trans->in.params.data, 4);
953 search->t2fnext.in.resume_key = IVAL(trans->in.params.data, 6);
954 search->t2fnext.in.flags = SVAL(trans->in.params.data, 10);
956 smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 12, &search->t2fnext.in.last_name, 0);
957 if (search->t2fnext.in.last_name == NULL) {
958 return NT_STATUS_FOOBAR;
961 search->t2fnext.level = RAW_SEARCH_TRANS2;
962 search->t2fnext.data_level = (enum smb_search_data_level)level;
963 if (search->t2fnext.data_level >= RAW_SEARCH_DATA_GENERIC) {
964 return NT_STATUS_INVALID_LEVEL;
967 if (search->t2fnext.data_level == RAW_SEARCH_DATA_EA_LIST) {
968 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
969 &search->t2fnext.in.num_names,
970 &search->t2fnext.in.ea_names));
973 /* setup the private state structure that the backend will give us in the callback */
974 state = talloc(op, struct find_state);
975 NT_STATUS_HAVE_NO_MEMORY(state);
976 state->op = op;
977 state->search = search;
978 state->data_level = search->t2fnext.data_level;
979 state->last_entry_offset= 0;
980 state->flags = search->t2fnext.in.flags;
982 /* setup for just a header in the reply */
983 TRANS2_CHECK(trans2_setup_reply(trans, 8, 0, 0));
985 op->op_info = state;
986 op->send_fn = trans2_findnext_send;
988 return ntvfs_search_next(req->ntvfs, search, state, find_callback);
993 backend for trans2 requests
995 static NTSTATUS trans2_backend(struct smbsrv_request *req, struct trans_op *op)
997 struct smb_trans2 *trans = op->trans;
998 NTSTATUS status;
1000 /* direct trans2 pass thru */
1001 status = ntvfs_trans2(req->ntvfs, trans);
1002 if (!NT_STATUS_EQUAL(NT_STATUS_NOT_IMPLEMENTED, status)) {
1003 return status;
1006 /* must have at least one setup word */
1007 if (trans->in.setup_count < 1) {
1008 return NT_STATUS_FOOBAR;
1011 /* the trans2 command is in setup[0] */
1012 switch (trans->in.setup[0]) {
1013 case TRANSACT2_FINDFIRST:
1014 return trans2_findfirst(req, op);
1015 case TRANSACT2_FINDNEXT:
1016 return trans2_findnext(req, op);
1017 case TRANSACT2_QPATHINFO:
1018 return trans2_qpathinfo(req, op);
1019 case TRANSACT2_QFILEINFO:
1020 return trans2_qfileinfo(req, op);
1021 case TRANSACT2_SETFILEINFO:
1022 return trans2_setfileinfo(req, op);
1023 case TRANSACT2_SETPATHINFO:
1024 return trans2_setpathinfo(req, op);
1025 case TRANSACT2_QFSINFO:
1026 return trans2_qfsinfo(req, op);
1027 case TRANSACT2_OPEN:
1028 return trans2_open(req, op);
1029 case TRANSACT2_MKDIR:
1030 return trans2_mkdir(req, op);
1033 /* an unknown trans2 command */
1034 return NT_STATUS_FOOBAR;
1037 int smbsrv_trans_partial_destructor(struct smbsrv_trans_partial *tp)
1039 DLIST_REMOVE(tp->req->smb_conn->trans_partial, tp);
1040 return 0;
1045 send a continue request
1047 static void reply_trans_continue(struct smbsrv_request *req, uint8_t command,
1048 struct smb_trans2 *trans)
1050 struct smbsrv_request *req2;
1051 struct smbsrv_trans_partial *tp;
1052 int count;
1054 /* make sure they don't flood us */
1055 for (count=0,tp=req->smb_conn->trans_partial;tp;tp=tp->next) count++;
1056 if (count > 100) {
1057 smbsrv_send_error(req, NT_STATUS_INSUFFICIENT_RESOURCES);
1058 return;
1061 tp = talloc(req, struct smbsrv_trans_partial);
1063 tp->req = req;
1064 tp->u.trans = trans;
1065 tp->command = command;
1067 DLIST_ADD(req->smb_conn->trans_partial, tp);
1068 talloc_set_destructor(tp, smbsrv_trans_partial_destructor);
1070 req2 = smbsrv_setup_secondary_request(req);
1072 /* send a 'please continue' reply */
1073 smbsrv_setup_reply(req2, 0, 0);
1074 smbsrv_send_reply(req2);
1079 answer a reconstructed trans request
1081 static void reply_trans_send(struct ntvfs_request *ntvfs)
1083 struct smbsrv_request *req;
1084 struct trans_op *op;
1085 struct smb_trans2 *trans;
1086 uint16_t params_left, data_left;
1087 uint8_t *params, *data;
1088 int i;
1090 SMBSRV_CHECK_ASYNC_STATUS_ERR(op, struct trans_op);
1091 trans = op->trans;
1093 /* if this function needs work to form the nttrans reply buffer, then
1094 call that now */
1095 if (op->send_fn != NULL) {
1096 NTSTATUS status;
1097 status = op->send_fn(op);
1098 if (!NT_STATUS_IS_OK(status)) {
1099 smbsrv_send_error(req, status);
1100 return;
1104 params_left = trans->out.params.length;
1105 data_left = trans->out.data.length;
1106 params = trans->out.params.data;
1107 data = trans->out.data.data;
1109 smbsrv_setup_reply(req, 10 + trans->out.setup_count, 0);
1111 if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) {
1112 smbsrv_setup_error(req, req->ntvfs->async_states->status);
1115 /* we need to divide up the reply into chunks that fit into
1116 the negotiated buffer size */
1117 do {
1118 uint16_t this_data, this_param, max_bytes;
1119 uint_t align1 = 1, align2 = (params_left ? 2 : 0);
1120 struct smbsrv_request *this_req;
1122 max_bytes = req_max_data(req) - (align1 + align2);
1124 this_param = params_left;
1125 if (this_param > max_bytes) {
1126 this_param = max_bytes;
1128 max_bytes -= this_param;
1130 this_data = data_left;
1131 if (this_data > max_bytes) {
1132 this_data = max_bytes;
1135 /* don't destroy unless this is the last chunk */
1136 if (params_left - this_param != 0 ||
1137 data_left - this_data != 0) {
1138 this_req = smbsrv_setup_secondary_request(req);
1139 } else {
1140 this_req = req;
1143 req_grow_data(this_req, this_param + this_data + (align1 + align2));
1145 SSVAL(this_req->out.vwv, VWV(0), trans->out.params.length);
1146 SSVAL(this_req->out.vwv, VWV(1), trans->out.data.length);
1147 SSVAL(this_req->out.vwv, VWV(2), 0);
1149 SSVAL(this_req->out.vwv, VWV(3), this_param);
1150 SSVAL(this_req->out.vwv, VWV(4), align1 + PTR_DIFF(this_req->out.data, this_req->out.hdr));
1151 SSVAL(this_req->out.vwv, VWV(5), PTR_DIFF(params, trans->out.params.data));
1153 SSVAL(this_req->out.vwv, VWV(6), this_data);
1154 SSVAL(this_req->out.vwv, VWV(7), align1 + align2 +
1155 PTR_DIFF(this_req->out.data + this_param, this_req->out.hdr));
1156 SSVAL(this_req->out.vwv, VWV(8), PTR_DIFF(data, trans->out.data.data));
1158 SCVAL(this_req->out.vwv, VWV(9), trans->out.setup_count);
1159 SCVAL(this_req->out.vwv, VWV(9)+1, 0); /* reserved */
1160 for (i=0;i<trans->out.setup_count;i++) {
1161 SSVAL(this_req->out.vwv, VWV(10+i), trans->out.setup[i]);
1164 memset(this_req->out.data, 0, align1);
1165 if (this_param != 0) {
1166 memcpy(this_req->out.data + align1, params, this_param);
1168 memset(this_req->out.data+this_param+align1, 0, align2);
1169 if (this_data != 0) {
1170 memcpy(this_req->out.data+this_param+align1+align2, data, this_data);
1173 params_left -= this_param;
1174 data_left -= this_data;
1175 params += this_param;
1176 data += this_data;
1178 smbsrv_send_reply(this_req);
1179 } while (params_left != 0 || data_left != 0);
1184 answer a reconstructed trans request
1186 static void reply_trans_complete(struct smbsrv_request *req, uint8_t command,
1187 struct smb_trans2 *trans)
1189 struct trans_op *op;
1191 SMBSRV_TALLOC_IO_PTR(op, struct trans_op);
1192 SMBSRV_SETUP_NTVFS_REQUEST(reply_trans_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1194 op->req = req;
1195 op->trans = trans;
1196 op->command = command;
1197 op->op_info = NULL;
1198 op->send_fn = NULL;
1200 /* its a full request, give it to the backend */
1201 if (command == SMBtrans) {
1202 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_trans(req->ntvfs, trans));
1203 return;
1204 } else {
1205 SMBSRV_CALL_NTVFS_BACKEND(trans2_backend(req, op));
1206 return;
1211 Reply to an SMBtrans or SMBtrans2 request
1213 static void reply_trans_generic(struct smbsrv_request *req, uint8_t command)
1215 struct smb_trans2 *trans;
1216 int i;
1217 uint16_t param_ofs, data_ofs;
1218 uint16_t param_count, data_count;
1219 uint16_t param_total, data_total;
1221 /* parse request */
1222 if (req->in.wct < 14) {
1223 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1224 return;
1227 trans = talloc(req, struct smb_trans2);
1228 if (trans == NULL) {
1229 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
1230 return;
1233 param_total = SVAL(req->in.vwv, VWV(0));
1234 data_total = SVAL(req->in.vwv, VWV(1));
1235 trans->in.max_param = SVAL(req->in.vwv, VWV(2));
1236 trans->in.max_data = SVAL(req->in.vwv, VWV(3));
1237 trans->in.max_setup = CVAL(req->in.vwv, VWV(4));
1238 trans->in.flags = SVAL(req->in.vwv, VWV(5));
1239 trans->in.timeout = IVAL(req->in.vwv, VWV(6));
1240 param_count = SVAL(req->in.vwv, VWV(9));
1241 param_ofs = SVAL(req->in.vwv, VWV(10));
1242 data_count = SVAL(req->in.vwv, VWV(11));
1243 data_ofs = SVAL(req->in.vwv, VWV(12));
1244 trans->in.setup_count = CVAL(req->in.vwv, VWV(13));
1246 if (req->in.wct != 14 + trans->in.setup_count) {
1247 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
1248 return;
1251 /* parse out the setup words */
1252 trans->in.setup = talloc_array(trans, uint16_t, trans->in.setup_count);
1253 if (trans->in.setup_count && !trans->in.setup) {
1254 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
1255 return;
1257 for (i=0;i<trans->in.setup_count;i++) {
1258 trans->in.setup[i] = SVAL(req->in.vwv, VWV(14+i));
1261 if (command == SMBtrans) {
1262 req_pull_string(&req->in.bufinfo, &trans->in.trans_name, req->in.data, -1, STR_TERMINATE);
1265 if (!req_pull_blob(&req->in.bufinfo, req->in.hdr + param_ofs, param_count, &trans->in.params) ||
1266 !req_pull_blob(&req->in.bufinfo, req->in.hdr + data_ofs, data_count, &trans->in.data)) {
1267 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1268 return;
1271 /* is it a partial request? if so, then send a 'send more' message */
1272 if (param_total > param_count || data_total > data_count) {
1273 reply_trans_continue(req, command, trans);
1274 return;
1277 reply_trans_complete(req, command, trans);
1282 Reply to an SMBtranss2 request
1284 static void reply_transs_generic(struct smbsrv_request *req, uint8_t command)
1286 struct smbsrv_trans_partial *tp;
1287 struct smb_trans2 *trans = NULL;
1288 uint16_t param_ofs, data_ofs;
1289 uint16_t param_count, data_count;
1290 uint16_t param_disp, data_disp;
1291 uint16_t param_total, data_total;
1292 DATA_BLOB params, data;
1293 uint8_t wct;
1295 if (command == SMBtrans2) {
1296 wct = 9;
1297 } else {
1298 wct = 8;
1301 /* parse request */
1302 if (req->in.wct != wct) {
1304 * TODO: add some error code tests
1305 * w2k3 returns NT_STATUS_DOS(ERRSRV, ERRerror) here
1307 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1308 return;
1311 for (tp=req->smb_conn->trans_partial;tp;tp=tp->next) {
1312 if (tp->command == command &&
1313 SVAL(tp->req->in.hdr, HDR_MID) == SVAL(req->in.hdr, HDR_MID)) {
1314 /* TODO: check the VUID, PID and TID too? */
1315 break;
1319 if (tp == NULL) {
1320 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1321 return;
1324 trans = tp->u.trans;
1326 param_total = SVAL(req->in.vwv, VWV(0));
1327 data_total = SVAL(req->in.vwv, VWV(1));
1328 param_count = SVAL(req->in.vwv, VWV(2));
1329 param_ofs = SVAL(req->in.vwv, VWV(3));
1330 param_disp = SVAL(req->in.vwv, VWV(4));
1331 data_count = SVAL(req->in.vwv, VWV(5));
1332 data_ofs = SVAL(req->in.vwv, VWV(6));
1333 data_disp = SVAL(req->in.vwv, VWV(7));
1335 if (!req_pull_blob(&req->in.bufinfo, req->in.hdr + param_ofs, param_count, &params) ||
1336 !req_pull_blob(&req->in.bufinfo, req->in.hdr + data_ofs, data_count, &data)) {
1337 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1338 return;
1341 /* only allow contiguous requests */
1342 if ((param_count != 0 &&
1343 param_disp != trans->in.params.length) ||
1344 (data_count != 0 &&
1345 data_disp != trans->in.data.length)) {
1346 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1347 return;
1350 /* add to the existing request */
1351 if (param_count != 0) {
1352 trans->in.params.data = talloc_realloc(trans,
1353 trans->in.params.data,
1354 uint8_t,
1355 param_disp + param_count);
1356 if (trans->in.params.data == NULL) {
1357 smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
1358 return;
1360 trans->in.params.length = param_disp + param_count;
1363 if (data_count != 0) {
1364 trans->in.data.data = talloc_realloc(trans,
1365 trans->in.data.data,
1366 uint8_t,
1367 data_disp + data_count);
1368 if (trans->in.data.data == NULL) {
1369 smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
1370 return;
1372 trans->in.data.length = data_disp + data_count;
1375 memcpy(trans->in.params.data + param_disp, params.data, params.length);
1376 memcpy(trans->in.data.data + data_disp, data.data, data.length);
1378 /* the sequence number of the reply is taken from the last secondary
1379 response */
1380 tp->req->seq_num = req->seq_num;
1382 /* we don't reply to Transs2 requests */
1383 talloc_free(req);
1385 if (trans->in.params.length == param_total &&
1386 trans->in.data.length == data_total) {
1387 /* its now complete */
1388 req = tp->req;
1389 talloc_free(tp);
1390 reply_trans_complete(req, command, trans);
1392 return;
1397 Reply to an SMBtrans2
1399 void smbsrv_reply_trans2(struct smbsrv_request *req)
1401 reply_trans_generic(req, SMBtrans2);
1405 Reply to an SMBtrans
1407 void smbsrv_reply_trans(struct smbsrv_request *req)
1409 reply_trans_generic(req, SMBtrans);
1413 Reply to an SMBtranss request
1415 void smbsrv_reply_transs(struct smbsrv_request *req)
1417 reply_transs_generic(req, SMBtrans);
1421 Reply to an SMBtranss2 request
1423 void smbsrv_reply_transs2(struct smbsrv_request *req)
1425 reply_transs_generic(req, SMBtrans2);