r16357: - start get rid of void parsing functions
[Samba/aatanasov.git] / source / smb_server / smb / trans2.c
blobc29e1020e1d24e7420d9f40bc516c1e17eaf49bd
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 "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 /* grow the data size of a trans2 reply */
65 static NTSTATUS trans2_grow_data(TALLOC_CTX *mem_ctx,
66 DATA_BLOB *blob,
67 uint32_t new_size)
69 if (new_size > blob->length) {
70 blob->data = talloc_realloc(mem_ctx, blob->data, uint8_t, new_size);
71 NT_STATUS_HAVE_NO_MEMORY(blob->data);
73 blob->length = new_size;
74 return NT_STATUS_OK;
77 /* grow the data, zero filling any new bytes */
78 static NTSTATUS trans2_grow_data_fill(TALLOC_CTX *mem_ctx,
79 DATA_BLOB *blob,
80 uint32_t new_size)
82 uint32_t old_size = blob->length;
83 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, new_size));
84 if (new_size > old_size) {
85 memset(blob->data + old_size, 0, new_size - old_size);
87 return NT_STATUS_OK;
91 /* setup a trans2 reply, given the data and params sizes */
92 static NTSTATUS trans2_setup_reply(struct smb_trans2 *trans,
93 uint16_t param_size, uint16_t data_size,
94 uint16_t setup_count)
96 trans->out.setup_count = setup_count;
97 if (setup_count > 0) {
98 trans->out.setup = talloc_zero_array(trans, uint16_t, setup_count);
99 NT_STATUS_HAVE_NO_MEMORY(trans->out.setup);
101 trans->out.params = data_blob_talloc(trans, NULL, param_size);
102 if (param_size > 0) NT_STATUS_HAVE_NO_MEMORY(trans->out.params.data);
104 trans->out.data = data_blob_talloc(trans, NULL, data_size);
105 if (data_size > 0) NT_STATUS_HAVE_NO_MEMORY(trans->out.data.data);
107 return NT_STATUS_OK;
112 pull a string from a blob in a trans2 request
114 static size_t trans2_pull_blob_string(struct smbsrv_request *req,
115 const DATA_BLOB *blob,
116 uint16_t offset,
117 const char **str,
118 int flags)
120 /* we use STR_NO_RANGE_CHECK because the params are allocated
121 separately in a DATA_BLOB, so we need to do our own range
122 checking */
123 if (offset >= blob->length) {
124 *str = NULL;
125 return 0;
128 return req_pull_string(req, str,
129 blob->data + offset,
130 blob->length - offset,
131 STR_NO_RANGE_CHECK | flags);
135 push a string into the data section of a trans2 request
136 return the number of bytes consumed in the output
138 static size_t trans2_push_data_string(struct smbsrv_request *req,
139 TALLOC_CTX *mem_ctx,
140 DATA_BLOB *blob,
141 uint32_t len_offset,
142 uint32_t offset,
143 const struct smb_wire_string *str,
144 int dest_len,
145 int flags)
147 int alignment = 0, ret = 0, pkt_len;
149 /* we use STR_NO_RANGE_CHECK because the params are allocated
150 separately in a DATA_BLOB, so we need to do our own range
151 checking */
152 if (!str->s || offset >= blob->length) {
153 if (flags & STR_LEN8BIT) {
154 SCVAL(blob->data, len_offset, 0);
155 } else {
156 SIVAL(blob->data, len_offset, 0);
158 return 0;
161 flags |= STR_NO_RANGE_CHECK;
163 if (dest_len == -1 || (dest_len > blob->length - offset)) {
164 dest_len = blob->length - offset;
167 if (!(flags & (STR_ASCII|STR_UNICODE))) {
168 flags |= (req->flags2 & FLAGS2_UNICODE_STRINGS) ? STR_UNICODE : STR_ASCII;
171 if ((offset&1) && (flags & STR_UNICODE) && !(flags & STR_NOALIGN)) {
172 alignment = 1;
173 if (dest_len > 0) {
174 SCVAL(blob->data + offset, 0, 0);
175 ret = push_string(blob->data + offset + 1, str->s, dest_len-1, flags);
177 } else {
178 ret = push_string(blob->data + offset, str->s, dest_len, flags);
181 /* sometimes the string needs to be terminated, but the length
182 on the wire must not include the termination! */
183 pkt_len = ret;
185 if ((flags & STR_LEN_NOTERM) && (flags & STR_TERMINATE)) {
186 if ((flags & STR_UNICODE) && ret >= 2) {
187 pkt_len = ret-2;
189 if ((flags & STR_ASCII) && ret >= 1) {
190 pkt_len = ret-1;
194 if (flags & STR_LEN8BIT) {
195 SCVAL(blob->data, len_offset, pkt_len);
196 } else {
197 SIVAL(blob->data, len_offset, pkt_len);
200 return ret + alignment;
204 append a string to the data section of a trans2 reply
205 len_offset points to the place in the packet where the length field
206 should go
208 static NTSTATUS trans2_append_data_string(struct smbsrv_request *req,
209 TALLOC_CTX *mem_ctx,
210 DATA_BLOB *blob,
211 const struct smb_wire_string *str,
212 uint_t len_offset,
213 int flags)
215 size_t ret;
216 uint32_t offset;
217 const int max_bytes_per_char = 3;
219 offset = blob->length;
220 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, offset + (2+strlen_m(str->s))*max_bytes_per_char));
221 ret = trans2_push_data_string(req, mem_ctx, blob, len_offset, offset, str, -1, flags);
222 if (ret < 0) {
223 return NT_STATUS_FOOBAR;
225 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, offset + ret));
226 return NT_STATUS_OK;
230 align the end of the data section of a trans reply on an even boundary
232 static NTSTATUS trans2_align_data(struct smb_trans2 *trans)
234 if (trans->out.data.length & 1) {
235 TRANS2_CHECK(trans2_grow_data_fill(trans, &trans->out.data, trans->out.data.length+1));
237 return NT_STATUS_OK;
242 trans2 qfsinfo implementation send
244 static NTSTATUS trans2_qfsinfo_send(struct trans_op *op)
246 struct smbsrv_request *req = op->req;
247 struct smb_trans2 *trans = op->trans;
248 union smb_fsinfo *fsinfo;
249 NTSTATUS status;
250 uint_t i;
251 DATA_BLOB guid_blob;
253 TRANS2_CHECK_ASYNC_STATUS(fsinfo, union smb_fsinfo);
255 switch (fsinfo->generic.level) {
256 case SMB_QFS_ALLOCATION:
257 trans2_setup_reply(trans, 0, 18, 0);
259 SIVAL(trans->out.data.data, 0, fsinfo->allocation.out.fs_id);
260 SIVAL(trans->out.data.data, 4, fsinfo->allocation.out.sectors_per_unit);
261 SIVAL(trans->out.data.data, 8, fsinfo->allocation.out.total_alloc_units);
262 SIVAL(trans->out.data.data, 12, fsinfo->allocation.out.avail_alloc_units);
263 SSVAL(trans->out.data.data, 16, fsinfo->allocation.out.bytes_per_sector);
265 return NT_STATUS_OK;
267 case SMB_QFS_VOLUME:
268 trans2_setup_reply(trans, 0, 5, 0);
270 SIVAL(trans->out.data.data, 0, fsinfo->volume.out.serial_number);
271 /* w2k3 implements this incorrectly for unicode - it
272 * leaves the last byte off the string */
273 trans2_append_data_string(req, trans, &trans->out.data,
274 &fsinfo->volume.out.volume_name,
275 4, STR_LEN8BIT|STR_NOALIGN);
277 return NT_STATUS_OK;
279 case SMB_QFS_VOLUME_INFO:
280 case SMB_QFS_VOLUME_INFORMATION:
281 trans2_setup_reply(trans, 0, 18, 0);
283 push_nttime(trans->out.data.data, 0, fsinfo->volume_info.out.create_time);
284 SIVAL(trans->out.data.data, 8, fsinfo->volume_info.out.serial_number);
285 SSVAL(trans->out.data.data, 16, 0); /* padding */
286 trans2_append_data_string(req, trans, &trans->out.data,
287 &fsinfo->volume_info.out.volume_name,
288 12, STR_UNICODE);
290 return NT_STATUS_OK;
292 case SMB_QFS_SIZE_INFO:
293 case SMB_QFS_SIZE_INFORMATION:
294 trans2_setup_reply(trans, 0, 24, 0);
296 SBVAL(trans->out.data.data, 0, fsinfo->size_info.out.total_alloc_units);
297 SBVAL(trans->out.data.data, 8, fsinfo->size_info.out.avail_alloc_units);
298 SIVAL(trans->out.data.data, 16, fsinfo->size_info.out.sectors_per_unit);
299 SIVAL(trans->out.data.data, 20, fsinfo->size_info.out.bytes_per_sector);
301 return NT_STATUS_OK;
303 case SMB_QFS_DEVICE_INFO:
304 case SMB_QFS_DEVICE_INFORMATION:
305 trans2_setup_reply(trans, 0, 8, 0);
306 SIVAL(trans->out.data.data, 0, fsinfo->device_info.out.device_type);
307 SIVAL(trans->out.data.data, 4, fsinfo->device_info.out.characteristics);
308 return NT_STATUS_OK;
311 case SMB_QFS_ATTRIBUTE_INFO:
312 case SMB_QFS_ATTRIBUTE_INFORMATION:
313 trans2_setup_reply(trans, 0, 12, 0);
315 SIVAL(trans->out.data.data, 0, fsinfo->attribute_info.out.fs_attr);
316 SIVAL(trans->out.data.data, 4, fsinfo->attribute_info.out.max_file_component_length);
317 /* this must not be null terminated or win98 gets
318 confused! also note that w2k3 returns this as
319 unicode even when ascii is negotiated */
320 trans2_append_data_string(req, trans, &trans->out.data,
321 &fsinfo->attribute_info.out.fs_type,
322 8, STR_UNICODE);
323 return NT_STATUS_OK;
326 case SMB_QFS_QUOTA_INFORMATION:
327 trans2_setup_reply(trans, 0, 48, 0);
329 SBVAL(trans->out.data.data, 0, fsinfo->quota_information.out.unknown[0]);
330 SBVAL(trans->out.data.data, 8, fsinfo->quota_information.out.unknown[1]);
331 SBVAL(trans->out.data.data, 16, fsinfo->quota_information.out.unknown[2]);
332 SBVAL(trans->out.data.data, 24, fsinfo->quota_information.out.quota_soft);
333 SBVAL(trans->out.data.data, 32, fsinfo->quota_information.out.quota_hard);
334 SBVAL(trans->out.data.data, 40, fsinfo->quota_information.out.quota_flags);
336 return NT_STATUS_OK;
339 case SMB_QFS_FULL_SIZE_INFORMATION:
340 trans2_setup_reply(trans, 0, 32, 0);
342 SBVAL(trans->out.data.data, 0, fsinfo->full_size_information.out.total_alloc_units);
343 SBVAL(trans->out.data.data, 8, fsinfo->full_size_information.out.call_avail_alloc_units);
344 SBVAL(trans->out.data.data, 16, fsinfo->full_size_information.out.actual_avail_alloc_units);
345 SIVAL(trans->out.data.data, 24, fsinfo->full_size_information.out.sectors_per_unit);
346 SIVAL(trans->out.data.data, 28, fsinfo->full_size_information.out.bytes_per_sector);
348 return NT_STATUS_OK;
350 case SMB_QFS_OBJECTID_INFORMATION:
351 trans2_setup_reply(trans, 0, 64, 0);
353 status = ndr_push_struct_blob(&guid_blob, req,
354 &fsinfo->objectid_information.out.guid,
355 (ndr_push_flags_fn_t)ndr_push_GUID);
356 if (!NT_STATUS_IS_OK(status)) {
357 return status;
360 memcpy(trans->out.data.data, guid_blob.data, guid_blob.length);
362 for (i=0;i<6;i++) {
363 SBVAL(trans->out.data.data, 16 + 8*i, fsinfo->objectid_information.out.unknown[i]);
365 return NT_STATUS_OK;
368 return NT_STATUS_INVALID_LEVEL;
372 trans2 qfsinfo implementation
374 static NTSTATUS trans2_qfsinfo(struct smbsrv_request *req, struct trans_op *op)
376 struct smb_trans2 *trans = op->trans;
377 union smb_fsinfo *fsinfo;
378 uint16_t level;
380 /* make sure we got enough parameters */
381 if (trans->in.params.length != 2) {
382 return NT_STATUS_FOOBAR;
385 fsinfo = talloc(op, union smb_fsinfo);
386 NT_STATUS_HAVE_NO_MEMORY(fsinfo);
388 op->op_info = fsinfo;
389 op->send_fn = trans2_qfsinfo_send;
391 level = SVAL(trans->in.params.data, 0);
393 switch (level) {
394 case SMB_QFS_ALLOCATION:
395 fsinfo->allocation.level = RAW_QFS_ALLOCATION;
396 return ntvfs_fsinfo(req->ntvfs, fsinfo);
398 case SMB_QFS_VOLUME:
399 fsinfo->volume.level = RAW_QFS_VOLUME;
400 return ntvfs_fsinfo(req->ntvfs, fsinfo);
402 case SMB_QFS_VOLUME_INFO:
403 case SMB_QFS_VOLUME_INFORMATION:
404 fsinfo->volume_info.level = RAW_QFS_VOLUME_INFO;
405 return ntvfs_fsinfo(req->ntvfs, fsinfo);
407 case SMB_QFS_SIZE_INFO:
408 case SMB_QFS_SIZE_INFORMATION:
409 fsinfo->size_info.level = RAW_QFS_SIZE_INFO;
410 return ntvfs_fsinfo(req->ntvfs, fsinfo);
412 case SMB_QFS_DEVICE_INFO:
413 case SMB_QFS_DEVICE_INFORMATION:
414 fsinfo->device_info.level = RAW_QFS_DEVICE_INFO;
415 return ntvfs_fsinfo(req->ntvfs, fsinfo);
417 case SMB_QFS_ATTRIBUTE_INFO:
418 case SMB_QFS_ATTRIBUTE_INFORMATION:
419 fsinfo->attribute_info.level = RAW_QFS_ATTRIBUTE_INFO;
420 return ntvfs_fsinfo(req->ntvfs, fsinfo);
422 case SMB_QFS_QUOTA_INFORMATION:
423 fsinfo->quota_information.level = RAW_QFS_QUOTA_INFORMATION;
424 return ntvfs_fsinfo(req->ntvfs, fsinfo);
426 case SMB_QFS_FULL_SIZE_INFORMATION:
427 fsinfo->full_size_information.level = RAW_QFS_FULL_SIZE_INFORMATION;
428 return ntvfs_fsinfo(req->ntvfs, fsinfo);
430 case SMB_QFS_OBJECTID_INFORMATION:
431 fsinfo->objectid_information.level = RAW_QFS_OBJECTID_INFORMATION;
432 return ntvfs_fsinfo(req->ntvfs, fsinfo);
435 return NT_STATUS_INVALID_LEVEL;
440 trans2 open implementation send
442 static NTSTATUS trans2_open_send(struct trans_op *op)
444 struct smbsrv_request *req = op->req;
445 struct smb_trans2 *trans = op->trans;
446 union smb_open *io;
448 TRANS2_CHECK_ASYNC_STATUS(io, union smb_open);
450 trans2_setup_reply(trans, 30, 0, 0);
452 smbsrv_push_fnum(trans->out.params.data, VWV(0), io->t2open.out.file.ntvfs);
453 SSVAL(trans->out.params.data, VWV(1), io->t2open.out.attrib);
454 srv_push_dos_date3(req->smb_conn, trans->out.params.data,
455 VWV(2), io->t2open.out.write_time);
456 SIVAL(trans->out.params.data, VWV(4), io->t2open.out.size);
457 SSVAL(trans->out.params.data, VWV(6), io->t2open.out.access);
458 SSVAL(trans->out.params.data, VWV(7), io->t2open.out.ftype);
459 SSVAL(trans->out.params.data, VWV(8), io->t2open.out.devstate);
460 SSVAL(trans->out.params.data, VWV(9), io->t2open.out.action);
461 SIVAL(trans->out.params.data, VWV(10), 0); /* reserved */
462 SSVAL(trans->out.params.data, VWV(12), 0); /* EaErrorOffset */
463 SIVAL(trans->out.params.data, VWV(13), 0); /* EaLength */
465 return NT_STATUS_OK;
469 trans2 open implementation
471 static NTSTATUS trans2_open(struct smbsrv_request *req, struct trans_op *op)
473 struct smb_trans2 *trans = op->trans;
474 union smb_open *io;
475 NTSTATUS status;
477 /* make sure we got enough parameters */
478 if (trans->in.params.length < 29) {
479 return NT_STATUS_FOOBAR;
482 io = talloc(op, union smb_open);
483 NT_STATUS_HAVE_NO_MEMORY(io);
485 io->t2open.level = RAW_OPEN_T2OPEN;
486 io->t2open.in.flags = SVAL(trans->in.params.data, VWV(0));
487 io->t2open.in.open_mode = SVAL(trans->in.params.data, VWV(1));
488 io->t2open.in.search_attrs = SVAL(trans->in.params.data, VWV(2));
489 io->t2open.in.file_attrs = SVAL(trans->in.params.data, VWV(3));
490 io->t2open.in.write_time = srv_pull_dos_date(req->smb_conn,
491 trans->in.params.data + VWV(4));;
492 io->t2open.in.open_func = SVAL(trans->in.params.data, VWV(6));
493 io->t2open.in.size = IVAL(trans->in.params.data, VWV(7));
494 io->t2open.in.timeout = IVAL(trans->in.params.data, VWV(9));
495 io->t2open.in.num_eas = 0;
496 io->t2open.in.eas = NULL;
498 trans2_pull_blob_string(req, &trans->in.params, 28, &io->t2open.in.fname, 0);
500 status = ea_pull_list(&trans->in.data, io, &io->t2open.in.num_eas, &io->t2open.in.eas);
501 NT_STATUS_NOT_OK_RETURN(status);
503 op->op_info = io;
504 op->send_fn = trans2_open_send;
506 return ntvfs_open(req->ntvfs, io);
511 trans2 simple send
513 static NTSTATUS trans2_simple_send(struct trans_op *op)
515 struct smbsrv_request *req = op->req;
516 struct smb_trans2 *trans = op->trans;
518 TRANS2_CHECK_ASYNC_STATUS_SIMPLE;
520 trans2_setup_reply(trans, 2, 0, 0);
522 SSVAL(trans->out.params.data, VWV(0), 0);
524 return NT_STATUS_OK;
528 trans2 mkdir implementation
530 static NTSTATUS trans2_mkdir(struct smbsrv_request *req, struct trans_op *op)
532 struct smb_trans2 *trans = op->trans;
533 union smb_mkdir *io;
534 NTSTATUS status;
536 /* make sure we got enough parameters */
537 if (trans->in.params.length < 5) {
538 return NT_STATUS_FOOBAR;
541 io = talloc(op, union smb_mkdir);
542 NT_STATUS_HAVE_NO_MEMORY(io);
544 io->t2mkdir.level = RAW_MKDIR_T2MKDIR;
545 trans2_pull_blob_string(req, &trans->in.params, 4, &io->t2mkdir.in.path, 0);
547 status = ea_pull_list(&trans->in.data, io,
548 &io->t2mkdir.in.num_eas,
549 &io->t2mkdir.in.eas);
550 NT_STATUS_NOT_OK_RETURN(status);
552 op->op_info = io;
553 op->send_fn = trans2_simple_send;
555 return ntvfs_mkdir(req->ntvfs, io);
558 static NTSTATUS trans2_push_fileinfo(struct smbsrv_request *req,
559 union smb_fileinfo *st,
560 TALLOC_CTX *mem_ctx,
561 DATA_BLOB *blob)
563 uint_t i;
564 uint32_t list_size;
566 switch (st->generic.level) {
567 case RAW_FILEINFO_GENERIC:
568 case RAW_FILEINFO_GETATTR:
569 case RAW_FILEINFO_GETATTRE:
570 case RAW_FILEINFO_SEC_DESC:
571 /* handled elsewhere */
572 return NT_STATUS_INVALID_LEVEL;
574 case RAW_FILEINFO_BASIC_INFO:
575 case RAW_FILEINFO_BASIC_INFORMATION:
576 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 40));
578 push_nttime(blob->data, 0, st->basic_info.out.create_time);
579 push_nttime(blob->data, 8, st->basic_info.out.access_time);
580 push_nttime(blob->data, 16, st->basic_info.out.write_time);
581 push_nttime(blob->data, 24, st->basic_info.out.change_time);
582 SIVAL(blob->data, 32, st->basic_info.out.attrib);
583 SIVAL(blob->data, 36, 0); /* padding */
584 return NT_STATUS_OK;
586 case RAW_FILEINFO_STANDARD:
587 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 22));
589 srv_push_dos_date2(req->smb_conn, blob->data, 0, st->standard.out.create_time);
590 srv_push_dos_date2(req->smb_conn, blob->data, 4, st->standard.out.access_time);
591 srv_push_dos_date2(req->smb_conn, blob->data, 8, st->standard.out.write_time);
592 SIVAL(blob->data, 12, st->standard.out.size);
593 SIVAL(blob->data, 16, st->standard.out.alloc_size);
594 SSVAL(blob->data, 20, st->standard.out.attrib);
595 return NT_STATUS_OK;
597 case RAW_FILEINFO_EA_SIZE:
598 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 26));
600 srv_push_dos_date2(req->smb_conn, blob->data, 0, st->ea_size.out.create_time);
601 srv_push_dos_date2(req->smb_conn, blob->data, 4, st->ea_size.out.access_time);
602 srv_push_dos_date2(req->smb_conn, blob->data, 8, st->ea_size.out.write_time);
603 SIVAL(blob->data, 12, st->ea_size.out.size);
604 SIVAL(blob->data, 16, st->ea_size.out.alloc_size);
605 SSVAL(blob->data, 20, st->ea_size.out.attrib);
606 SIVAL(blob->data, 22, st->ea_size.out.ea_size);
607 return NT_STATUS_OK;
609 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
610 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 56));
612 push_nttime(blob->data, 0, st->network_open_information.out.create_time);
613 push_nttime(blob->data, 8, st->network_open_information.out.access_time);
614 push_nttime(blob->data, 16, st->network_open_information.out.write_time);
615 push_nttime(blob->data, 24, st->network_open_information.out.change_time);
616 SBVAL(blob->data, 32, st->network_open_information.out.alloc_size);
617 SBVAL(blob->data, 40, st->network_open_information.out.size);
618 SIVAL(blob->data, 48, st->network_open_information.out.attrib);
619 SIVAL(blob->data, 52, 0); /* padding */
620 return NT_STATUS_OK;
622 case RAW_FILEINFO_STANDARD_INFO:
623 case RAW_FILEINFO_STANDARD_INFORMATION:
624 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 24));
626 SBVAL(blob->data, 0, st->standard_info.out.alloc_size);
627 SBVAL(blob->data, 8, st->standard_info.out.size);
628 SIVAL(blob->data, 16, st->standard_info.out.nlink);
629 SCVAL(blob->data, 20, st->standard_info.out.delete_pending);
630 SCVAL(blob->data, 21, st->standard_info.out.directory);
631 SSVAL(blob->data, 22, 0); /* padding */
632 return NT_STATUS_OK;
634 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
635 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 8));
637 SIVAL(blob->data, 0, st->attribute_tag_information.out.attrib);
638 SIVAL(blob->data, 4, st->attribute_tag_information.out.reparse_tag);
639 return NT_STATUS_OK;
641 case RAW_FILEINFO_EA_INFO:
642 case RAW_FILEINFO_EA_INFORMATION:
643 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 4));
645 SIVAL(blob->data, 0, st->ea_info.out.ea_size);
646 return NT_STATUS_OK;
648 case RAW_FILEINFO_MODE_INFORMATION:
649 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 4));
651 SIVAL(blob->data, 0, st->mode_information.out.mode);
652 return NT_STATUS_OK;
654 case RAW_FILEINFO_ALIGNMENT_INFORMATION:
655 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 4));
657 SIVAL(blob->data, 0,
658 st->alignment_information.out.alignment_requirement);
659 return NT_STATUS_OK;
661 case RAW_FILEINFO_EA_LIST:
662 list_size = ea_list_size(st->ea_list.out.num_eas,
663 st->ea_list.out.eas);
664 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, list_size));
666 ea_put_list(blob->data,
667 st->ea_list.out.num_eas, st->ea_list.out.eas);
668 return NT_STATUS_OK;
670 case RAW_FILEINFO_ALL_EAS:
671 list_size = ea_list_size(st->all_eas.out.num_eas,
672 st->all_eas.out.eas);
673 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, list_size));
675 ea_put_list(blob->data,
676 st->all_eas.out.num_eas, st->all_eas.out.eas);
677 return NT_STATUS_OK;
679 case RAW_FILEINFO_ACCESS_INFORMATION:
680 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 4));
682 SIVAL(blob->data, 0, st->access_information.out.access_flags);
683 return NT_STATUS_OK;
685 case RAW_FILEINFO_POSITION_INFORMATION:
686 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 8));
688 SBVAL(blob->data, 0, st->position_information.out.position);
689 return NT_STATUS_OK;
691 case RAW_FILEINFO_COMPRESSION_INFO:
692 case RAW_FILEINFO_COMPRESSION_INFORMATION:
693 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 16));
695 SBVAL(blob->data, 0, st->compression_info.out.compressed_size);
696 SSVAL(blob->data, 8, st->compression_info.out.format);
697 SCVAL(blob->data, 10, st->compression_info.out.unit_shift);
698 SCVAL(blob->data, 11, st->compression_info.out.chunk_shift);
699 SCVAL(blob->data, 12, st->compression_info.out.cluster_shift);
700 SSVAL(blob->data, 13, 0); /* 3 bytes padding */
701 SCVAL(blob->data, 15, 0);
702 return NT_STATUS_OK;
704 case RAW_FILEINFO_IS_NAME_VALID:
705 return NT_STATUS_OK;
707 case RAW_FILEINFO_INTERNAL_INFORMATION:
708 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 8));
710 SBVAL(blob->data, 0, st->internal_information.out.file_id);
711 return NT_STATUS_OK;
713 case RAW_FILEINFO_ALL_INFO:
714 case RAW_FILEINFO_ALL_INFORMATION:
715 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 72));
717 push_nttime(blob->data, 0, st->all_info.out.create_time);
718 push_nttime(blob->data, 8, st->all_info.out.access_time);
719 push_nttime(blob->data, 16, st->all_info.out.write_time);
720 push_nttime(blob->data, 24, st->all_info.out.change_time);
721 SIVAL(blob->data, 32, st->all_info.out.attrib);
722 SIVAL(blob->data, 36, 0);
723 SBVAL(blob->data, 40, st->all_info.out.alloc_size);
724 SBVAL(blob->data, 48, st->all_info.out.size);
725 SIVAL(blob->data, 56, st->all_info.out.nlink);
726 SCVAL(blob->data, 60, st->all_info.out.delete_pending);
727 SCVAL(blob->data, 61, st->all_info.out.directory);
728 SSVAL(blob->data, 62, 0); /* padding */
729 SIVAL(blob->data, 64, st->all_info.out.ea_size);
730 TRANS2_CHECK(trans2_append_data_string(req, mem_ctx, blob,
731 &st->all_info.out.fname,
732 68, STR_UNICODE));
733 return NT_STATUS_OK;
735 case RAW_FILEINFO_NAME_INFO:
736 case RAW_FILEINFO_NAME_INFORMATION:
737 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 4));
739 TRANS2_CHECK(trans2_append_data_string(req, mem_ctx, blob,
740 &st->name_info.out.fname,
741 0, STR_UNICODE));
742 return NT_STATUS_OK;
744 case RAW_FILEINFO_ALT_NAME_INFO:
745 case RAW_FILEINFO_ALT_NAME_INFORMATION:
746 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 4));
748 TRANS2_CHECK(trans2_append_data_string(req, mem_ctx, blob,
749 &st->alt_name_info.out.fname,
750 0, STR_UNICODE));
751 return NT_STATUS_OK;
753 case RAW_FILEINFO_STREAM_INFO:
754 case RAW_FILEINFO_STREAM_INFORMATION:
755 for (i=0;i<st->stream_info.out.num_streams;i++) {
756 uint32_t data_size = blob->length;
757 uint8_t *data;
759 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, data_size + 24));
760 data = blob->data + data_size;
761 SBVAL(data, 8, st->stream_info.out.streams[i].size);
762 SBVAL(data, 16, st->stream_info.out.streams[i].alloc_size);
763 TRANS2_CHECK(trans2_append_data_string(req, mem_ctx, blob,
764 &st->stream_info.out.streams[i].stream_name,
765 data_size + 4, STR_UNICODE));
766 if (i == st->stream_info.out.num_streams - 1) {
767 SIVAL(blob->data, data_size, 0);
768 } else {
769 TRANS2_CHECK(trans2_grow_data_fill(mem_ctx, blob, (blob->length+7)&~7));
770 SIVAL(blob->data, data_size,
771 blob->length - data_size);
774 return NT_STATUS_OK;
776 case RAW_FILEINFO_UNIX_BASIC:
777 case RAW_FILEINFO_UNIX_LINK:
778 return NT_STATUS_INVALID_LEVEL;
780 case RAW_FILEINFO_SMB2_ALL_EAS:
781 case RAW_FILEINFO_SMB2_ALL_INFORMATION:
782 return NT_STATUS_INVALID_LEVEL;
785 return NT_STATUS_INVALID_LEVEL;
789 fill in the reply from a qpathinfo or qfileinfo call
791 static NTSTATUS trans2_fileinfo_send(struct trans_op *op)
793 struct smbsrv_request *req = op->req;
794 struct smb_trans2 *trans = op->trans;
795 union smb_fileinfo *st;
797 TRANS2_CHECK_ASYNC_STATUS(st, union smb_fileinfo);
799 TRANS2_CHECK(trans2_setup_reply(trans, 2, 0, 0));
800 SSVAL(trans->out.params.data, 0, 0);
802 TRANS2_CHECK(trans2_push_fileinfo(req, st, trans, &trans->out.data));
804 return NT_STATUS_OK;
808 trans2 qpathinfo implementation
810 static NTSTATUS trans2_qpathinfo(struct smbsrv_request *req, struct trans_op *op)
812 struct smb_trans2 *trans = op->trans;
813 union smb_fileinfo *st;
814 NTSTATUS status;
815 uint16_t level;
817 /* make sure we got enough parameters */
818 if (trans->in.params.length < 2) {
819 return NT_STATUS_FOOBAR;
822 st = talloc(op, union smb_fileinfo);
823 NT_STATUS_HAVE_NO_MEMORY(st);
825 level = SVAL(trans->in.params.data, 0);
827 trans2_pull_blob_string(req, &trans->in.params, 6, &st->generic.in.file.path, 0);
828 if (st->generic.in.file.path == NULL) {
829 return NT_STATUS_FOOBAR;
832 /* work out the backend level - we make it 1-1 in the header */
833 st->generic.level = (enum smb_fileinfo_level)level;
834 if (st->generic.level >= RAW_FILEINFO_GENERIC) {
835 return NT_STATUS_INVALID_LEVEL;
838 if (st->generic.level == RAW_FILEINFO_EA_LIST) {
839 status = ea_pull_name_list(&trans->in.data, req,
840 &st->ea_list.in.num_names,
841 &st->ea_list.in.ea_names);
842 NT_STATUS_NOT_OK_RETURN(status);
845 op->op_info = st;
846 op->send_fn = trans2_fileinfo_send;
848 return ntvfs_qpathinfo(req->ntvfs, st);
853 trans2 qpathinfo implementation
855 static NTSTATUS trans2_qfileinfo(struct smbsrv_request *req, struct trans_op *op)
857 struct smb_trans2 *trans = op->trans;
858 union smb_fileinfo *st;
859 NTSTATUS status;
860 uint16_t level;
861 struct ntvfs_handle *h;
863 /* make sure we got enough parameters */
864 if (trans->in.params.length < 4) {
865 return NT_STATUS_FOOBAR;
868 st = talloc(op, union smb_fileinfo);
869 NT_STATUS_HAVE_NO_MEMORY(st);
871 h = smbsrv_pull_fnum(req, trans->in.params.data, 0);
872 level = SVAL(trans->in.params.data, 2);
874 st->generic.in.file.ntvfs = h;
875 /* work out the backend level - we make it 1-1 in the header */
876 st->generic.level = (enum smb_fileinfo_level)level;
877 if (st->generic.level >= RAW_FILEINFO_GENERIC) {
878 return NT_STATUS_INVALID_LEVEL;
881 if (st->generic.level == RAW_FILEINFO_EA_LIST) {
882 status = ea_pull_name_list(&trans->in.data, req,
883 &st->ea_list.in.num_names,
884 &st->ea_list.in.ea_names);
885 NT_STATUS_NOT_OK_RETURN(status);
888 op->op_info = st;
889 op->send_fn = trans2_fileinfo_send;
891 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st->generic.in.file.ntvfs);
892 return ntvfs_qfileinfo(req->ntvfs, st);
897 parse a trans2 setfileinfo/setpathinfo data blob
899 static NTSTATUS trans2_parse_sfileinfo(struct smbsrv_request *req,
900 union smb_setfileinfo *st,
901 const DATA_BLOB *blob)
903 uint32_t len;
905 switch (st->generic.level) {
906 case RAW_SFILEINFO_GENERIC:
907 case RAW_SFILEINFO_SETATTR:
908 case RAW_SFILEINFO_SETATTRE:
909 case RAW_SFILEINFO_SEC_DESC:
910 /* handled elsewhere */
911 return NT_STATUS_INVALID_LEVEL;
913 case RAW_SFILEINFO_STANDARD:
914 CHECK_MIN_BLOB_SIZE(blob, 12);
915 st->standard.in.create_time = srv_pull_dos_date2(req->smb_conn, blob->data + 0);
916 st->standard.in.access_time = srv_pull_dos_date2(req->smb_conn, blob->data + 4);
917 st->standard.in.write_time = srv_pull_dos_date2(req->smb_conn, blob->data + 8);
918 return NT_STATUS_OK;
920 case RAW_SFILEINFO_EA_SET:
921 return ea_pull_list(blob, req,
922 &st->ea_set.in.num_eas,
923 &st->ea_set.in.eas);
925 case SMB_SFILEINFO_BASIC_INFO:
926 case SMB_SFILEINFO_BASIC_INFORMATION:
927 CHECK_MIN_BLOB_SIZE(blob, 36);
928 st->basic_info.in.create_time = pull_nttime(blob->data, 0);
929 st->basic_info.in.access_time = pull_nttime(blob->data, 8);
930 st->basic_info.in.write_time = pull_nttime(blob->data, 16);
931 st->basic_info.in.change_time = pull_nttime(blob->data, 24);
932 st->basic_info.in.attrib = IVAL(blob->data, 32);
933 return NT_STATUS_OK;
935 case SMB_SFILEINFO_DISPOSITION_INFO:
936 case SMB_SFILEINFO_DISPOSITION_INFORMATION:
937 CHECK_MIN_BLOB_SIZE(blob, 1);
938 st->disposition_info.in.delete_on_close = CVAL(blob->data, 0);
939 return NT_STATUS_OK;
941 case SMB_SFILEINFO_ALLOCATION_INFO:
942 case SMB_SFILEINFO_ALLOCATION_INFORMATION:
943 CHECK_MIN_BLOB_SIZE(blob, 8);
944 st->allocation_info.in.alloc_size = BVAL(blob->data, 0);
945 return NT_STATUS_OK;
947 case RAW_SFILEINFO_END_OF_FILE_INFO:
948 case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
949 CHECK_MIN_BLOB_SIZE(blob, 8);
950 st->end_of_file_info.in.size = BVAL(blob->data, 0);
951 return NT_STATUS_OK;
953 case RAW_SFILEINFO_RENAME_INFORMATION: {
954 DATA_BLOB blob2;
956 CHECK_MIN_BLOB_SIZE(blob, 12);
957 st->rename_information.in.overwrite = CVAL(blob->data, 0);
958 st->rename_information.in.root_fid = IVAL(blob->data, 4);
959 len = IVAL(blob->data, 8);
960 blob2.data = blob->data+12;
961 blob2.length = MIN(blob->length, len);
962 trans2_pull_blob_string(req, &blob2, 0,
963 &st->rename_information.in.new_name, STR_UNICODE);
964 return NT_STATUS_OK;
967 case RAW_SFILEINFO_POSITION_INFORMATION:
968 CHECK_MIN_BLOB_SIZE(blob, 8);
969 st->position_information.in.position = BVAL(blob->data, 0);
970 return NT_STATUS_OK;
972 case RAW_SFILEINFO_MODE_INFORMATION:
973 CHECK_MIN_BLOB_SIZE(blob, 4);
974 st->mode_information.in.mode = IVAL(blob->data, 0);
975 return NT_STATUS_OK;
977 case RAW_SFILEINFO_UNIX_BASIC:
978 case RAW_SFILEINFO_UNIX_LINK:
979 case RAW_SFILEINFO_UNIX_HLINK:
980 case RAW_SFILEINFO_1023:
981 case RAW_SFILEINFO_1025:
982 case RAW_SFILEINFO_1029:
983 case RAW_SFILEINFO_1032:
984 case RAW_SFILEINFO_1039:
985 case RAW_SFILEINFO_1040:
986 return NT_STATUS_INVALID_LEVEL;
989 return NT_STATUS_INVALID_LEVEL;
993 trans2 setfileinfo implementation
995 static NTSTATUS trans2_setfileinfo(struct smbsrv_request *req, struct trans_op *op)
997 struct smb_trans2 *trans = op->trans;
998 union smb_setfileinfo *st;
999 NTSTATUS status;
1000 uint16_t level;
1001 struct ntvfs_handle *h;
1003 /* make sure we got enough parameters */
1004 if (trans->in.params.length < 4) {
1005 return NT_STATUS_FOOBAR;
1008 st = talloc(op, union smb_setfileinfo);
1009 NT_STATUS_HAVE_NO_MEMORY(st);
1011 h = smbsrv_pull_fnum(req, trans->in.params.data, 0);
1012 level = SVAL(trans->in.params.data, 2);
1014 st->generic.in.file.ntvfs = h;
1015 /* work out the backend level - we make it 1-1 in the header */
1016 st->generic.level = (enum smb_setfileinfo_level)level;
1017 if (st->generic.level >= RAW_SFILEINFO_GENERIC) {
1018 return NT_STATUS_INVALID_LEVEL;
1021 status = trans2_parse_sfileinfo(req, st, &trans->in.data);
1022 NT_STATUS_NOT_OK_RETURN(status);
1024 op->op_info = st;
1025 op->send_fn = trans2_simple_send;
1027 SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st->generic.in.file.ntvfs);
1028 return ntvfs_setfileinfo(req->ntvfs, st);
1032 trans2 setpathinfo implementation
1034 static NTSTATUS trans2_setpathinfo(struct smbsrv_request *req, struct trans_op *op)
1036 struct smb_trans2 *trans = op->trans;
1037 union smb_setfileinfo *st;
1038 NTSTATUS status;
1039 uint16_t level;
1041 /* make sure we got enough parameters */
1042 if (trans->in.params.length < 4) {
1043 return NT_STATUS_FOOBAR;
1046 st = talloc(op, union smb_setfileinfo);
1047 NT_STATUS_HAVE_NO_MEMORY(st);
1049 level = SVAL(trans->in.params.data, 0);
1051 trans2_pull_blob_string(req, &trans->in.params, 6, &st->generic.in.file.path, 0);
1052 if (st->generic.in.file.path == NULL) {
1053 return NT_STATUS_FOOBAR;
1056 /* work out the backend level - we make it 1-1 in the header */
1057 st->generic.level = (enum smb_setfileinfo_level)level;
1058 if (st->generic.level >= RAW_SFILEINFO_GENERIC) {
1059 return NT_STATUS_INVALID_LEVEL;
1062 status = trans2_parse_sfileinfo(req, st, &trans->in.data);
1063 NT_STATUS_NOT_OK_RETURN(status);
1065 op->op_info = st;
1066 op->send_fn = trans2_simple_send;
1068 return ntvfs_setpathinfo(req->ntvfs, st);
1072 /* a structure to encapsulate the state information about an in-progress ffirst/fnext operation */
1073 struct find_state {
1074 struct trans_op *op;
1075 void *search;
1076 enum smb_search_level level;
1077 uint16_t last_entry_offset;
1078 uint16_t flags;
1082 fill a single entry in a trans2 find reply
1084 static BOOL find_fill_info(struct find_state *state,
1085 union smb_search_data *file)
1087 struct smbsrv_request *req = state->op->req;
1088 struct smb_trans2 *trans = state->op->trans;
1089 uint8_t *data;
1090 uint_t ofs = trans->out.data.length;
1091 uint32_t ea_size;
1093 switch (state->level) {
1094 case RAW_SEARCH_SEARCH:
1095 case RAW_SEARCH_FFIRST:
1096 case RAW_SEARCH_FUNIQUE:
1097 case RAW_SEARCH_GENERIC:
1098 case RAW_SEARCH_SMB2:
1099 /* handled elsewhere */
1100 return False;
1102 case RAW_SEARCH_STANDARD:
1103 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
1104 trans2_grow_data(trans, &trans->out.data, ofs + 27);
1105 SIVAL(trans->out.data.data, ofs, file->standard.resume_key);
1106 ofs += 4;
1107 } else {
1108 trans2_grow_data(trans, &trans->out.data, ofs + 23);
1110 data = trans->out.data.data + ofs;
1111 srv_push_dos_date2(req->smb_conn, data, 0, file->standard.create_time);
1112 srv_push_dos_date2(req->smb_conn, data, 4, file->standard.access_time);
1113 srv_push_dos_date2(req->smb_conn, data, 8, file->standard.write_time);
1114 SIVAL(data, 12, file->standard.size);
1115 SIVAL(data, 16, file->standard.alloc_size);
1116 SSVAL(data, 20, file->standard.attrib);
1117 trans2_append_data_string(req, trans, &trans->out.data, &file->standard.name,
1118 ofs + 22, STR_LEN8BIT | STR_TERMINATE | STR_LEN_NOTERM);
1119 break;
1121 case RAW_SEARCH_EA_SIZE:
1122 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
1123 trans2_grow_data(trans, &trans->out.data, ofs + 31);
1124 SIVAL(trans->out.data.data, ofs, file->ea_size.resume_key);
1125 ofs += 4;
1126 } else {
1127 trans2_grow_data(trans, &trans->out.data, ofs + 27);
1129 data = trans->out.data.data + ofs;
1130 srv_push_dos_date2(req->smb_conn, data, 0, file->ea_size.create_time);
1131 srv_push_dos_date2(req->smb_conn, data, 4, file->ea_size.access_time);
1132 srv_push_dos_date2(req->smb_conn, data, 8, file->ea_size.write_time);
1133 SIVAL(data, 12, file->ea_size.size);
1134 SIVAL(data, 16, file->ea_size.alloc_size);
1135 SSVAL(data, 20, file->ea_size.attrib);
1136 SIVAL(data, 22, file->ea_size.ea_size);
1137 trans2_append_data_string(req, trans, &trans->out.data, &file->ea_size.name,
1138 ofs + 26, STR_LEN8BIT | STR_NOALIGN);
1139 trans2_grow_data(trans, &trans->out.data, trans->out.data.length + 1);
1140 trans->out.data.data[trans->out.data.length-1] = 0;
1141 break;
1143 case RAW_SEARCH_EA_LIST:
1144 ea_size = ea_list_size(file->ea_list.eas.num_eas, file->ea_list.eas.eas);
1145 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
1146 if (!NT_STATUS_IS_OK(trans2_grow_data(trans, &trans->out.data, ofs + 27 + ea_size))) {
1147 return False;
1149 SIVAL(trans->out.data.data, ofs, file->ea_list.resume_key);
1150 ofs += 4;
1151 } else {
1152 if (!NT_STATUS_IS_OK(trans2_grow_data(trans, &trans->out.data, ofs + 23 + ea_size))) {
1153 return False;
1156 data = trans->out.data.data + ofs;
1157 srv_push_dos_date2(req->smb_conn, data, 0, file->ea_list.create_time);
1158 srv_push_dos_date2(req->smb_conn, data, 4, file->ea_list.access_time);
1159 srv_push_dos_date2(req->smb_conn, data, 8, file->ea_list.write_time);
1160 SIVAL(data, 12, file->ea_list.size);
1161 SIVAL(data, 16, file->ea_list.alloc_size);
1162 SSVAL(data, 20, file->ea_list.attrib);
1163 ea_put_list(data+22, file->ea_list.eas.num_eas, file->ea_list.eas.eas);
1164 trans2_append_data_string(req, trans, &trans->out.data, &file->ea_list.name,
1165 ofs + 22 + ea_size, STR_LEN8BIT | STR_NOALIGN);
1166 trans2_grow_data(trans, &trans->out.data, trans->out.data.length + 1);
1167 trans->out.data.data[trans->out.data.length-1] = 0;
1168 break;
1170 case RAW_SEARCH_DIRECTORY_INFO:
1171 trans2_grow_data(trans, &trans->out.data, ofs + 64);
1172 data = trans->out.data.data + ofs;
1173 SIVAL(data, 4, file->directory_info.file_index);
1174 push_nttime(data, 8, file->directory_info.create_time);
1175 push_nttime(data, 16, file->directory_info.access_time);
1176 push_nttime(data, 24, file->directory_info.write_time);
1177 push_nttime(data, 32, file->directory_info.change_time);
1178 SBVAL(data, 40, file->directory_info.size);
1179 SBVAL(data, 48, file->directory_info.alloc_size);
1180 SIVAL(data, 56, file->directory_info.attrib);
1181 trans2_append_data_string(req, trans, &trans->out.data, &file->directory_info.name,
1182 ofs + 60, STR_TERMINATE_ASCII);
1183 data = trans->out.data.data + ofs;
1184 SIVAL(data, 0, trans->out.data.length - ofs);
1185 break;
1187 case RAW_SEARCH_FULL_DIRECTORY_INFO:
1188 trans2_grow_data(trans, &trans->out.data, ofs + 68);
1189 data = trans->out.data.data + ofs;
1190 SIVAL(data, 4, file->full_directory_info.file_index);
1191 push_nttime(data, 8, file->full_directory_info.create_time);
1192 push_nttime(data, 16, file->full_directory_info.access_time);
1193 push_nttime(data, 24, file->full_directory_info.write_time);
1194 push_nttime(data, 32, file->full_directory_info.change_time);
1195 SBVAL(data, 40, file->full_directory_info.size);
1196 SBVAL(data, 48, file->full_directory_info.alloc_size);
1197 SIVAL(data, 56, file->full_directory_info.attrib);
1198 SIVAL(data, 64, file->full_directory_info.ea_size);
1199 trans2_append_data_string(req, trans, &trans->out.data, &file->full_directory_info.name,
1200 ofs + 60, STR_TERMINATE_ASCII);
1201 data = trans->out.data.data + ofs;
1202 SIVAL(data, 0, trans->out.data.length - ofs);
1203 break;
1205 case RAW_SEARCH_NAME_INFO:
1206 trans2_grow_data(trans, &trans->out.data, ofs + 12);
1207 data = trans->out.data.data + ofs;
1208 SIVAL(data, 4, file->name_info.file_index);
1209 trans2_append_data_string(req, trans, &trans->out.data, &file->name_info.name,
1210 ofs + 8, STR_TERMINATE_ASCII);
1211 data = trans->out.data.data + ofs;
1212 SIVAL(data, 0, trans->out.data.length - ofs);
1213 break;
1215 case RAW_SEARCH_BOTH_DIRECTORY_INFO:
1216 trans2_grow_data(trans, &trans->out.data, ofs + 94);
1217 data = trans->out.data.data + ofs;
1218 SIVAL(data, 4, file->both_directory_info.file_index);
1219 push_nttime(data, 8, file->both_directory_info.create_time);
1220 push_nttime(data, 16, file->both_directory_info.access_time);
1221 push_nttime(data, 24, file->both_directory_info.write_time);
1222 push_nttime(data, 32, file->both_directory_info.change_time);
1223 SBVAL(data, 40, file->both_directory_info.size);
1224 SBVAL(data, 48, file->both_directory_info.alloc_size);
1225 SIVAL(data, 56, file->both_directory_info.attrib);
1226 SIVAL(data, 64, file->both_directory_info.ea_size);
1227 SCVAL(data, 69, 0); /* reserved */
1228 memset(data+70,0,24);
1229 trans2_push_data_string(req, trans, &trans->out.data,
1230 68 + ofs, 70 + ofs,
1231 &file->both_directory_info.short_name,
1232 24, STR_UNICODE | STR_LEN8BIT);
1233 trans2_append_data_string(req, trans, &trans->out.data, &file->both_directory_info.name,
1234 ofs + 60, STR_TERMINATE_ASCII);
1235 trans2_align_data(trans);
1236 data = trans->out.data.data + ofs;
1237 SIVAL(data, 0, trans->out.data.length - ofs);
1238 break;
1240 case RAW_SEARCH_ID_FULL_DIRECTORY_INFO:
1241 trans2_grow_data(trans, &trans->out.data, ofs + 80);
1242 data = trans->out.data.data + ofs;
1243 SIVAL(data, 4, file->id_full_directory_info.file_index);
1244 push_nttime(data, 8, file->id_full_directory_info.create_time);
1245 push_nttime(data, 16, file->id_full_directory_info.access_time);
1246 push_nttime(data, 24, file->id_full_directory_info.write_time);
1247 push_nttime(data, 32, file->id_full_directory_info.change_time);
1248 SBVAL(data, 40, file->id_full_directory_info.size);
1249 SBVAL(data, 48, file->id_full_directory_info.alloc_size);
1250 SIVAL(data, 56, file->id_full_directory_info.attrib);
1251 SIVAL(data, 64, file->id_full_directory_info.ea_size);
1252 SIVAL(data, 68, 0); /* padding */
1253 SBVAL(data, 72, file->id_full_directory_info.file_id);
1254 trans2_append_data_string(req, trans, &trans->out.data, &file->id_full_directory_info.name,
1255 ofs + 60, STR_TERMINATE_ASCII);
1256 data = trans->out.data.data + ofs;
1257 SIVAL(data, 0, trans->out.data.length - ofs);
1258 break;
1260 case RAW_SEARCH_ID_BOTH_DIRECTORY_INFO:
1261 trans2_grow_data(trans, &trans->out.data, ofs + 104);
1262 data = trans->out.data.data + ofs;
1263 SIVAL(data, 4, file->id_both_directory_info.file_index);
1264 push_nttime(data, 8, file->id_both_directory_info.create_time);
1265 push_nttime(data, 16, file->id_both_directory_info.access_time);
1266 push_nttime(data, 24, file->id_both_directory_info.write_time);
1267 push_nttime(data, 32, file->id_both_directory_info.change_time);
1268 SBVAL(data, 40, file->id_both_directory_info.size);
1269 SBVAL(data, 48, file->id_both_directory_info.alloc_size);
1270 SIVAL(data, 56, file->id_both_directory_info.attrib);
1271 SIVAL(data, 64, file->id_both_directory_info.ea_size);
1272 SCVAL(data, 69, 0); /* reserved */
1273 memset(data+70,0,26);
1274 trans2_push_data_string(req, trans, &trans->out.data,
1275 68 + ofs, 70 + ofs,
1276 &file->id_both_directory_info.short_name,
1277 24, STR_UNICODE | STR_LEN8BIT);
1278 SBVAL(data, 96, file->id_both_directory_info.file_id);
1279 trans2_append_data_string(req, trans, &trans->out.data, &file->id_both_directory_info.name,
1280 ofs + 60, STR_TERMINATE_ASCII);
1281 data = trans->out.data.data + ofs;
1282 SIVAL(data, 0, trans->out.data.length - ofs);
1283 break;
1286 return True;
1289 /* callback function for trans2 findfirst/findnext */
1290 static BOOL find_callback(void *private, union smb_search_data *file)
1292 struct find_state *state = talloc_get_type(private, struct find_state);
1293 struct smb_trans2 *trans = state->op->trans;
1294 uint_t old_length;
1296 old_length = trans->out.data.length;
1298 if (!find_fill_info(state, file) ||
1299 trans->out.data.length > trans->in.max_data) {
1300 /* restore the old length and tell the backend to stop */
1301 trans2_grow_data(trans, &trans->out.data, old_length);
1302 return False;
1305 state->last_entry_offset = old_length;
1306 return True;
1310 trans2 findfirst send
1312 static NTSTATUS trans2_findfirst_send(struct trans_op *op)
1314 struct smbsrv_request *req = op->req;
1315 struct smb_trans2 *trans = op->trans;
1316 union smb_search_first *search;
1317 struct find_state *state;
1318 uint8_t *param;
1320 TRANS2_CHECK_ASYNC_STATUS(state, struct find_state);
1321 search = talloc_get_type(state->search, union smb_search_first);
1323 /* fill in the findfirst reply header */
1324 param = trans->out.params.data;
1325 SSVAL(param, VWV(0), search->t2ffirst.out.handle);
1326 SSVAL(param, VWV(1), search->t2ffirst.out.count);
1327 SSVAL(param, VWV(2), search->t2ffirst.out.end_of_search);
1328 SSVAL(param, VWV(3), 0);
1329 SSVAL(param, VWV(4), state->last_entry_offset);
1331 return NT_STATUS_OK;
1336 trans2 findfirst implementation
1338 static NTSTATUS trans2_findfirst(struct smbsrv_request *req, struct trans_op *op)
1340 struct smb_trans2 *trans = op->trans;
1341 union smb_search_first *search;
1342 NTSTATUS status;
1343 uint16_t level;
1344 struct find_state *state;
1346 /* make sure we got all the parameters */
1347 if (trans->in.params.length < 14) {
1348 return NT_STATUS_FOOBAR;
1351 search = talloc(op, union smb_search_first);
1352 NT_STATUS_HAVE_NO_MEMORY(search);
1354 search->t2ffirst.in.search_attrib = SVAL(trans->in.params.data, 0);
1355 search->t2ffirst.in.max_count = SVAL(trans->in.params.data, 2);
1356 search->t2ffirst.in.flags = SVAL(trans->in.params.data, 4);
1357 level = SVAL(trans->in.params.data, 6);
1358 search->t2ffirst.in.storage_type = IVAL(trans->in.params.data, 8);
1360 trans2_pull_blob_string(req, &trans->in.params, 12, &search->t2ffirst.in.pattern, 0);
1361 if (search->t2ffirst.in.pattern == NULL) {
1362 return NT_STATUS_FOOBAR;
1365 search->t2ffirst.level = (enum smb_search_level)level;
1366 if (search->t2ffirst.level >= RAW_SEARCH_GENERIC) {
1367 return NT_STATUS_INVALID_LEVEL;
1370 if (search->t2ffirst.level == RAW_SEARCH_EA_LIST) {
1371 status = ea_pull_name_list(&trans->in.data, req,
1372 &search->t2ffirst.in.num_names,
1373 &search->t2ffirst.in.ea_names);
1374 NT_STATUS_NOT_OK_RETURN(status);
1377 /* setup the private state structure that the backend will
1378 give us in the callback */
1379 state = talloc(op, struct find_state);
1380 NT_STATUS_HAVE_NO_MEMORY(state);
1381 state->op = op;
1382 state->search = search;
1383 state->level = search->t2ffirst.level;
1384 state->last_entry_offset= 0;
1385 state->flags = search->t2ffirst.in.flags;
1387 /* setup for just a header in the reply */
1388 trans2_setup_reply(trans, 10, 0, 0);
1390 op->op_info = state;
1391 op->send_fn = trans2_findfirst_send;
1393 return ntvfs_search_first(req->ntvfs, search, state, find_callback);
1398 trans2 findnext send
1400 static NTSTATUS trans2_findnext_send(struct trans_op *op)
1402 struct smbsrv_request *req = op->req;
1403 struct smb_trans2 *trans = op->trans;
1404 union smb_search_next *search;
1405 struct find_state *state;
1406 uint8_t *param;
1408 TRANS2_CHECK_ASYNC_STATUS(state, struct find_state);
1409 search = talloc_get_type(state->search, union smb_search_next);
1411 /* fill in the findfirst reply header */
1412 param = trans->out.params.data;
1413 SSVAL(param, VWV(0), search->t2fnext.out.count);
1414 SSVAL(param, VWV(1), search->t2fnext.out.end_of_search);
1415 SSVAL(param, VWV(2), 0);
1416 SSVAL(param, VWV(3), state->last_entry_offset);
1418 return NT_STATUS_OK;
1423 trans2 findnext implementation
1425 static NTSTATUS trans2_findnext(struct smbsrv_request *req, struct trans_op *op)
1427 struct smb_trans2 *trans = op->trans;
1428 union smb_search_next *search;
1429 NTSTATUS status;
1430 uint16_t level;
1431 struct find_state *state;
1433 /* make sure we got all the parameters */
1434 if (trans->in.params.length < 12) {
1435 return NT_STATUS_FOOBAR;
1438 search = talloc(op, union smb_search_next);
1439 NT_STATUS_HAVE_NO_MEMORY(search);
1441 search->t2fnext.in.handle = SVAL(trans->in.params.data, 0);
1442 search->t2fnext.in.max_count = SVAL(trans->in.params.data, 2);
1443 level = SVAL(trans->in.params.data, 4);
1444 search->t2fnext.in.resume_key = IVAL(trans->in.params.data, 6);
1445 search->t2fnext.in.flags = SVAL(trans->in.params.data, 10);
1447 trans2_pull_blob_string(req, &trans->in.params, 12, &search->t2fnext.in.last_name, 0);
1448 if (search->t2fnext.in.last_name == NULL) {
1449 return NT_STATUS_FOOBAR;
1452 search->t2fnext.level = (enum smb_search_level)level;
1453 if (search->t2fnext.level >= RAW_SEARCH_GENERIC) {
1454 return NT_STATUS_INVALID_LEVEL;
1457 if (search->t2fnext.level == RAW_SEARCH_EA_LIST) {
1458 status = ea_pull_name_list(&trans->in.data, req,
1459 &search->t2fnext.in.num_names,
1460 &search->t2fnext.in.ea_names);
1461 NT_STATUS_NOT_OK_RETURN(status);
1464 /* setup the private state structure that the backend will give us in the callback */
1465 state = talloc(op, struct find_state);
1466 NT_STATUS_HAVE_NO_MEMORY(state);
1467 state->op = op;
1468 state->search = search;
1469 state->level = search->t2fnext.level;
1470 state->last_entry_offset= 0;
1471 state->flags = search->t2fnext.in.flags;
1473 /* setup for just a header in the reply */
1474 trans2_setup_reply(trans, 8, 0, 0);
1476 op->op_info = state;
1477 op->send_fn = trans2_findnext_send;
1479 return ntvfs_search_next(req->ntvfs, search, state, find_callback);
1484 backend for trans2 requests
1486 static NTSTATUS trans2_backend(struct smbsrv_request *req, struct trans_op *op)
1488 struct smb_trans2 *trans = op->trans;
1489 NTSTATUS status;
1491 /* direct trans2 pass thru */
1492 status = ntvfs_trans2(req->ntvfs, trans);
1493 if (!NT_STATUS_EQUAL(NT_STATUS_NOT_IMPLEMENTED, status)) {
1494 return status;
1497 /* must have at least one setup word */
1498 if (trans->in.setup_count < 1) {
1499 return NT_STATUS_FOOBAR;
1502 /* the trans2 command is in setup[0] */
1503 switch (trans->in.setup[0]) {
1504 case TRANSACT2_FINDFIRST:
1505 return trans2_findfirst(req, op);
1506 case TRANSACT2_FINDNEXT:
1507 return trans2_findnext(req, op);
1508 case TRANSACT2_QPATHINFO:
1509 return trans2_qpathinfo(req, op);
1510 case TRANSACT2_QFILEINFO:
1511 return trans2_qfileinfo(req, op);
1512 case TRANSACT2_SETFILEINFO:
1513 return trans2_setfileinfo(req, op);
1514 case TRANSACT2_SETPATHINFO:
1515 return trans2_setpathinfo(req, op);
1516 case TRANSACT2_QFSINFO:
1517 return trans2_qfsinfo(req, op);
1518 case TRANSACT2_OPEN:
1519 return trans2_open(req, op);
1520 case TRANSACT2_MKDIR:
1521 return trans2_mkdir(req, op);
1524 /* an unknown trans2 command */
1525 return NT_STATUS_FOOBAR;
1530 send a continue request
1532 static void reply_trans_continue(struct smbsrv_request *req, uint8_t command,
1533 struct smb_trans2 *trans)
1535 struct smbsrv_trans_partial *tp;
1536 int count;
1538 /* make sure they don't flood us */
1539 for (count=0,tp=req->smb_conn->trans_partial;tp;tp=tp->next) count++;
1540 if (count > 100) {
1541 smbsrv_send_error(req, NT_STATUS_INSUFFICIENT_RESOURCES);
1542 return;
1545 tp = talloc(req, struct smbsrv_trans_partial);
1547 tp->req = talloc_reference(tp, req);
1548 tp->trans = trans;
1549 tp->command = command;
1551 DLIST_ADD(req->smb_conn->trans_partial, tp);
1553 /* send a 'please continue' reply */
1554 smbsrv_setup_reply(req, 0, 0);
1555 smbsrv_send_reply(req);
1560 answer a reconstructed trans request
1562 static void reply_trans_send(struct ntvfs_request *ntvfs)
1564 struct smbsrv_request *req;
1565 struct trans_op *op;
1566 struct smb_trans2 *trans;
1567 uint16_t params_left, data_left;
1568 uint8_t *params, *data;
1569 int i;
1571 SMBSRV_CHECK_ASYNC_STATUS_ERR(op, struct trans_op);
1572 trans = op->trans;
1574 /* if this function needs work to form the nttrans reply buffer, then
1575 call that now */
1576 if (op->send_fn != NULL) {
1577 NTSTATUS status;
1578 status = op->send_fn(op);
1579 if (!NT_STATUS_IS_OK(status)) {
1580 smbsrv_send_error(req, status);
1581 return;
1585 params_left = trans->out.params.length;
1586 data_left = trans->out.data.length;
1587 params = trans->out.params.data;
1588 data = trans->out.data.data;
1590 smbsrv_setup_reply(req, 10 + trans->out.setup_count, 0);
1592 if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) {
1593 smbsrv_setup_error(req, req->ntvfs->async_states->status);
1596 /* we need to divide up the reply into chunks that fit into
1597 the negotiated buffer size */
1598 do {
1599 uint16_t this_data, this_param, max_bytes;
1600 uint_t align1 = 1, align2 = (params_left ? 2 : 0);
1601 struct smbsrv_request *this_req;
1603 max_bytes = req_max_data(req) - (align1 + align2);
1605 this_param = params_left;
1606 if (this_param > max_bytes) {
1607 this_param = max_bytes;
1609 max_bytes -= this_param;
1611 this_data = data_left;
1612 if (this_data > max_bytes) {
1613 this_data = max_bytes;
1616 /* don't destroy unless this is the last chunk */
1617 if (params_left - this_param != 0 ||
1618 data_left - this_data != 0) {
1619 this_req = smbsrv_setup_secondary_request(req);
1620 } else {
1621 this_req = req;
1624 req_grow_data(this_req, this_param + this_data + (align1 + align2));
1626 SSVAL(this_req->out.vwv, VWV(0), trans->out.params.length);
1627 SSVAL(this_req->out.vwv, VWV(1), trans->out.data.length);
1628 SSVAL(this_req->out.vwv, VWV(2), 0);
1630 SSVAL(this_req->out.vwv, VWV(3), this_param);
1631 SSVAL(this_req->out.vwv, VWV(4), align1 + PTR_DIFF(this_req->out.data, this_req->out.hdr));
1632 SSVAL(this_req->out.vwv, VWV(5), PTR_DIFF(params, trans->out.params.data));
1634 SSVAL(this_req->out.vwv, VWV(6), this_data);
1635 SSVAL(this_req->out.vwv, VWV(7), align1 + align2 +
1636 PTR_DIFF(this_req->out.data + this_param, this_req->out.hdr));
1637 SSVAL(this_req->out.vwv, VWV(8), PTR_DIFF(data, trans->out.data.data));
1639 SSVAL(this_req->out.vwv, VWV(9), trans->out.setup_count);
1640 for (i=0;i<trans->out.setup_count;i++) {
1641 SSVAL(this_req->out.vwv, VWV(10+i), trans->out.setup[i]);
1644 memset(this_req->out.data, 0, align1);
1645 if (this_param != 0) {
1646 memcpy(this_req->out.data + align1, params, this_param);
1648 memset(this_req->out.data+this_param+align1, 0, align2);
1649 if (this_data != 0) {
1650 memcpy(this_req->out.data+this_param+align1+align2, data, this_data);
1653 params_left -= this_param;
1654 data_left -= this_data;
1655 params += this_param;
1656 data += this_data;
1658 smbsrv_send_reply(this_req);
1659 } while (params_left != 0 || data_left != 0);
1664 answer a reconstructed trans request
1666 static void reply_trans_complete(struct smbsrv_request *req, uint8_t command,
1667 struct smb_trans2 *trans)
1669 struct trans_op *op;
1671 SMBSRV_TALLOC_IO_PTR(op, struct trans_op);
1672 SMBSRV_SETUP_NTVFS_REQUEST(reply_trans_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1674 op->req = req;
1675 op->trans = trans;
1676 op->command = command;
1677 op->op_info = NULL;
1678 op->send_fn = NULL;
1680 /* its a full request, give it to the backend */
1681 if (command == SMBtrans) {
1682 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_trans(req->ntvfs, trans));
1683 return;
1684 } else {
1685 SMBSRV_CALL_NTVFS_BACKEND(trans2_backend(req, op));
1686 return;
1691 Reply to an SMBtrans or SMBtrans2 request
1693 static void reply_trans_generic(struct smbsrv_request *req, uint8_t command)
1695 struct smb_trans2 *trans;
1696 int i;
1697 uint16_t param_ofs, data_ofs;
1698 uint16_t param_count, data_count;
1699 uint16_t param_total, data_total;
1701 /* parse request */
1702 if (req->in.wct < 14) {
1703 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1704 return;
1707 trans = talloc(req, struct smb_trans2);
1708 if (trans == NULL) {
1709 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
1710 return;
1713 param_total = SVAL(req->in.vwv, VWV(0));
1714 data_total = SVAL(req->in.vwv, VWV(1));
1715 trans->in.max_param = SVAL(req->in.vwv, VWV(2));
1716 trans->in.max_data = SVAL(req->in.vwv, VWV(3));
1717 trans->in.max_setup = CVAL(req->in.vwv, VWV(4));
1718 trans->in.flags = SVAL(req->in.vwv, VWV(5));
1719 trans->in.timeout = IVAL(req->in.vwv, VWV(6));
1720 param_count = SVAL(req->in.vwv, VWV(9));
1721 param_ofs = SVAL(req->in.vwv, VWV(10));
1722 data_count = SVAL(req->in.vwv, VWV(11));
1723 data_ofs = SVAL(req->in.vwv, VWV(12));
1724 trans->in.setup_count = CVAL(req->in.vwv, VWV(13));
1726 if (req->in.wct != 14 + trans->in.setup_count) {
1727 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
1728 return;
1731 /* parse out the setup words */
1732 trans->in.setup = talloc_array(trans, uint16_t, trans->in.setup_count);
1733 if (trans->in.setup_count && !trans->in.setup) {
1734 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
1735 return;
1737 for (i=0;i<trans->in.setup_count;i++) {
1738 trans->in.setup[i] = SVAL(req->in.vwv, VWV(14+i));
1741 if (command == SMBtrans) {
1742 req_pull_string(req, &trans->in.trans_name, req->in.data, -1, STR_TERMINATE);
1745 if (!req_pull_blob(req, req->in.hdr + param_ofs, param_count, &trans->in.params) ||
1746 !req_pull_blob(req, req->in.hdr + data_ofs, data_count, &trans->in.data)) {
1747 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1748 return;
1751 /* is it a partial request? if so, then send a 'send more' message */
1752 if (param_total > param_count || data_total > data_count) {
1753 reply_trans_continue(req, command, trans);
1754 return;
1757 reply_trans_complete(req, command, trans);
1762 Reply to an SMBtranss2 request
1764 static void reply_transs_generic(struct smbsrv_request *req, uint8_t command)
1766 struct smbsrv_trans_partial *tp;
1767 struct smb_trans2 *trans = NULL;
1768 uint16_t param_ofs, data_ofs;
1769 uint16_t param_count, data_count;
1770 uint16_t param_disp, data_disp;
1771 uint16_t param_total, data_total;
1772 DATA_BLOB params, data;
1774 /* parse request */
1775 if (req->in.wct < 8) {
1776 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1777 return;
1780 for (tp=req->smb_conn->trans_partial;tp;tp=tp->next) {
1781 if (tp->command == command &&
1782 SVAL(tp->req->in.hdr, HDR_MID) == SVAL(req->in.hdr, HDR_MID)) {
1783 /* TODO: check the VUID, PID and TID too? */
1784 break;
1788 if (tp == NULL) {
1789 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1790 return;
1793 trans = tp->trans;
1795 param_total = SVAL(req->in.vwv, VWV(0));
1796 data_total = SVAL(req->in.vwv, VWV(1));
1797 param_count = SVAL(req->in.vwv, VWV(2));
1798 param_ofs = SVAL(req->in.vwv, VWV(3));
1799 param_disp = SVAL(req->in.vwv, VWV(4));
1800 data_count = SVAL(req->in.vwv, VWV(5));
1801 data_ofs = SVAL(req->in.vwv, VWV(6));
1802 data_disp = SVAL(req->in.vwv, VWV(7));
1804 if (!req_pull_blob(req, req->in.hdr + param_ofs, param_count, &params) ||
1805 !req_pull_blob(req, req->in.hdr + data_ofs, data_count, &data)) {
1806 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1807 return;
1810 /* only allow contiguous requests */
1811 if ((param_count != 0 &&
1812 param_disp != trans->in.params.length) ||
1813 (data_count != 0 &&
1814 data_disp != trans->in.data.length)) {
1815 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1816 return;
1819 /* add to the existing request */
1820 if (param_count != 0) {
1821 trans->in.params.data = talloc_realloc(trans,
1822 trans->in.params.data,
1823 uint8_t,
1824 param_disp + param_count);
1825 if (trans->in.params.data == NULL) {
1826 goto failed;
1828 trans->in.params.length = param_disp + param_count;
1831 if (data_count != 0) {
1832 trans->in.data.data = talloc_realloc(trans,
1833 trans->in.data.data,
1834 uint8_t,
1835 data_disp + data_count);
1836 if (trans->in.data.data == NULL) {
1837 goto failed;
1839 trans->in.data.length = data_disp + data_count;
1842 memcpy(trans->in.params.data + param_disp, params.data, params.length);
1843 memcpy(trans->in.data.data + data_disp, data.data, data.length);
1845 /* the sequence number of the reply is taken from the last secondary
1846 response */
1847 tp->req->seq_num = req->seq_num;
1849 /* we don't reply to Transs2 requests */
1850 talloc_free(req);
1852 if (trans->in.params.length == param_total &&
1853 trans->in.data.length == data_total) {
1854 /* its now complete */
1855 DLIST_REMOVE(tp->req->smb_conn->trans_partial, tp);
1856 reply_trans_complete(tp->req, command, trans);
1858 return;
1860 failed:
1861 smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
1862 DLIST_REMOVE(req->smb_conn->trans_partial, tp);
1863 talloc_free(req);
1864 talloc_free(tp);
1869 Reply to an SMBtrans2
1871 void smbsrv_reply_trans2(struct smbsrv_request *req)
1873 reply_trans_generic(req, SMBtrans2);
1877 Reply to an SMBtrans
1879 void smbsrv_reply_trans(struct smbsrv_request *req)
1881 reply_trans_generic(req, SMBtrans);
1885 Reply to an SMBtranss request
1887 void smbsrv_reply_transs(struct smbsrv_request *req)
1889 reply_transs_generic(req, SMBtrans);
1893 Reply to an SMBtranss2 request
1895 void smbsrv_reply_transs2(struct smbsrv_request *req)
1897 reply_transs_generic(req, SMBtrans2);