1 /*
2    Unix SMB/CIFS implementation.
3    transaction2 handling
4    Copyright (C) Andrew Tridgell 2003
5 
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.
10 
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.
15 
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.
19 */
20 /*
21    This file handles the parsing of transact2 requests
22 */
23 
24 #include "includes.h"
25 #include "lib/util/dlinklist.h"
26 #include "smb_server/smb_server.h"
27 #include "librpc/gen_ndr/ndr_misc.h"
28 #include "ntvfs/ntvfs.h"
29 #include "libcli/raw/libcliraw.h"
30 
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)
46 
47 /*
48   hold the state of a nttrans op while in progress. Needed to allow for async backend
49   functions.
50 */
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;
57 };
58 
59 #define CHECK_MIN_BLOB_SIZE(blob, size) do { \
60 	if ((blob)->length < (size)) { \
61 		return NT_STATUS_INFO_LENGTH_MISMATCH; \
62 	}} while (0)
63 
64 /* setup a trans2 reply, given the data and params sizes */
trans2_setup_reply(struct smb_trans2 * trans,uint16_t param_size,uint16_t data_size,uint16_t setup_count)65 static NTSTATUS trans2_setup_reply(struct smb_trans2 *trans,
66 				   uint16_t param_size, uint16_t data_size,
67 				   uint16_t setup_count)
68 {
69 	trans->out.setup_count = setup_count;
70 	if (setup_count > 0) {
71 		trans->out.setup = talloc_zero_array(trans, uint16_t, setup_count);
72 		NT_STATUS_HAVE_NO_MEMORY(trans->out.setup);
73 	}
74 	trans->out.params = data_blob_talloc(trans, NULL, param_size);
75 	if (param_size > 0) NT_STATUS_HAVE_NO_MEMORY(trans->out.params.data);
76 
77 	trans->out.data = data_blob_talloc(trans, NULL, data_size);
78 	if (data_size > 0) NT_STATUS_HAVE_NO_MEMORY(trans->out.data.data);
79 
80 	return NT_STATUS_OK;
81 }
82 
trans2_push_fsinfo(struct smbsrv_connection * smb_conn,TALLOC_CTX * mem_ctx,DATA_BLOB * blob,union smb_fsinfo * fsinfo,int default_str_flags)83 static NTSTATUS trans2_push_fsinfo(struct smbsrv_connection *smb_conn,
84 				   TALLOC_CTX *mem_ctx,
85 				   DATA_BLOB *blob,
86 				   union smb_fsinfo *fsinfo,
87 				   int default_str_flags)
88 {
89 	enum smb_fsinfo_level passthru_level;
90 
91 	switch (fsinfo->generic.level) {
92 	case RAW_QFS_ALLOCATION:
93 		TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 18));
94 
95 		SIVAL(blob->data,  0, fsinfo->allocation.out.fs_id);
96 		SIVAL(blob->data,  4, fsinfo->allocation.out.sectors_per_unit);
97 		SIVAL(blob->data,  8, fsinfo->allocation.out.total_alloc_units);
98 		SIVAL(blob->data, 12, fsinfo->allocation.out.avail_alloc_units);
99 		SSVAL(blob->data, 16, fsinfo->allocation.out.bytes_per_sector);
100 
101 		return NT_STATUS_OK;
102 
103 	case RAW_QFS_VOLUME:
104 		TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 5));
105 
106 		SIVAL(blob->data,       0, fsinfo->volume.out.serial_number);
107 		/* w2k3 implements this incorrectly for unicode - it
108 		 * leaves the last byte off the string */
109 		TRANS2_CHECK(smbsrv_blob_append_string(mem_ctx, blob,
110 						       fsinfo->volume.out.volume_name.s,
111 						       4, default_str_flags,
112 						       STR_LEN8BIT|STR_NOALIGN));
113 
114 		return NT_STATUS_OK;
115 
116 	case RAW_QFS_VOLUME_INFO:
117 		passthru_level = RAW_QFS_VOLUME_INFORMATION;
118 		break;
119 
120 	case RAW_QFS_SIZE_INFO:
121 		passthru_level = RAW_QFS_SIZE_INFORMATION;
122 		break;
123 
124 	case RAW_QFS_DEVICE_INFO:
125 		passthru_level = RAW_QFS_DEVICE_INFORMATION;
126 		break;
127 
128 	case RAW_QFS_ATTRIBUTE_INFO:
129 		passthru_level = RAW_QFS_ATTRIBUTE_INFORMATION;
130 		break;
131 
132 	default:
133 		passthru_level = fsinfo->generic.level;
134 		break;
135 	}
136 
137 	return smbsrv_push_passthru_fsinfo(mem_ctx, blob,
138 					   passthru_level, fsinfo,
139 					   default_str_flags);
140 }
141 
142 /*
143   trans2 qfsinfo implementation send
144 */
trans2_qfsinfo_send(struct trans_op * op)145 static NTSTATUS trans2_qfsinfo_send(struct trans_op *op)
146 {
147 	struct smbsrv_request *req = op->req;
148 	struct smb_trans2 *trans = op->trans;
149 	union smb_fsinfo *fsinfo;
150 
151 	TRANS2_CHECK_ASYNC_STATUS(fsinfo, union smb_fsinfo);
152 
153 	TRANS2_CHECK(trans2_setup_reply(trans, 0, 0, 0));
154 
155 	TRANS2_CHECK(trans2_push_fsinfo(req->smb_conn, trans,
156 					&trans->out.data, fsinfo,
157 					SMBSRV_REQ_DEFAULT_STR_FLAGS(req)));
158 
159 	return NT_STATUS_OK;
160 }
161 
162 /*
163   trans2 qfsinfo implementation
164 */
trans2_qfsinfo(struct smbsrv_request * req,struct trans_op * op)165 static NTSTATUS trans2_qfsinfo(struct smbsrv_request *req, struct trans_op *op)
166 {
167 	struct smb_trans2 *trans = op->trans;
168 	union smb_fsinfo *fsinfo;
169 	uint16_t level;
170 
171 	/* make sure we got enough parameters */
172 	if (trans->in.params.length != 2) {
173 		return NT_STATUS_FOOBAR;
174 	}
175 
176 	fsinfo = talloc(op, union smb_fsinfo);
177 	NT_STATUS_HAVE_NO_MEMORY(fsinfo);
178 
179 	level = SVAL(trans->in.params.data, 0);
180 
181 	/* work out the backend level - we make it 1-1 in the header */
182 	fsinfo->generic.level = (enum smb_fsinfo_level)level;
183 	if (fsinfo->generic.level >= RAW_QFS_GENERIC) {
184 		return NT_STATUS_INVALID_LEVEL;
185 	}
186 
187 	op->op_info = fsinfo;
188 	op->send_fn = trans2_qfsinfo_send;
189 
190 	return ntvfs_fsinfo(req->ntvfs, fsinfo);
191 }
192 
193 
194 /*
195   trans2 open implementation send
196 */
trans2_open_send(struct trans_op * op)197 static NTSTATUS trans2_open_send(struct trans_op *op)
198 {
199 	struct smbsrv_request *req = op->req;
200 	struct smb_trans2 *trans = op->trans;
201 	union smb_open *io;
202 
203 	TRANS2_CHECK_ASYNC_STATUS(io, union smb_open);
204 
205 	TRANS2_CHECK(trans2_setup_reply(trans, 30, 0, 0));
206 
207 	smbsrv_push_fnum(trans->out.params.data, VWV(0), io->t2open.out.file.ntvfs);
208 	SSVAL(trans->out.params.data, VWV(1), io->t2open.out.attrib);
209 	srv_push_dos_date3(req->smb_conn, trans->out.params.data,
210 			   VWV(2), io->t2open.out.write_time);
211 	SIVAL(trans->out.params.data, VWV(4), io->t2open.out.size);
212 	SSVAL(trans->out.params.data, VWV(6), io->t2open.out.access);
213 	SSVAL(trans->out.params.data, VWV(7), io->t2open.out.ftype);
214 	SSVAL(trans->out.params.data, VWV(8), io->t2open.out.devstate);
215 	SSVAL(trans->out.params.data, VWV(9), io->t2open.out.action);
216 	SIVAL(trans->out.params.data, VWV(10), 0); /* reserved */
217 	SSVAL(trans->out.params.data, VWV(12), 0); /* EaErrorOffset */
218 	SIVAL(trans->out.params.data, VWV(13), 0); /* EaLength */
219 
220 	return NT_STATUS_OK;
221 }
222 
223 /*
224   trans2 open implementation
225 */
trans2_open(struct smbsrv_request * req,struct trans_op * op)226 static NTSTATUS trans2_open(struct smbsrv_request *req, struct trans_op *op)
227 {
228 	struct smb_trans2 *trans = op->trans;
229 	union smb_open *io;
230 
231 	/* make sure we got enough parameters */
232 	if (trans->in.params.length < 29) {
233 		return NT_STATUS_FOOBAR;
234 	}
235 
236 	io = talloc(op, union smb_open);
237 	NT_STATUS_HAVE_NO_MEMORY(io);
238 
239 	io->t2open.level           = RAW_OPEN_T2OPEN;
240 	io->t2open.in.flags        = SVAL(trans->in.params.data, VWV(0));
241 	io->t2open.in.open_mode    = SVAL(trans->in.params.data, VWV(1));
242 	io->t2open.in.search_attrs = SVAL(trans->in.params.data, VWV(2));
243 	io->t2open.in.file_attrs   = SVAL(trans->in.params.data, VWV(3));
244 	io->t2open.in.write_time   = srv_pull_dos_date(req->smb_conn,
245 						    trans->in.params.data + VWV(4));
246 	io->t2open.in.open_func    = SVAL(trans->in.params.data, VWV(6));
247 	io->t2open.in.size         = IVAL(trans->in.params.data, VWV(7));
248 	io->t2open.in.timeout      = IVAL(trans->in.params.data, VWV(9));
249 	io->t2open.in.num_eas      = 0;
250 	io->t2open.in.eas          = NULL;
251 
252 	smbsrv_blob_pull_string(req, &trans->in.params, 28, &io->t2open.in.fname, 0);
253 	if (io->t2open.in.fname == NULL) {
254 		return NT_STATUS_FOOBAR;
255 	}
256 
257 	TRANS2_CHECK(ea_pull_list(&trans->in.data, io, &io->t2open.in.num_eas, &io->t2open.in.eas));
258 
259 	op->op_info = io;
260 	op->send_fn = trans2_open_send;
261 
262 	return ntvfs_open(req->ntvfs, io);
263 }
264 
265 
266 /*
267   trans2 simple send
268 */
trans2_simple_send(struct trans_op * op)269 static NTSTATUS trans2_simple_send(struct trans_op *op)
270 {
271 	struct smbsrv_request *req = op->req;
272 	struct smb_trans2 *trans = op->trans;
273 
274 	TRANS2_CHECK_ASYNC_STATUS_SIMPLE;
275 
276 	TRANS2_CHECK(trans2_setup_reply(trans, 2, 0, 0));
277 
278 	SSVAL(trans->out.params.data, VWV(0), 0);
279 
280 	return NT_STATUS_OK;
281 }
282 
283 /*
284   trans2 mkdir implementation
285 */
trans2_mkdir(struct smbsrv_request * req,struct trans_op * op)286 static NTSTATUS trans2_mkdir(struct smbsrv_request *req, struct trans_op *op)
287 {
288 	struct smb_trans2 *trans = op->trans;
289 	union smb_mkdir *io;
290 
291 	/* make sure we got enough parameters */
292 	if (trans->in.params.length < 5) {
293 		return NT_STATUS_FOOBAR;
294 	}
295 
296 	io = talloc(op, union smb_mkdir);
297 	NT_STATUS_HAVE_NO_MEMORY(io);
298 
299 	io->t2mkdir.level = RAW_MKDIR_T2MKDIR;
300 	smbsrv_blob_pull_string(req, &trans->in.params, 4, &io->t2mkdir.in.path, 0);
301 	if (io->t2mkdir.in.path == NULL) {
302 		return NT_STATUS_FOOBAR;
303 	}
304 
305 	TRANS2_CHECK(ea_pull_list(&trans->in.data, io,
306 				  &io->t2mkdir.in.num_eas,
307 				  &io->t2mkdir.in.eas));
308 
309 	op->op_info = io;
310 	op->send_fn = trans2_simple_send;
311 
312 	return ntvfs_mkdir(req->ntvfs, io);
313 }
314 
trans2_push_fileinfo(struct smbsrv_connection * smb_conn,TALLOC_CTX * mem_ctx,DATA_BLOB * blob,union smb_fileinfo * st,int default_str_flags)315 static NTSTATUS trans2_push_fileinfo(struct smbsrv_connection *smb_conn,
316 				     TALLOC_CTX *mem_ctx,
317 				     DATA_BLOB *blob,
318 				     union smb_fileinfo *st,
319 				     int default_str_flags)
320 {
321 	uint32_t list_size;
322 	enum smb_fileinfo_level passthru_level;
323 
324 	switch (st->generic.level) {
325 	case RAW_FILEINFO_GENERIC:
326 	case RAW_FILEINFO_GETATTR:
327 	case RAW_FILEINFO_GETATTRE:
328 	case RAW_FILEINFO_SEC_DESC:
329 	case RAW_FILEINFO_SMB2_ALL_EAS:
330 	case RAW_FILEINFO_SMB2_ALL_INFORMATION:
331 		/* handled elsewhere */
332 		return NT_STATUS_INVALID_LEVEL;
333 
334 	case RAW_FILEINFO_UNIX_BASIC:
335 	case RAW_FILEINFO_UNIX_LINK:
336 		/* not implemented yet */
337 		return NT_STATUS_INVALID_LEVEL;
338 
339 	case RAW_FILEINFO_STANDARD:
340 		TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 22));
341 
342 		srv_push_dos_date2(smb_conn, blob->data, 0, st->standard.out.create_time);
343 		srv_push_dos_date2(smb_conn, blob->data, 4, st->standard.out.access_time);
344 		srv_push_dos_date2(smb_conn, blob->data, 8, st->standard.out.write_time);
345 		SIVAL(blob->data,        12, st->standard.out.size);
346 		SIVAL(blob->data,        16, st->standard.out.alloc_size);
347 		SSVAL(blob->data,        20, st->standard.out.attrib);
348 		return NT_STATUS_OK;
349 
350 	case RAW_FILEINFO_EA_SIZE:
351 		TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 26));
352 
353 		srv_push_dos_date2(smb_conn, blob->data, 0, st->ea_size.out.create_time);
354 		srv_push_dos_date2(smb_conn, blob->data, 4, st->ea_size.out.access_time);
355 		srv_push_dos_date2(smb_conn, blob->data, 8, st->ea_size.out.write_time);
356 		SIVAL(blob->data,        12, st->ea_size.out.size);
357 		SIVAL(blob->data,        16, st->ea_size.out.alloc_size);
358 		SSVAL(blob->data,        20, st->ea_size.out.attrib);
359 		SIVAL(blob->data,        22, st->ea_size.out.ea_size);
360 		return NT_STATUS_OK;
361 
362 	case RAW_FILEINFO_EA_LIST:
363 		list_size = ea_list_size(st->ea_list.out.num_eas,
364 					 st->ea_list.out.eas);
365 		TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, list_size));
366 
367 		ea_put_list(blob->data,
368 			    st->ea_list.out.num_eas, st->ea_list.out.eas);
369 		return NT_STATUS_OK;
370 
371 	case RAW_FILEINFO_ALL_EAS:
372 		list_size = ea_list_size(st->all_eas.out.num_eas,
373 						  st->all_eas.out.eas);
374 		TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, list_size));
375 
376 		ea_put_list(blob->data,
377 			    st->all_eas.out.num_eas, st->all_eas.out.eas);
378 		return NT_STATUS_OK;
379 
380 	case RAW_FILEINFO_IS_NAME_VALID:
381 		return NT_STATUS_OK;
382 
383 	case RAW_FILEINFO_BASIC_INFO:
384 		passthru_level = RAW_FILEINFO_BASIC_INFORMATION;
385 		break;
386 
387 	case RAW_FILEINFO_STANDARD_INFO:
388 		passthru_level = RAW_FILEINFO_STANDARD_INFORMATION;
389 		break;
390 
391 	case RAW_FILEINFO_EA_INFO:
392 		passthru_level = RAW_FILEINFO_EA_INFORMATION;
393 		break;
394 
395 	case RAW_FILEINFO_COMPRESSION_INFO:
396 		passthru_level = RAW_FILEINFO_COMPRESSION_INFORMATION;
397 		break;
398 
399 	case RAW_FILEINFO_ALL_INFO:
400 		passthru_level = RAW_FILEINFO_ALL_INFORMATION;
401 		break;
402 
403 	case RAW_FILEINFO_NAME_INFO:
404 		passthru_level = RAW_FILEINFO_NAME_INFORMATION;
405 		break;
406 
407 	case RAW_FILEINFO_ALT_NAME_INFO:
408 		passthru_level = RAW_FILEINFO_ALT_NAME_INFORMATION;
409 		break;
410 
411 	case RAW_FILEINFO_STREAM_INFO:
412 		passthru_level = RAW_FILEINFO_STREAM_INFORMATION;
413 		break;
414 
415 	default:
416 		passthru_level = st->generic.level;
417 		break;
418 	}
419 
420 	return smbsrv_push_passthru_fileinfo(mem_ctx, blob,
421 					     passthru_level, st,
422 					     default_str_flags);
423 }
424 
425 /*
426   fill in the reply from a qpathinfo or qfileinfo call
427 */
trans2_fileinfo_send(struct trans_op * op)428 static NTSTATUS trans2_fileinfo_send(struct trans_op *op)
429 {
430 	struct smbsrv_request *req = op->req;
431 	struct smb_trans2 *trans = op->trans;
432 	union smb_fileinfo *st;
433 
434 	TRANS2_CHECK_ASYNC_STATUS(st, union smb_fileinfo);
435 
436 	TRANS2_CHECK(trans2_setup_reply(trans, 2, 0, 0));
437 	SSVAL(trans->out.params.data, 0, 0);
438 
439 	TRANS2_CHECK(trans2_push_fileinfo(req->smb_conn, trans,
440 					  &trans->out.data, st,
441 					  SMBSRV_REQ_DEFAULT_STR_FLAGS(req)));
442 
443 	return NT_STATUS_OK;
444 }
445 
446 /*
447   trans2 qpathinfo implementation
448 */
trans2_qpathinfo(struct smbsrv_request * req,struct trans_op * op)449 static NTSTATUS trans2_qpathinfo(struct smbsrv_request *req, struct trans_op *op)
450 {
451 	struct smb_trans2 *trans = op->trans;
452 	union smb_fileinfo *st;
453 	uint16_t level;
454 
455 	/* make sure we got enough parameters */
456 	if (trans->in.params.length < 2) {
457 		return NT_STATUS_FOOBAR;
458 	}
459 
460 	st = talloc(op, union smb_fileinfo);
461 	NT_STATUS_HAVE_NO_MEMORY(st);
462 
463 	level = SVAL(trans->in.params.data, 0);
464 
465 	smbsrv_blob_pull_string(req, &trans->in.params, 6, &st->generic.in.file.path, 0);
466 	if (st->generic.in.file.path == NULL) {
467 		return NT_STATUS_FOOBAR;
468 	}
469 
470 	/* work out the backend level - we make it 1-1 in the header */
471 	st->generic.level = (enum smb_fileinfo_level)level;
472 	if (st->generic.level >= RAW_FILEINFO_GENERIC) {
473 		return NT_STATUS_INVALID_LEVEL;
474 	}
475 
476 	if (st->generic.level == RAW_FILEINFO_EA_LIST) {
477 		TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
478 					       &st->ea_list.in.num_names,
479 					       &st->ea_list.in.ea_names));
480 	}
481 
482 	op->op_info = st;
483 	op->send_fn = trans2_fileinfo_send;
484 
485 	return ntvfs_qpathinfo(req->ntvfs, st);
486 }
487 
488 
489 /*
490   trans2 qpathinfo implementation
491 */
trans2_qfileinfo(struct smbsrv_request * req,struct trans_op * op)492 static NTSTATUS trans2_qfileinfo(struct smbsrv_request *req, struct trans_op *op)
493 {
494 	struct smb_trans2 *trans = op->trans;
495 	union smb_fileinfo *st;
496 	uint16_t level;
497 	struct ntvfs_handle *h;
498 
499 	/* make sure we got enough parameters */
500 	if (trans->in.params.length < 4) {
501 		return NT_STATUS_FOOBAR;
502 	}
503 
504 	st = talloc(op, union smb_fileinfo);
505 	NT_STATUS_HAVE_NO_MEMORY(st);
506 
507 	h     = smbsrv_pull_fnum(req, trans->in.params.data, 0);
508 	level = SVAL(trans->in.params.data, 2);
509 
510 	st->generic.in.file.ntvfs = h;
511 	/* work out the backend level - we make it 1-1 in the header */
512 	st->generic.level = (enum smb_fileinfo_level)level;
513 	if (st->generic.level >= RAW_FILEINFO_GENERIC) {
514 		return NT_STATUS_INVALID_LEVEL;
515 	}
516 
517 	if (st->generic.level == RAW_FILEINFO_EA_LIST) {
518 		TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
519 					       &st->ea_list.in.num_names,
520 					       &st->ea_list.in.ea_names));
521 	}
522 
523 	op->op_info = st;
524 	op->send_fn = trans2_fileinfo_send;
525 
526 	SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st->generic.in.file.ntvfs);
527 	return ntvfs_qfileinfo(req->ntvfs, st);
528 }
529 
530 
531 /*
532   parse a trans2 setfileinfo/setpathinfo data blob
533 */
trans2_parse_sfileinfo(struct smbsrv_request * req,union smb_setfileinfo * st,const DATA_BLOB * blob)534 static NTSTATUS trans2_parse_sfileinfo(struct smbsrv_request *req,
535 				       union smb_setfileinfo *st,
536 				       const DATA_BLOB *blob)
537 {
538 	enum smb_setfileinfo_level passthru_level;
539 
540 	switch (st->generic.level) {
541 	case RAW_SFILEINFO_GENERIC:
542 	case RAW_SFILEINFO_SETATTR:
543 	case RAW_SFILEINFO_SETATTRE:
544 	case RAW_SFILEINFO_SEC_DESC:
545 		/* handled elsewhere */
546 		return NT_STATUS_INVALID_LEVEL;
547 
548 	case RAW_SFILEINFO_STANDARD:
549 		CHECK_MIN_BLOB_SIZE(blob, 12);
550 
551 		st->standard.in.create_time = srv_pull_dos_date2(req->smb_conn, blob->data + 0);
552 		st->standard.in.access_time = srv_pull_dos_date2(req->smb_conn, blob->data + 4);
553 		st->standard.in.write_time  = srv_pull_dos_date2(req->smb_conn, blob->data + 8);
554 
555 		return NT_STATUS_OK;
556 
557 	case RAW_SFILEINFO_EA_SET:
558 		return ea_pull_list(blob, req,
559 				    &st->ea_set.in.num_eas,
560 				    &st->ea_set.in.eas);
561 
562 	case SMB_SFILEINFO_BASIC_INFO:
563 	case SMB_SFILEINFO_BASIC_INFORMATION:
564 		passthru_level = SMB_SFILEINFO_BASIC_INFORMATION;
565 		break;
566 
567 	case SMB_SFILEINFO_DISPOSITION_INFO:
568 	case SMB_SFILEINFO_DISPOSITION_INFORMATION:
569 		passthru_level = SMB_SFILEINFO_DISPOSITION_INFORMATION;
570 		break;
571 
572 	case SMB_SFILEINFO_ALLOCATION_INFO:
573 	case SMB_SFILEINFO_ALLOCATION_INFORMATION:
574 		passthru_level = SMB_SFILEINFO_ALLOCATION_INFORMATION;
575 		break;
576 
577 	case RAW_SFILEINFO_END_OF_FILE_INFO:
578 	case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
579 		passthru_level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
580 		break;
581 
582 	case RAW_SFILEINFO_RENAME_INFORMATION:
583 	case RAW_SFILEINFO_POSITION_INFORMATION:
584 	case RAW_SFILEINFO_MODE_INFORMATION:
585 		passthru_level = st->generic.level;
586 		break;
587 
588 	case RAW_SFILEINFO_UNIX_BASIC:
589 	case RAW_SFILEINFO_UNIX_LINK:
590 	case RAW_SFILEINFO_UNIX_HLINK:
591 	case RAW_SFILEINFO_1023:
592 	case RAW_SFILEINFO_1025:
593 	case RAW_SFILEINFO_1029:
594 	case RAW_SFILEINFO_1032:
595 	case RAW_SFILEINFO_1039:
596 	case RAW_SFILEINFO_1040:
597 		return NT_STATUS_INVALID_LEVEL;
598 
599 	default:
600 		/* we need a default here to cope with invalid values on the wire */
601 		return NT_STATUS_INVALID_LEVEL;
602 	}
603 
604 	return smbsrv_pull_passthru_sfileinfo(st, passthru_level, st,
605 					      blob, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
606 					      req);
607 }
608 
609 /*
610   trans2 setfileinfo implementation
611 */
trans2_setfileinfo(struct smbsrv_request * req,struct trans_op * op)612 static NTSTATUS trans2_setfileinfo(struct smbsrv_request *req, struct trans_op *op)
613 {
614 	struct smb_trans2 *trans = op->trans;
615 	union smb_setfileinfo *st;
616 	uint16_t level;
617 	struct ntvfs_handle *h;
618 
619 	/* make sure we got enough parameters */
620 	if (trans->in.params.length < 4) {
621 		return NT_STATUS_FOOBAR;
622 	}
623 
624 	st = talloc(op, union smb_setfileinfo);
625 	NT_STATUS_HAVE_NO_MEMORY(st);
626 
627 	h     = smbsrv_pull_fnum(req, trans->in.params.data, 0);
628 	level = SVAL(trans->in.params.data, 2);
629 
630 	st->generic.in.file.ntvfs = h;
631 	/* work out the backend level - we make it 1-1 in the header */
632 	st->generic.level = (enum smb_setfileinfo_level)level;
633 	if (st->generic.level >= RAW_SFILEINFO_GENERIC) {
634 		return NT_STATUS_INVALID_LEVEL;
635 	}
636 
637 	TRANS2_CHECK(trans2_parse_sfileinfo(req, st, &trans->in.data));
638 
639 	op->op_info = st;
640 	op->send_fn = trans2_simple_send;
641 
642 	SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st->generic.in.file.ntvfs);
643 	return ntvfs_setfileinfo(req->ntvfs, st);
644 }
645 
646 /*
647   trans2 setpathinfo implementation
648 */
trans2_setpathinfo(struct smbsrv_request * req,struct trans_op * op)649 static NTSTATUS trans2_setpathinfo(struct smbsrv_request *req, struct trans_op *op)
650 {
651 	struct smb_trans2 *trans = op->trans;
652 	union smb_setfileinfo *st;
653 	uint16_t level;
654 
655 	/* make sure we got enough parameters */
656 	if (trans->in.params.length < 4) {
657 		return NT_STATUS_FOOBAR;
658 	}
659 
660 	st = talloc(op, union smb_setfileinfo);
661 	NT_STATUS_HAVE_NO_MEMORY(st);
662 
663 	level = SVAL(trans->in.params.data, 0);
664 
665 	smbsrv_blob_pull_string(req, &trans->in.params, 6, &st->generic.in.file.path, 0);
666 	if (st->generic.in.file.path == NULL) {
667 		return NT_STATUS_FOOBAR;
668 	}
669 
670 	/* work out the backend level - we make it 1-1 in the header */
671 	st->generic.level = (enum smb_setfileinfo_level)level;
672 	if (st->generic.level >= RAW_SFILEINFO_GENERIC) {
673 		return NT_STATUS_INVALID_LEVEL;
674 	}
675 
676 	TRANS2_CHECK(trans2_parse_sfileinfo(req, st, &trans->in.data));
677 
678 	op->op_info = st;
679 	op->send_fn = trans2_simple_send;
680 
681 	return ntvfs_setpathinfo(req->ntvfs, st);
682 }
683 
684 
685 /* a structure to encapsulate the state information about an in-progress ffirst/fnext operation */
686 struct find_state {
687 	struct trans_op *op;
688 	void *search;
689 	enum smb_search_data_level data_level;
690 	uint16_t last_entry_offset;
691 	uint16_t flags;
692 };
693 
694 /*
695   fill a single entry in a trans2 find reply
696 */
find_fill_info(struct find_state * state,union smb_search_data * file)697 static NTSTATUS find_fill_info(struct find_state *state,
698 			       union smb_search_data *file)
699 {
700 	struct smbsrv_request *req = state->op->req;
701 	struct smb_trans2 *trans = state->op->trans;
702 	uint8_t *data;
703 	uint_t ofs = trans->out.data.length;
704 	uint32_t ea_size;
705 
706 	switch (state->data_level) {
707 	case RAW_SEARCH_DATA_GENERIC:
708 	case RAW_SEARCH_DATA_SEARCH:
709 		/* handled elsewhere */
710 		return NT_STATUS_INVALID_LEVEL;
711 
712 	case RAW_SEARCH_DATA_STANDARD:
713 		if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
714 			TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 27));
715 			SIVAL(trans->out.data.data, ofs, file->standard.resume_key);
716 			ofs += 4;
717 		} else {
718 			TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 23));
719 		}
720 		data = trans->out.data.data + ofs;
721 		srv_push_dos_date2(req->smb_conn, data, 0, file->standard.create_time);
722 		srv_push_dos_date2(req->smb_conn, data, 4, file->standard.access_time);
723 		srv_push_dos_date2(req->smb_conn, data, 8, file->standard.write_time);
724 		SIVAL(data, 12, file->standard.size);
725 		SIVAL(data, 16, file->standard.alloc_size);
726 		SSVAL(data, 20, file->standard.attrib);
727 		TRANS2_CHECK(smbsrv_blob_append_string(trans, &trans->out.data, file->standard.name.s,
728 						       ofs + 22, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
729 						       STR_LEN8BIT | STR_TERMINATE | STR_LEN_NOTERM));
730 		break;
731 
732 	case RAW_SEARCH_DATA_EA_SIZE:
733 		if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
734 			TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 31));
735 			SIVAL(trans->out.data.data, ofs, file->ea_size.resume_key);
736 			ofs += 4;
737 		} else {
738 			TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 27));
739 		}
740 		data = trans->out.data.data + ofs;
741 		srv_push_dos_date2(req->smb_conn, data, 0, file->ea_size.create_time);
742 		srv_push_dos_date2(req->smb_conn, data, 4, file->ea_size.access_time);
743 		srv_push_dos_date2(req->smb_conn, data, 8, file->ea_size.write_time);
744 		SIVAL(data, 12, file->ea_size.size);
745 		SIVAL(data, 16, file->ea_size.alloc_size);
746 		SSVAL(data, 20, file->ea_size.attrib);
747 		SIVAL(data, 22, file->ea_size.ea_size);
748 		TRANS2_CHECK(smbsrv_blob_append_string(trans, &trans->out.data, file->ea_size.name.s,
749 						       ofs + 26, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
750 						       STR_LEN8BIT | STR_NOALIGN));
751 		TRANS2_CHECK(smbsrv_blob_fill_data(trans, &trans->out.data, trans->out.data.length + 1));
752 		break;
753 
754 	case RAW_SEARCH_DATA_EA_LIST:
755 		ea_size = ea_list_size(file->ea_list.eas.num_eas, file->ea_list.eas.eas);
756 		if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
757 			TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 27 + ea_size));
758 			SIVAL(trans->out.data.data, ofs, file->ea_list.resume_key);
759 			ofs += 4;
760 		} else {
761 			TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 23 + ea_size));
762 		}
763 		data = trans->out.data.data + ofs;
764 		srv_push_dos_date2(req->smb_conn, data, 0, file->ea_list.create_time);
765 		srv_push_dos_date2(req->smb_conn, data, 4, file->ea_list.access_time);
766 		srv_push_dos_date2(req->smb_conn, data, 8, file->ea_list.write_time);
767 		SIVAL(data, 12, file->ea_list.size);
768 		SIVAL(data, 16, file->ea_list.alloc_size);
769 		SSVAL(data, 20, file->ea_list.attrib);
770 		ea_put_list(data+22, file->ea_list.eas.num_eas, file->ea_list.eas.eas);
771 		TRANS2_CHECK(smbsrv_blob_append_string(trans, &trans->out.data, file->ea_list.name.s,
772 						       ofs + 22 + ea_size, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
773 						       STR_LEN8BIT | STR_NOALIGN));
774 		TRANS2_CHECK(smbsrv_blob_fill_data(trans, &trans->out.data, trans->out.data.length + 1));
775 		break;
776 
777 	case RAW_SEARCH_DATA_DIRECTORY_INFO:
778 	case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO:
779 	case RAW_SEARCH_DATA_NAME_INFO:
780 	case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO:
781 	case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO:
782 	case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO:
783 		return smbsrv_push_passthru_search(trans, &trans->out.data, state->data_level, file,
784 						   SMBSRV_REQ_DEFAULT_STR_FLAGS(req));
785 
786 	case RAW_SEARCH_DATA_UNIX_INFO:
787 		return NT_STATUS_INVALID_LEVEL;
788 	}
789 
790 	return NT_STATUS_OK;
791 }
792 
793 /* callback function for trans2 findfirst/findnext */
find_callback(void * private,union smb_search_data * file)794 static BOOL find_callback(void *private, union smb_search_data *file)
795 {
796 	struct find_state *state = talloc_get_type(private, struct find_state);
797 	struct smb_trans2 *trans = state->op->trans;
798 	uint_t old_length;
799 
800 	old_length = trans->out.data.length;
801 
802 	if (!NT_STATUS_IS_OK(find_fill_info(state, file)) ||
803 	    trans->out.data.length > trans->in.max_data) {
804 		/* restore the old length and tell the backend to stop */
805 		smbsrv_blob_grow_data(trans, &trans->out.data, old_length);
806 		return False;
807 	}
808 
809 	state->last_entry_offset = old_length;
810 	return True;
811 }
812 
813 /*
814   trans2 findfirst send
815  */
trans2_findfirst_send(struct trans_op * op)816 static NTSTATUS trans2_findfirst_send(struct trans_op *op)
817 {
818 	struct smbsrv_request *req = op->req;
819 	struct smb_trans2 *trans = op->trans;
820 	union smb_search_first *search;
821 	struct find_state *state;
822 	uint8_t *param;
823 
824 	TRANS2_CHECK_ASYNC_STATUS(state, struct find_state);
825 	search = talloc_get_type(state->search, union smb_search_first);
826 
827 	/* fill in the findfirst reply header */
828 	param = trans->out.params.data;
829 	SSVAL(param, VWV(0), search->t2ffirst.out.handle);
830 	SSVAL(param, VWV(1), search->t2ffirst.out.count);
831 	SSVAL(param, VWV(2), search->t2ffirst.out.end_of_search);
832 	SSVAL(param, VWV(3), 0);
833 	SSVAL(param, VWV(4), state->last_entry_offset);
834 
835 	return NT_STATUS_OK;
836 }
837 
838 
839 /*
840   trans2 findfirst implementation
841 */
trans2_findfirst(struct smbsrv_request * req,struct trans_op * op)842 static NTSTATUS trans2_findfirst(struct smbsrv_request *req, struct trans_op *op)
843 {
844 	struct smb_trans2 *trans = op->trans;
845 	union smb_search_first *search;
846 	uint16_t level;
847 	struct find_state *state;
848 
849 	/* make sure we got all the parameters */
850 	if (trans->in.params.length < 14) {
851 		return NT_STATUS_FOOBAR;
852 	}
853 
854 	search = talloc(op, union smb_search_first);
855 	NT_STATUS_HAVE_NO_MEMORY(search);
856 
857 	search->t2ffirst.in.search_attrib = SVAL(trans->in.params.data, 0);
858 	search->t2ffirst.in.max_count     = SVAL(trans->in.params.data, 2);
859 	search->t2ffirst.in.flags         = SVAL(trans->in.params.data, 4);
860 	level                             = SVAL(trans->in.params.data, 6);
861 	search->t2ffirst.in.storage_type  = IVAL(trans->in.params.data, 8);
862 
863 	smbsrv_blob_pull_string(req, &trans->in.params, 12, &search->t2ffirst.in.pattern, 0);
864 	if (search->t2ffirst.in.pattern == NULL) {
865 		return NT_STATUS_FOOBAR;
866 	}
867 
868 	search->t2ffirst.level = RAW_SEARCH_TRANS2;
869 	search->t2ffirst.data_level = (enum smb_search_data_level)level;
870 	if (search->t2ffirst.data_level >= RAW_SEARCH_DATA_GENERIC) {
871 		return NT_STATUS_INVALID_LEVEL;
872 	}
873 
874 	if (search->t2ffirst.data_level == RAW_SEARCH_DATA_EA_LIST) {
875 		TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
876 					       &search->t2ffirst.in.num_names,
877 					       &search->t2ffirst.in.ea_names));
878 	}
879 
880 	/* setup the private state structure that the backend will
881 	   give us in the callback */
882 	state = talloc(op, struct find_state);
883 	NT_STATUS_HAVE_NO_MEMORY(state);
884 	state->op		= op;
885 	state->search		= search;
886 	state->data_level	= search->t2ffirst.data_level;
887 	state->last_entry_offset= 0;
888 	state->flags		= search->t2ffirst.in.flags;
889 
890 	/* setup for just a header in the reply */
891 	TRANS2_CHECK(trans2_setup_reply(trans, 10, 0, 0));
892 
893 	op->op_info = state;
894 	op->send_fn = trans2_findfirst_send;
895 
896 	return ntvfs_search_first(req->ntvfs, search, state, find_callback);
897 }
898 
899 
900 /*
901   trans2 findnext send
902 */
trans2_findnext_send(struct trans_op * op)903 static NTSTATUS trans2_findnext_send(struct trans_op *op)
904 {
905 	struct smbsrv_request *req = op->req;
906 	struct smb_trans2 *trans = op->trans;
907 	union smb_search_next *search;
908 	struct find_state *state;
909 	uint8_t *param;
910 
911 	TRANS2_CHECK_ASYNC_STATUS(state, struct find_state);
912 	search = talloc_get_type(state->search, union smb_search_next);
913 
914 	/* fill in the findfirst reply header */
915 	param = trans->out.params.data;
916 	SSVAL(param, VWV(0), search->t2fnext.out.count);
917 	SSVAL(param, VWV(1), search->t2fnext.out.end_of_search);
918 	SSVAL(param, VWV(2), 0);
919 	SSVAL(param, VWV(3), state->last_entry_offset);
920 
921 	return NT_STATUS_OK;
922 }
923 
924 
925 /*
926   trans2 findnext implementation
927 */
trans2_findnext(struct smbsrv_request * req,struct trans_op * op)928 static NTSTATUS trans2_findnext(struct smbsrv_request *req, struct trans_op *op)
929 {
930 	struct smb_trans2 *trans = op->trans;
931 	union smb_search_next *search;
932 	uint16_t level;
933 	struct find_state *state;
934 
935 	/* make sure we got all the parameters */
936 	if (trans->in.params.length < 12) {
937 		return NT_STATUS_FOOBAR;
938 	}
939 
940 	search = talloc(op, union smb_search_next);
941 	NT_STATUS_HAVE_NO_MEMORY(search);
942 
943 	search->t2fnext.in.handle        = SVAL(trans->in.params.data, 0);
944 	search->t2fnext.in.max_count     = SVAL(trans->in.params.data, 2);
945 	level                            = SVAL(trans->in.params.data, 4);
946 	search->t2fnext.in.resume_key    = IVAL(trans->in.params.data, 6);
947 	search->t2fnext.in.flags         = SVAL(trans->in.params.data, 10);
948 
949 	smbsrv_blob_pull_string(req, &trans->in.params, 12, &search->t2fnext.in.last_name, 0);
950 	if (search->t2fnext.in.last_name == NULL) {
951 		return NT_STATUS_FOOBAR;
952 	}
953 
954 	search->t2fnext.level = RAW_SEARCH_TRANS2;
955 	search->t2fnext.data_level = (enum smb_search_data_level)level;
956 	if (search->t2fnext.data_level >= RAW_SEARCH_DATA_GENERIC) {
957 		return NT_STATUS_INVALID_LEVEL;
958 	}
959 
960 	if (search->t2fnext.data_level == RAW_SEARCH_DATA_EA_LIST) {
961 		TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
962 					       &search->t2fnext.in.num_names,
963 					       &search->t2fnext.in.ea_names));
964 	}
965 
966 	/* setup the private state structure that the backend will give us in the callback */
967 	state = talloc(op, struct find_state);
968 	NT_STATUS_HAVE_NO_MEMORY(state);
969 	state->op		= op;
970 	state->search		= search;
971 	state->data_level	= search->t2fnext.data_level;
972 	state->last_entry_offset= 0;
973 	state->flags		= search->t2fnext.in.flags;
974 
975 	/* setup for just a header in the reply */
976 	TRANS2_CHECK(trans2_setup_reply(trans, 8, 0, 0));
977 
978 	op->op_info = state;
979 	op->send_fn = trans2_findnext_send;
980 
981 	return ntvfs_search_next(req->ntvfs, search, state, find_callback);
982 }
983 
984 
985 /*
986   backend for trans2 requests
987 */
trans2_backend(struct smbsrv_request * req,struct trans_op * op)988 static NTSTATUS trans2_backend(struct smbsrv_request *req, struct trans_op *op)
989 {
990 	struct smb_trans2 *trans = op->trans;
991 	NTSTATUS status;
992 
993 	/* direct trans2 pass thru */
994 	status = ntvfs_trans2(req->ntvfs, trans);
995 	if (!NT_STATUS_EQUAL(NT_STATUS_NOT_IMPLEMENTED, status)) {
996 		return status;
997 	}
998 
999 	/* must have at least one setup word */
1000 	if (trans->in.setup_count < 1) {
1001 		return NT_STATUS_FOOBAR;
1002 	}
1003 
1004 	/* the trans2 command is in setup[0] */
1005 	switch (trans->in.setup[0]) {
1006 	case TRANSACT2_FINDFIRST:
1007 		return trans2_findfirst(req, op);
1008 	case TRANSACT2_FINDNEXT:
1009 		return trans2_findnext(req, op);
1010 	case TRANSACT2_QPATHINFO:
1011 		return trans2_qpathinfo(req, op);
1012 	case TRANSACT2_QFILEINFO:
1013 		return trans2_qfileinfo(req, op);
1014 	case TRANSACT2_SETFILEINFO:
1015 		return trans2_setfileinfo(req, op);
1016 	case TRANSACT2_SETPATHINFO:
1017 		return trans2_setpathinfo(req, op);
1018 	case TRANSACT2_QFSINFO:
1019 		return trans2_qfsinfo(req, op);
1020 	case TRANSACT2_OPEN:
1021 		return trans2_open(req, op);
1022 	case TRANSACT2_MKDIR:
1023 		return trans2_mkdir(req, op);
1024 	}
1025 
1026 	/* an unknown trans2 command */
1027 	return NT_STATUS_FOOBAR;
1028 }
1029 
1030 
1031 /*
1032   send a continue request
1033 */
reply_trans_continue(struct smbsrv_request * req,uint8_t command,struct smb_trans2 * trans)1034 static void reply_trans_continue(struct smbsrv_request *req, uint8_t command,
1035 				 struct smb_trans2 *trans)
1036 {
1037 	struct smbsrv_trans_partial *tp;
1038 	int count;
1039 
1040 	/* make sure they don't flood us */
1041 	for (count=0,tp=req->smb_conn->trans_partial;tp;tp=tp->next) count++;
1042 	if (count > 100) {
1043 		smbsrv_send_error(req, NT_STATUS_INSUFFICIENT_RESOURCES);
1044 		return;
1045 	}
1046 
1047 	tp = talloc(req, struct smbsrv_trans_partial);
1048 
1049 	tp->req = talloc_reference(tp, req);
1050 	tp->trans = trans;
1051 	tp->command = command;
1052 
1053 	DLIST_ADD(req->smb_conn->trans_partial, tp);
1054 
1055 	/* send a 'please continue' reply */
1056 	smbsrv_setup_reply(req, 0, 0);
1057 	smbsrv_send_reply(req);
1058 }
1059 
1060 
1061 /*
1062   answer a reconstructed trans request
1063 */
reply_trans_send(struct ntvfs_request * ntvfs)1064 static void reply_trans_send(struct ntvfs_request *ntvfs)
1065 {
1066 	struct smbsrv_request *req;
1067 	struct trans_op *op;
1068 	struct smb_trans2 *trans;
1069 	uint16_t params_left, data_left;
1070 	uint8_t *params, *data;
1071 	int i;
1072 
1073 	SMBSRV_CHECK_ASYNC_STATUS_ERR(op, struct trans_op);
1074 	trans = op->trans;
1075 
1076 	/* if this function needs work to form the nttrans reply buffer, then
1077 	   call that now */
1078 	if (op->send_fn != NULL) {
1079 		NTSTATUS status;
1080 		status = op->send_fn(op);
1081 		if (!NT_STATUS_IS_OK(status)) {
1082 			smbsrv_send_error(req, status);
1083 			return;
1084 		}
1085 	}
1086 
1087 	params_left = trans->out.params.length;
1088 	data_left   = trans->out.data.length;
1089 	params      = trans->out.params.data;
1090 	data        = trans->out.data.data;
1091 
1092 	smbsrv_setup_reply(req, 10 + trans->out.setup_count, 0);
1093 
1094 	if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) {
1095 		smbsrv_setup_error(req, req->ntvfs->async_states->status);
1096 	}
1097 
1098 	/* we need to divide up the reply into chunks that fit into
1099 	   the negotiated buffer size */
1100 	do {
1101 		uint16_t this_data, this_param, max_bytes;
1102 		uint_t align1 = 1, align2 = (params_left ? 2 : 0);
1103 		struct smbsrv_request *this_req;
1104 
1105 		max_bytes = req_max_data(req) - (align1 + align2);
1106 
1107 		this_param = params_left;
1108 		if (this_param > max_bytes) {
1109 			this_param = max_bytes;
1110 		}
1111 		max_bytes -= this_param;
1112 
1113 		this_data = data_left;
1114 		if (this_data > max_bytes) {
1115 			this_data = max_bytes;
1116 		}
1117 
1118 		/* don't destroy unless this is the last chunk */
1119 		if (params_left - this_param != 0 ||
1120 		    data_left - this_data != 0) {
1121 			this_req = smbsrv_setup_secondary_request(req);
1122 		} else {
1123 			this_req = req;
1124 		}
1125 
1126 		req_grow_data(this_req, this_param + this_data + (align1 + align2));
1127 
1128 		SSVAL(this_req->out.vwv, VWV(0), trans->out.params.length);
1129 		SSVAL(this_req->out.vwv, VWV(1), trans->out.data.length);
1130 		SSVAL(this_req->out.vwv, VWV(2), 0);
1131 
1132 		SSVAL(this_req->out.vwv, VWV(3), this_param);
1133 		SSVAL(this_req->out.vwv, VWV(4), align1 + PTR_DIFF(this_req->out.data, this_req->out.hdr));
1134 		SSVAL(this_req->out.vwv, VWV(5), PTR_DIFF(params, trans->out.params.data));
1135 
1136 		SSVAL(this_req->out.vwv, VWV(6), this_data);
1137 		SSVAL(this_req->out.vwv, VWV(7), align1 + align2 +
1138 		      PTR_DIFF(this_req->out.data + this_param, this_req->out.hdr));
1139 		SSVAL(this_req->out.vwv, VWV(8), PTR_DIFF(data, trans->out.data.data));
1140 
1141 		SSVAL(this_req->out.vwv, VWV(9), trans->out.setup_count);
1142 		for (i=0;i<trans->out.setup_count;i++) {
1143 			SSVAL(this_req->out.vwv, VWV(10+i), trans->out.setup[i]);
1144 		}
1145 
1146 		memset(this_req->out.data, 0, align1);
1147 		if (this_param != 0) {
1148 			memcpy(this_req->out.data + align1, params, this_param);
1149 		}
1150 		memset(this_req->out.data+this_param+align1, 0, align2);
1151 		if (this_data != 0) {
1152 			memcpy(this_req->out.data+this_param+align1+align2, data, this_data);
1153 		}
1154 
1155 		params_left -= this_param;
1156 		data_left -= this_data;
1157 		params += this_param;
1158 		data += this_data;
1159 
1160 		smbsrv_send_reply(this_req);
1161 	} while (params_left != 0 || data_left != 0);
1162 }
1163 
1164 
1165 /*
1166   answer a reconstructed trans request
1167 */
reply_trans_complete(struct smbsrv_request * req,uint8_t command,struct smb_trans2 * trans)1168 static void reply_trans_complete(struct smbsrv_request *req, uint8_t command,
1169 				 struct smb_trans2 *trans)
1170 {
1171 	struct trans_op *op;
1172 
1173 	SMBSRV_TALLOC_IO_PTR(op, struct trans_op);
1174 	SMBSRV_SETUP_NTVFS_REQUEST(reply_trans_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1175 
1176 	op->req		= req;
1177 	op->trans	= trans;
1178 	op->command	= command;
1179 	op->op_info	= NULL;
1180 	op->send_fn	= NULL;
1181 
1182 	/* its a full request, give it to the backend */
1183 	if (command == SMBtrans) {
1184 		SMBSRV_CALL_NTVFS_BACKEND(ntvfs_trans(req->ntvfs, trans));
1185 		return;
1186 	} else {
1187 		SMBSRV_CALL_NTVFS_BACKEND(trans2_backend(req, op));
1188 		return;
1189 	}
1190 }
1191 
1192 /*
1193   Reply to an SMBtrans or SMBtrans2 request
1194 */
reply_trans_generic(struct smbsrv_request * req,uint8_t command)1195 static void reply_trans_generic(struct smbsrv_request *req, uint8_t command)
1196 {
1197 	struct smb_trans2 *trans;
1198 	int i;
1199 	uint16_t param_ofs, data_ofs;
1200 	uint16_t param_count, data_count;
1201 	uint16_t param_total, data_total;
1202 
1203 	/* parse request */
1204 	if (req->in.wct < 14) {
1205 		smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1206 		return;
1207 	}
1208 
1209 	trans = talloc(req, struct smb_trans2);
1210 	if (trans == NULL) {
1211 		smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
1212 		return;
1213 	}
1214 
1215 	param_total           = SVAL(req->in.vwv, VWV(0));
1216 	data_total            = SVAL(req->in.vwv, VWV(1));
1217 	trans->in.max_param   = SVAL(req->in.vwv, VWV(2));
1218 	trans->in.max_data    = SVAL(req->in.vwv, VWV(3));
1219 	trans->in.max_setup   = CVAL(req->in.vwv, VWV(4));
1220 	trans->in.flags       = SVAL(req->in.vwv, VWV(5));
1221 	trans->in.timeout     = IVAL(req->in.vwv, VWV(6));
1222 	param_count           = SVAL(req->in.vwv, VWV(9));
1223 	param_ofs             = SVAL(req->in.vwv, VWV(10));
1224 	data_count            = SVAL(req->in.vwv, VWV(11));
1225 	data_ofs              = SVAL(req->in.vwv, VWV(12));
1226 	trans->in.setup_count = CVAL(req->in.vwv, VWV(13));
1227 
1228 	if (req->in.wct != 14 + trans->in.setup_count) {
1229 		smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
1230 		return;
1231 	}
1232 
1233 	/* parse out the setup words */
1234 	trans->in.setup = talloc_array(trans, uint16_t, trans->in.setup_count);
1235 	if (trans->in.setup_count && !trans->in.setup) {
1236 		smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
1237 		return;
1238 	}
1239 	for (i=0;i<trans->in.setup_count;i++) {
1240 		trans->in.setup[i] = SVAL(req->in.vwv, VWV(14+i));
1241 	}
1242 
1243 	if (command == SMBtrans) {
1244 		req_pull_string(req, &trans->in.trans_name, req->in.data, -1, STR_TERMINATE);
1245 	}
1246 
1247 	if (!req_pull_blob(req, req->in.hdr + param_ofs, param_count, &trans->in.params) ||
1248 	    !req_pull_blob(req, req->in.hdr + data_ofs, data_count, &trans->in.data)) {
1249 		smbsrv_send_error(req, NT_STATUS_FOOBAR);
1250 		return;
1251 	}
1252 
1253 	/* is it a partial request? if so, then send a 'send more' message */
1254 	if (param_total > param_count || data_total > data_count) {
1255 		reply_trans_continue(req, command, trans);
1256 		return;
1257 	}
1258 
1259 	reply_trans_complete(req, command, trans);
1260 }
1261 
1262 
1263 /*
1264   Reply to an SMBtranss2 request
1265 */
reply_transs_generic(struct smbsrv_request * req,uint8_t command)1266 static void reply_transs_generic(struct smbsrv_request *req, uint8_t command)
1267 {
1268 	struct smbsrv_trans_partial *tp;
1269 	struct smb_trans2 *trans = NULL;
1270 	uint16_t param_ofs, data_ofs;
1271 	uint16_t param_count, data_count;
1272 	uint16_t param_disp, data_disp;
1273 	uint16_t param_total, data_total;
1274 	DATA_BLOB params, data;
1275 
1276 	/* parse request */
1277 	if (req->in.wct < 8) {
1278 		smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1279 		return;
1280 	}
1281 
1282 	for (tp=req->smb_conn->trans_partial;tp;tp=tp->next) {
1283 		if (tp->command == command &&
1284 		    SVAL(tp->req->in.hdr, HDR_MID) == SVAL(req->in.hdr, HDR_MID)) {
1285 /* TODO: check the VUID, PID and TID too? */
1286 			break;
1287 		}
1288 	}
1289 
1290 	if (tp == NULL) {
1291 		smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1292 		return;
1293 	}
1294 
1295 	trans = tp->trans;
1296 
1297 	param_total           = SVAL(req->in.vwv, VWV(0));
1298 	data_total            = SVAL(req->in.vwv, VWV(1));
1299 	param_count           = SVAL(req->in.vwv, VWV(2));
1300 	param_ofs             = SVAL(req->in.vwv, VWV(3));
1301 	param_disp            = SVAL(req->in.vwv, VWV(4));
1302 	data_count            = SVAL(req->in.vwv, VWV(5));
1303 	data_ofs              = SVAL(req->in.vwv, VWV(6));
1304 	data_disp             = SVAL(req->in.vwv, VWV(7));
1305 
1306 	if (!req_pull_blob(req, req->in.hdr + param_ofs, param_count, &params) ||
1307 	    !req_pull_blob(req, req->in.hdr + data_ofs, data_count, &data)) {
1308 		smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1309 		return;
1310 	}
1311 
1312 	/* only allow contiguous requests */
1313 	if ((param_count != 0 &&
1314 	     param_disp != trans->in.params.length) ||
1315 	    (data_count != 0 &&
1316 	     data_disp != trans->in.data.length)) {
1317 		smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1318 		return;
1319 	}
1320 
1321 	/* add to the existing request */
1322 	if (param_count != 0) {
1323 		trans->in.params.data = talloc_realloc(trans,
1324 							 trans->in.params.data,
1325 							 uint8_t,
1326 							 param_disp + param_count);
1327 		if (trans->in.params.data == NULL) {
1328 			goto failed;
1329 		}
1330 		trans->in.params.length = param_disp + param_count;
1331 	}
1332 
1333 	if (data_count != 0) {
1334 		trans->in.data.data = talloc_realloc(trans,
1335 						       trans->in.data.data,
1336 						       uint8_t,
1337 						       data_disp + data_count);
1338 		if (trans->in.data.data == NULL) {
1339 			goto failed;
1340 		}
1341 		trans->in.data.length = data_disp + data_count;
1342 	}
1343 
1344 	memcpy(trans->in.params.data + param_disp, params.data, params.length);
1345 	memcpy(trans->in.data.data + data_disp, data.data, data.length);
1346 
1347 	/* the sequence number of the reply is taken from the last secondary
1348 	   response */
1349 	tp->req->seq_num = req->seq_num;
1350 
1351 	/* we don't reply to Transs2 requests */
1352 	talloc_free(req);
1353 
1354 	if (trans->in.params.length == param_total &&
1355 	    trans->in.data.length == data_total) {
1356 		/* its now complete */
1357 		DLIST_REMOVE(tp->req->smb_conn->trans_partial, tp);
1358 		reply_trans_complete(tp->req, command, trans);
1359 	}
1360 	return;
1361 
1362 failed:
1363 	smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
1364 	DLIST_REMOVE(req->smb_conn->trans_partial, tp);
1365 	talloc_free(req);
1366 	talloc_free(tp);
1367 }
1368 
1369 
1370 /*
1371   Reply to an SMBtrans2
1372 */
smbsrv_reply_trans2(struct smbsrv_request * req)1373 void smbsrv_reply_trans2(struct smbsrv_request *req)
1374 {
1375 	reply_trans_generic(req, SMBtrans2);
1376 }
1377 
1378 /*
1379   Reply to an SMBtrans
1380 */
smbsrv_reply_trans(struct smbsrv_request * req)1381 void smbsrv_reply_trans(struct smbsrv_request *req)
1382 {
1383 	reply_trans_generic(req, SMBtrans);
1384 }
1385 
1386 /*
1387   Reply to an SMBtranss request
1388 */
smbsrv_reply_transs(struct smbsrv_request * req)1389 void smbsrv_reply_transs(struct smbsrv_request *req)
1390 {
1391 	reply_transs_generic(req, SMBtrans);
1392 }
1393 
1394 /*
1395   Reply to an SMBtranss2 request
1396 */
smbsrv_reply_transs2(struct smbsrv_request * req)1397 void smbsrv_reply_transs2(struct smbsrv_request *req)
1398 {
1399 	reply_transs_generic(req, SMBtrans2);
1400 }
1401