Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : NT transaction handling
4 : Copyright (C) Andrew Tridgell 2003
5 : Copyright (C) James J Myers 2003 <myersjj@samba.org>
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 : /*
21 : This file handles the parsing of transact2 requests
22 : */
23 :
24 : #include "includes.h"
25 : #include "smb_server/smb_server.h"
26 : #include "ntvfs/ntvfs.h"
27 : #include "libcli/raw/libcliraw.h"
28 : #include "libcli/raw/raw_proto.h"
29 : #include "librpc/gen_ndr/ndr_security.h"
30 :
31 : /*
32 : hold the state of a nttrans op while in progress. Needed to allow for async backend
33 : functions.
34 : */
35 : struct nttrans_op {
36 : struct smb_nttrans *trans;
37 : NTSTATUS (*send_fn)(struct nttrans_op *);
38 : void *op_info;
39 : };
40 :
41 :
42 : /* setup a nttrans reply, given the data and params sizes */
43 701 : static NTSTATUS nttrans_setup_reply(struct nttrans_op *op,
44 : struct smb_nttrans *trans,
45 : uint32_t param_size, uint32_t data_size,
46 : uint8_t setup_count)
47 : {
48 701 : trans->out.setup_count = setup_count;
49 701 : if (setup_count != 0) {
50 5 : trans->out.setup = talloc_zero_array(op, uint8_t, setup_count*2);
51 5 : NT_STATUS_HAVE_NO_MEMORY(trans->out.setup);
52 : }
53 701 : trans->out.params = data_blob_talloc(op, NULL, param_size);
54 701 : if (param_size != 0) {
55 690 : NT_STATUS_HAVE_NO_MEMORY(trans->out.params.data);
56 : }
57 701 : trans->out.data = data_blob_talloc(op, NULL, data_size);
58 701 : if (data_size != 0) {
59 0 : NT_STATUS_HAVE_NO_MEMORY(trans->out.data.data);
60 : }
61 701 : return NT_STATUS_OK;
62 : }
63 :
64 : /*
65 : send a nttrans create reply
66 : */
67 60 : static NTSTATUS nttrans_create_send(struct nttrans_op *op)
68 : {
69 60 : union smb_open *io = talloc_get_type(op->op_info, union smb_open);
70 0 : uint8_t *params;
71 0 : NTSTATUS status;
72 :
73 60 : status = nttrans_setup_reply(op, op->trans, 69, 0, 0);
74 60 : NT_STATUS_NOT_OK_RETURN(status);
75 60 : params = op->trans->out.params.data;
76 :
77 60 : SSVAL(params, 0, io->ntcreatex.out.oplock_level);
78 60 : smbsrv_push_fnum(params, 2, io->ntcreatex.out.file.ntvfs);
79 60 : SIVAL(params, 4, io->ntcreatex.out.create_action);
80 60 : SIVAL(params, 8, 0); /* ea error offset */
81 60 : push_nttime(params, 12, io->ntcreatex.out.create_time);
82 60 : push_nttime(params, 20, io->ntcreatex.out.access_time);
83 60 : push_nttime(params, 28, io->ntcreatex.out.write_time);
84 60 : push_nttime(params, 36, io->ntcreatex.out.change_time);
85 60 : SIVAL(params, 44, io->ntcreatex.out.attrib);
86 60 : SBVAL(params, 48, io->ntcreatex.out.alloc_size);
87 60 : SBVAL(params, 56, io->ntcreatex.out.size);
88 60 : SSVAL(params, 64, io->ntcreatex.out.file_type);
89 60 : SSVAL(params, 66, io->ntcreatex.out.ipc_state);
90 60 : SCVAL(params, 68, io->ntcreatex.out.is_directory);
91 :
92 60 : return NT_STATUS_OK;
93 : }
94 :
95 : /*
96 : parse NTTRANS_CREATE request
97 : */
98 85 : static NTSTATUS nttrans_create(struct smbsrv_request *req,
99 : struct nttrans_op *op)
100 : {
101 85 : struct smb_nttrans *trans = op->trans;
102 0 : union smb_open *io;
103 0 : uint16_t fname_len;
104 0 : uint32_t sd_length, ea_length;
105 0 : NTSTATUS status;
106 0 : uint8_t *params;
107 0 : enum ndr_err_code ndr_err;
108 :
109 85 : if (trans->in.params.length < 54) {
110 0 : return NT_STATUS_INVALID_PARAMETER;
111 : }
112 :
113 : /* parse the request */
114 85 : io = talloc(op, union smb_open);
115 85 : NT_STATUS_HAVE_NO_MEMORY(io);
116 :
117 85 : io->ntcreatex.level = RAW_OPEN_NTTRANS_CREATE;
118 :
119 85 : params = trans->in.params.data;
120 :
121 85 : io->ntcreatex.in.flags = IVAL(params, 0);
122 85 : io->ntcreatex.in.root_fid.ntvfs = smbsrv_pull_fnum(req, params, 4);
123 85 : io->ntcreatex.in.access_mask = IVAL(params, 8);
124 85 : io->ntcreatex.in.alloc_size = BVAL(params, 12);
125 85 : io->ntcreatex.in.file_attr = IVAL(params, 20);
126 85 : io->ntcreatex.in.share_access = IVAL(params, 24);
127 85 : io->ntcreatex.in.open_disposition = IVAL(params, 28);
128 85 : io->ntcreatex.in.create_options = IVAL(params, 32);
129 85 : sd_length = IVAL(params, 36);
130 85 : ea_length = IVAL(params, 40);
131 85 : fname_len = IVAL(params, 44);
132 85 : io->ntcreatex.in.impersonation = IVAL(params, 48);
133 85 : io->ntcreatex.in.security_flags = CVAL(params, 52);
134 85 : io->ntcreatex.in.sec_desc = NULL;
135 85 : io->ntcreatex.in.ea_list = NULL;
136 85 : io->ntcreatex.in.query_maximal_access = false;
137 85 : io->ntcreatex.in.query_on_disk_id = false;
138 85 : io->ntcreatex.in.private_flags = 0;
139 :
140 85 : req_pull_string(&req->in.bufinfo, &io->ntcreatex.in.fname,
141 85 : params + 53,
142 85 : MIN(fname_len+1, trans->in.params.length - 53),
143 : STR_NO_RANGE_CHECK | STR_TERMINATE);
144 85 : if (!io->ntcreatex.in.fname) {
145 0 : return NT_STATUS_INVALID_PARAMETER;
146 : }
147 :
148 85 : if (sd_length > trans->in.data.length ||
149 85 : ea_length > trans->in.data.length ||
150 85 : (sd_length+ea_length) > trans->in.data.length) {
151 0 : return NT_STATUS_INVALID_PARAMETER;
152 : }
153 :
154 : /* this call has an optional security descriptor */
155 85 : if (sd_length != 0) {
156 0 : DATA_BLOB blob;
157 19 : blob.data = trans->in.data.data;
158 19 : blob.length = sd_length;
159 19 : io->ntcreatex.in.sec_desc = talloc(io, struct security_descriptor);
160 19 : if (io->ntcreatex.in.sec_desc == NULL) {
161 0 : return NT_STATUS_NO_MEMORY;
162 : }
163 19 : ndr_err = ndr_pull_struct_blob(&blob, io,
164 19 : io->ntcreatex.in.sec_desc,
165 : (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
166 19 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
167 0 : return ndr_map_error2ntstatus(ndr_err);
168 : }
169 : }
170 :
171 : /* and an optional ea_list */
172 85 : if (ea_length > 4) {
173 0 : DATA_BLOB blob;
174 0 : blob.data = trans->in.data.data + sd_length;
175 0 : blob.length = ea_length;
176 0 : io->ntcreatex.in.ea_list = talloc(io, struct smb_ea_list);
177 0 : if (io->ntcreatex.in.ea_list == NULL) {
178 0 : return NT_STATUS_NO_MEMORY;
179 : }
180 :
181 0 : status = ea_pull_list_chained(&blob, io,
182 0 : &io->ntcreatex.in.ea_list->num_eas,
183 0 : &io->ntcreatex.in.ea_list->eas);
184 0 : if (!NT_STATUS_IS_OK(status)) {
185 0 : return status;
186 : }
187 : }
188 :
189 85 : op->send_fn = nttrans_create_send;
190 85 : op->op_info = io;
191 :
192 85 : return ntvfs_open(req->ntvfs, io);
193 : }
194 :
195 :
196 : /*
197 : send NTTRANS_QUERY_SEC_DESC reply
198 : */
199 572 : static NTSTATUS nttrans_query_sec_desc_send(struct nttrans_op *op)
200 : {
201 572 : union smb_fileinfo *io = talloc_get_type(op->op_info, union smb_fileinfo);
202 0 : uint8_t *params;
203 0 : NTSTATUS status;
204 0 : enum ndr_err_code ndr_err;
205 :
206 572 : status = nttrans_setup_reply(op, op->trans, 4, 0, 0);
207 572 : NT_STATUS_NOT_OK_RETURN(status);
208 572 : params = op->trans->out.params.data;
209 :
210 572 : ndr_err = ndr_push_struct_blob(&op->trans->out.data, op,
211 572 : io->query_secdesc.out.sd,
212 : (ndr_push_flags_fn_t)ndr_push_security_descriptor);
213 572 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
214 0 : return ndr_map_error2ntstatus(ndr_err);
215 : }
216 :
217 572 : SIVAL(params, 0, op->trans->out.data.length);
218 :
219 572 : return NT_STATUS_OK;
220 : }
221 :
222 : /*
223 : parse NTTRANS_QUERY_SEC_DESC request
224 : */
225 572 : static NTSTATUS nttrans_query_sec_desc(struct smbsrv_request *req,
226 : struct nttrans_op *op)
227 : {
228 572 : struct smb_nttrans *trans = op->trans;
229 0 : union smb_fileinfo *io;
230 :
231 572 : if (trans->in.params.length < 8) {
232 0 : return NT_STATUS_INVALID_PARAMETER;
233 : }
234 :
235 : /* parse the request */
236 572 : io = talloc(op, union smb_fileinfo);
237 572 : NT_STATUS_HAVE_NO_MEMORY(io);
238 :
239 572 : io->query_secdesc.level = RAW_FILEINFO_SEC_DESC;
240 572 : io->query_secdesc.in.file.ntvfs = smbsrv_pull_fnum(req, trans->in.params.data, 0);
241 572 : io->query_secdesc.in.secinfo_flags = IVAL(trans->in.params.data, 4);
242 :
243 572 : op->op_info = io;
244 572 : op->send_fn = nttrans_query_sec_desc_send;
245 :
246 572 : SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(io->query_secdesc.in.file.ntvfs);
247 572 : return ntvfs_qfileinfo(req->ntvfs, io);
248 : }
249 :
250 :
251 : /*
252 : parse NTTRANS_SET_SEC_DESC request
253 : */
254 531 : static NTSTATUS nttrans_set_sec_desc(struct smbsrv_request *req,
255 : struct nttrans_op *op)
256 : {
257 531 : struct smb_nttrans *trans = op->trans;
258 0 : union smb_setfileinfo *io;
259 0 : enum ndr_err_code ndr_err;
260 :
261 531 : if (trans->in.params.length < 8) {
262 0 : return NT_STATUS_INVALID_PARAMETER;
263 : }
264 :
265 : /* parse the request */
266 531 : io = talloc(req, union smb_setfileinfo);
267 531 : NT_STATUS_HAVE_NO_MEMORY(io);
268 :
269 531 : io->set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
270 531 : io->set_secdesc.in.file.ntvfs = smbsrv_pull_fnum(req, trans->in.params.data, 0);
271 531 : io->set_secdesc.in.secinfo_flags = IVAL(trans->in.params.data, 4);
272 :
273 531 : io->set_secdesc.in.sd = talloc(io, struct security_descriptor);
274 531 : NT_STATUS_HAVE_NO_MEMORY(io->set_secdesc.in.sd);
275 :
276 531 : ndr_err = ndr_pull_struct_blob(&trans->in.data, req,
277 531 : io->set_secdesc.in.sd,
278 : (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
279 531 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
280 0 : return ndr_map_error2ntstatus(ndr_err);
281 : }
282 :
283 531 : SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(io->set_secdesc.in.file.ntvfs);
284 530 : return ntvfs_setfileinfo(req->ntvfs, io);
285 : }
286 :
287 :
288 : /* parse NTTRANS_RENAME request
289 : */
290 2 : static NTSTATUS nttrans_rename(struct smbsrv_request *req,
291 : struct nttrans_op *op)
292 : {
293 2 : struct smb_nttrans *trans = op->trans;
294 0 : union smb_rename *io;
295 :
296 2 : if (trans->in.params.length < 5) {
297 0 : return NT_STATUS_INVALID_PARAMETER;
298 : }
299 :
300 : /* parse the request */
301 2 : io = talloc(req, union smb_rename);
302 2 : NT_STATUS_HAVE_NO_MEMORY(io);
303 :
304 2 : io->nttrans.level = RAW_RENAME_NTTRANS;
305 2 : io->nttrans.in.file.ntvfs = smbsrv_pull_fnum(req, trans->in.params.data, 0);
306 2 : io->nttrans.in.flags = SVAL(trans->in.params.data, 2);
307 :
308 2 : smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 4,
309 : &io->nttrans.in.new_name,
310 : STR_TERMINATE);
311 2 : if (!io->nttrans.in.new_name) {
312 0 : return NT_STATUS_INVALID_PARAMETER;
313 : }
314 :
315 2 : SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(io->nttrans.in.file.ntvfs);
316 1 : return ntvfs_rename(req->ntvfs, io);
317 : }
318 :
319 : /*
320 : parse NTTRANS_IOCTL send
321 : */
322 5 : static NTSTATUS nttrans_ioctl_send(struct nttrans_op *op)
323 : {
324 5 : union smb_ioctl *info = talloc_get_type(op->op_info, union smb_ioctl);
325 0 : NTSTATUS status;
326 :
327 : /*
328 : * we pass 0 as data_count here,
329 : * because we reuse the DATA_BLOB from the smb_ioctl
330 : * struct
331 : */
332 5 : status = nttrans_setup_reply(op, op->trans, 0, 0, 1);
333 5 : NT_STATUS_NOT_OK_RETURN(status);
334 :
335 5 : op->trans->out.setup[0] = 0;
336 5 : op->trans->out.data = info->ntioctl.out.blob;
337 :
338 5 : return NT_STATUS_OK;
339 : }
340 :
341 :
342 : /*
343 : parse NTTRANS_IOCTL request
344 : */
345 10 : static NTSTATUS nttrans_ioctl(struct smbsrv_request *req,
346 : struct nttrans_op *op)
347 : {
348 10 : struct smb_nttrans *trans = op->trans;
349 0 : union smb_ioctl *nt;
350 :
351 : /* should have at least 4 setup words */
352 10 : if (trans->in.setup_count != 4) {
353 0 : return NT_STATUS_INVALID_PARAMETER;
354 : }
355 :
356 10 : nt = talloc(op, union smb_ioctl);
357 10 : NT_STATUS_HAVE_NO_MEMORY(nt);
358 :
359 10 : nt->ntioctl.level = RAW_IOCTL_NTIOCTL;
360 10 : nt->ntioctl.in.function = IVAL(trans->in.setup, 0);
361 10 : nt->ntioctl.in.file.ntvfs = smbsrv_pull_fnum(req, (uint8_t *)trans->in.setup, 4);
362 10 : nt->ntioctl.in.fsctl = CVAL(trans->in.setup, 6);
363 10 : nt->ntioctl.in.filter = CVAL(trans->in.setup, 7);
364 10 : nt->ntioctl.in.max_data = trans->in.max_data;
365 10 : nt->ntioctl.in.blob = trans->in.data;
366 :
367 10 : op->op_info = nt;
368 10 : op->send_fn = nttrans_ioctl_send;
369 :
370 10 : SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(nt->ntioctl.in.file.ntvfs);
371 9 : return ntvfs_ioctl(req->ntvfs, nt);
372 : }
373 :
374 :
375 : /*
376 : send NTTRANS_NOTIFY_CHANGE reply
377 : */
378 64 : static NTSTATUS nttrans_notify_change_send(struct nttrans_op *op)
379 : {
380 64 : union smb_notify *info = talloc_get_type(op->op_info, union smb_notify);
381 64 : size_t size = 0;
382 0 : int i;
383 0 : NTSTATUS status;
384 0 : uint8_t *p;
385 : #define MAX_BYTES_PER_CHAR 3
386 :
387 : /* work out how big the reply buffer could be */
388 363 : for (i=0;i<info->nttrans.out.num_changes;i++) {
389 299 : size += 12 + 3 + (1+strlen(info->nttrans.out.changes[i].name.s)) * MAX_BYTES_PER_CHAR;
390 : }
391 :
392 64 : status = nttrans_setup_reply(op, op->trans, size, 0, 0);
393 64 : NT_STATUS_NOT_OK_RETURN(status);
394 64 : p = op->trans->out.params.data;
395 :
396 : /* construct the changes buffer */
397 363 : for (i=0;i<info->nttrans.out.num_changes;i++) {
398 0 : uint32_t ofs;
399 0 : ssize_t len;
400 :
401 299 : SIVAL(p, 4, info->nttrans.out.changes[i].action);
402 299 : len = push_string(p + 12, info->nttrans.out.changes[i].name.s,
403 299 : op->trans->out.params.length -
404 299 : (p+12 - op->trans->out.params.data), STR_UNICODE);
405 299 : SIVAL(p, 8, len);
406 :
407 299 : ofs = len + 12;
408 :
409 299 : if (ofs & 3) {
410 121 : int pad = 4 - (ofs & 3);
411 121 : memset(p+ofs, 0, pad);
412 121 : ofs += pad;
413 : }
414 :
415 299 : if (i == info->nttrans.out.num_changes-1) {
416 58 : SIVAL(p, 0, 0);
417 : } else {
418 241 : SIVAL(p, 0, ofs);
419 : }
420 :
421 299 : p += ofs;
422 : }
423 :
424 64 : op->trans->out.params.length = p - op->trans->out.params.data;
425 :
426 64 : return NT_STATUS_OK;
427 : }
428 :
429 : /*
430 : parse NTTRANS_NOTIFY_CHANGE request
431 : */
432 567 : static NTSTATUS nttrans_notify_change(struct smbsrv_request *req,
433 : struct nttrans_op *op)
434 : {
435 567 : struct smb_nttrans *trans = op->trans;
436 0 : union smb_notify *info;
437 :
438 : /* should have at least 4 setup words */
439 567 : if (trans->in.setup_count != 4) {
440 0 : return NT_STATUS_INVALID_PARAMETER;
441 : }
442 :
443 567 : info = talloc(op, union smb_notify);
444 567 : NT_STATUS_HAVE_NO_MEMORY(info);
445 :
446 567 : info->nttrans.level = RAW_NOTIFY_NTTRANS;
447 567 : info->nttrans.in.completion_filter = IVAL(trans->in.setup, 0);
448 567 : info->nttrans.in.file.ntvfs = smbsrv_pull_fnum(req, (uint8_t *)trans->in.setup, 4);
449 567 : info->nttrans.in.recursive = SVAL(trans->in.setup, 6);
450 567 : info->nttrans.in.buffer_size = trans->in.max_param;
451 :
452 567 : op->op_info = info;
453 567 : op->send_fn = nttrans_notify_change_send;
454 :
455 567 : SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(info->nttrans.in.file.ntvfs);
456 563 : return ntvfs_notify(req->ntvfs, info);
457 : }
458 :
459 : /*
460 : backend for nttrans requests
461 : */
462 1767 : static NTSTATUS nttrans_backend(struct smbsrv_request *req,
463 : struct nttrans_op *op)
464 : {
465 : /* the nttrans command is in function */
466 1767 : switch (op->trans->in.function) {
467 85 : case NT_TRANSACT_CREATE:
468 85 : return nttrans_create(req, op);
469 10 : case NT_TRANSACT_IOCTL:
470 10 : return nttrans_ioctl(req, op);
471 2 : case NT_TRANSACT_RENAME:
472 2 : return nttrans_rename(req, op);
473 572 : case NT_TRANSACT_QUERY_SECURITY_DESC:
474 572 : return nttrans_query_sec_desc(req, op);
475 531 : case NT_TRANSACT_SET_SECURITY_DESC:
476 531 : return nttrans_set_sec_desc(req, op);
477 567 : case NT_TRANSACT_NOTIFY_CHANGE:
478 567 : return nttrans_notify_change(req, op);
479 : }
480 :
481 : /* an unknown nttrans command */
482 0 : return NT_STATUS_DOS(ERRSRV, ERRerror);
483 : }
484 :
485 :
486 1767 : static void reply_nttrans_send(struct ntvfs_request *ntvfs)
487 : {
488 0 : struct smbsrv_request *req;
489 0 : uint32_t params_left, data_left;
490 0 : uint8_t *params, *data;
491 0 : struct smb_nttrans *trans;
492 0 : struct nttrans_op *op;
493 :
494 1767 : SMBSRV_CHECK_ASYNC_STATUS(op, struct nttrans_op);
495 :
496 1232 : trans = op->trans;
497 :
498 : /* if this function needs work to form the nttrans reply buffer, then
499 : call that now */
500 1232 : if (op->send_fn != NULL) {
501 0 : NTSTATUS status;
502 701 : status = op->send_fn(op);
503 701 : if (!NT_STATUS_IS_OK(status)) {
504 0 : smbsrv_send_error(req, status);
505 0 : return;
506 : }
507 : }
508 :
509 1232 : smbsrv_setup_reply(req, 18 + trans->out.setup_count, 0);
510 :
511 : /* note that we don't check the max_setup count (matching w2k3
512 : behaviour) */
513 :
514 1232 : if (trans->out.params.length > trans->in.max_param) {
515 0 : smbsrv_setup_error(req, NT_STATUS_BUFFER_TOO_SMALL);
516 0 : trans->out.params.length = trans->in.max_param;
517 : }
518 1232 : if (trans->out.data.length > trans->in.max_data) {
519 0 : smbsrv_setup_error(req, NT_STATUS_BUFFER_TOO_SMALL);
520 0 : trans->out.data.length = trans->in.max_data;
521 : }
522 :
523 1232 : params_left = trans->out.params.length;
524 1232 : data_left = trans->out.data.length;
525 1232 : params = trans->out.params.data;
526 1232 : data = trans->out.data.data;
527 :
528 : /* we need to divide up the reply into chunks that fit into
529 : the negotiated buffer size */
530 0 : do {
531 0 : uint32_t this_data, this_param, max_bytes;
532 1232 : unsigned int align1 = 1, align2 = (params_left ? 2 : 0);
533 0 : struct smbsrv_request *this_req;
534 :
535 1232 : max_bytes = req_max_data(req) - (align1 + align2);
536 :
537 1232 : this_param = params_left;
538 1232 : if (this_param > max_bytes) {
539 0 : this_param = max_bytes;
540 : }
541 1232 : max_bytes -= this_param;
542 :
543 1232 : this_data = data_left;
544 1232 : if (this_data > max_bytes) {
545 0 : this_data = max_bytes;
546 : }
547 :
548 : /* don't destroy unless this is the last chunk */
549 1232 : if (params_left - this_param != 0 ||
550 0 : data_left - this_data != 0) {
551 0 : this_req = smbsrv_setup_secondary_request(req);
552 : } else {
553 1232 : this_req = req;
554 : }
555 :
556 1232 : req_grow_data(this_req, this_param + this_data + (align1 + align2));
557 :
558 1232 : SSVAL(this_req->out.vwv, 0, 0); /* reserved */
559 1232 : SCVAL(this_req->out.vwv, 2, 0); /* reserved */
560 1232 : SIVAL(this_req->out.vwv, 3, trans->out.params.length);
561 1232 : SIVAL(this_req->out.vwv, 7, trans->out.data.length);
562 :
563 1232 : SIVAL(this_req->out.vwv, 11, this_param);
564 1232 : SIVAL(this_req->out.vwv, 15, align1 + PTR_DIFF(this_req->out.data, this_req->out.hdr));
565 1232 : SIVAL(this_req->out.vwv, 19, PTR_DIFF(params, trans->out.params.data));
566 :
567 1232 : SIVAL(this_req->out.vwv, 23, this_data);
568 1232 : SIVAL(this_req->out.vwv, 27, align1 + align2 +
569 : PTR_DIFF(this_req->out.data + this_param, this_req->out.hdr));
570 1232 : SIVAL(this_req->out.vwv, 31, PTR_DIFF(data, trans->out.data.data));
571 :
572 1232 : SCVAL(this_req->out.vwv, 35, trans->out.setup_count);
573 1232 : if (trans->out.setup_count > 0) {
574 5 : memcpy((char *)(this_req->out.vwv) + VWV(18),
575 5 : trans->out.setup,
576 5 : sizeof(uint16_t) * trans->out.setup_count);
577 : }
578 1232 : memset(this_req->out.data, 0, align1);
579 1232 : if (this_param != 0) {
580 690 : memcpy(this_req->out.data + align1, params, this_param);
581 : }
582 1232 : memset(this_req->out.data+this_param+align1, 0, align2);
583 1232 : if (this_data != 0) {
584 572 : memcpy(this_req->out.data+this_param+align1+align2,
585 : data, this_data);
586 : }
587 :
588 1232 : params_left -= this_param;
589 1232 : data_left -= this_data;
590 1232 : params += this_param;
591 1232 : data += this_data;
592 :
593 1232 : smbsrv_send_reply(this_req);
594 1232 : } while (params_left != 0 || data_left != 0);
595 : }
596 :
597 : /*
598 : send a continue request
599 : */
600 0 : static void reply_nttrans_continue(struct smbsrv_request *req, struct smb_nttrans *trans)
601 : {
602 0 : struct smbsrv_request *req2;
603 0 : struct smbsrv_trans_partial *tp;
604 0 : int count;
605 :
606 : /* make sure they don't flood us */
607 0 : for (count=0,tp=req->smb_conn->trans_partial;tp;tp=tp->next) count++;
608 0 : if (count > 100) {
609 0 : smbsrv_send_error(req, NT_STATUS_INSUFFICIENT_RESOURCES);
610 0 : return;
611 : }
612 :
613 0 : tp = talloc(req, struct smbsrv_trans_partial);
614 :
615 0 : tp->req = req;
616 0 : tp->u.nttrans = trans;
617 0 : tp->command = SMBnttrans;
618 :
619 0 : DLIST_ADD(req->smb_conn->trans_partial, tp);
620 0 : talloc_set_destructor(tp, smbsrv_trans_partial_destructor);
621 :
622 0 : req2 = smbsrv_setup_secondary_request(req);
623 :
624 : /* send a 'please continue' reply */
625 0 : smbsrv_setup_reply(req2, 0, 0);
626 0 : smbsrv_send_reply(req2);
627 : }
628 :
629 :
630 : /*
631 : answer a reconstructed trans request
632 : */
633 1767 : static void reply_nttrans_complete(struct smbsrv_request *req, struct smb_nttrans *trans)
634 : {
635 0 : struct nttrans_op *op;
636 :
637 1767 : SMBSRV_TALLOC_IO_PTR(op, struct nttrans_op);
638 1767 : SMBSRV_SETUP_NTVFS_REQUEST(reply_nttrans_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
639 :
640 1767 : op->trans = trans;
641 1767 : op->op_info = NULL;
642 1767 : op->send_fn = NULL;
643 :
644 : /* its a full request, give it to the backend */
645 1767 : ZERO_STRUCT(trans->out);
646 1767 : SMBSRV_CALL_NTVFS_BACKEND(nttrans_backend(req, op));
647 : }
648 :
649 :
650 : /****************************************************************************
651 : Reply to an SMBnttrans request
652 : ****************************************************************************/
653 1767 : void smbsrv_reply_nttrans(struct smbsrv_request *req)
654 : {
655 0 : struct smb_nttrans *trans;
656 0 : uint32_t param_ofs, data_ofs;
657 0 : uint32_t param_count, data_count;
658 0 : uint32_t param_total, data_total;
659 :
660 : /* parse request */
661 1767 : if (req->in.wct < 19) {
662 0 : smbsrv_send_error(req, NT_STATUS_FOOBAR);
663 0 : return;
664 : }
665 :
666 1767 : trans = talloc(req, struct smb_nttrans);
667 1767 : if (trans == NULL) {
668 0 : smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
669 0 : return;
670 : }
671 :
672 1767 : trans->in.max_setup = CVAL(req->in.vwv, 0);
673 1767 : param_total = IVAL(req->in.vwv, 3);
674 1767 : data_total = IVAL(req->in.vwv, 7);
675 1767 : trans->in.max_param = IVAL(req->in.vwv, 11);
676 1767 : trans->in.max_data = IVAL(req->in.vwv, 15);
677 1767 : param_count = IVAL(req->in.vwv, 19);
678 1767 : param_ofs = IVAL(req->in.vwv, 23);
679 1767 : data_count = IVAL(req->in.vwv, 27);
680 1767 : data_ofs = IVAL(req->in.vwv, 31);
681 1767 : trans->in.setup_count= CVAL(req->in.vwv, 35);
682 1767 : trans->in.function = SVAL(req->in.vwv, 36);
683 :
684 1767 : if (req->in.wct != 19 + trans->in.setup_count) {
685 0 : smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
686 0 : return;
687 : }
688 :
689 : /* parse out the setup words */
690 1767 : trans->in.setup = talloc_array(req, uint8_t, trans->in.setup_count*2);
691 1767 : if (!trans->in.setup) {
692 0 : smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
693 0 : return;
694 : }
695 1767 : memcpy(trans->in.setup, (char *)(req->in.vwv) + VWV(19),
696 1767 : sizeof(uint16_t) * trans->in.setup_count);
697 :
698 1767 : if (!req_pull_blob(&req->in.bufinfo, req->in.hdr + param_ofs, param_count, &trans->in.params) ||
699 1767 : !req_pull_blob(&req->in.bufinfo, req->in.hdr + data_ofs, data_count, &trans->in.data)) {
700 0 : smbsrv_send_error(req, NT_STATUS_FOOBAR);
701 0 : return;
702 : }
703 :
704 : /* is it a partial request? if so, then send a 'send more' message */
705 1767 : if (param_total > param_count || data_total > data_count) {
706 0 : reply_nttrans_continue(req, trans);
707 0 : return;
708 : }
709 :
710 1767 : reply_nttrans_complete(req, trans);
711 : }
712 :
713 :
714 : /****************************************************************************
715 : Reply to an SMBnttranss request
716 : ****************************************************************************/
717 0 : void smbsrv_reply_nttranss(struct smbsrv_request *req)
718 : {
719 0 : struct smbsrv_trans_partial *tp;
720 0 : struct smb_nttrans *trans = NULL;
721 0 : uint32_t param_ofs, data_ofs;
722 0 : uint32_t param_count, data_count;
723 0 : uint32_t param_disp, data_disp;
724 0 : uint32_t param_total, data_total;
725 0 : DATA_BLOB params, data;
726 :
727 : /* parse request */
728 0 : if (req->in.wct != 18) {
729 0 : smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
730 0 : return;
731 : }
732 :
733 0 : for (tp=req->smb_conn->trans_partial;tp;tp=tp->next) {
734 0 : if (tp->command == SMBnttrans &&
735 0 : SVAL(tp->req->in.hdr, HDR_MID) == SVAL(req->in.hdr, HDR_MID)) {
736 : /* TODO: check the VUID, PID and TID too? */
737 0 : break;
738 : }
739 : }
740 :
741 0 : if (tp == NULL) {
742 0 : smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
743 0 : return;
744 : }
745 :
746 0 : trans = tp->u.nttrans;
747 :
748 0 : param_total = IVAL(req->in.vwv, 3);
749 0 : data_total = IVAL(req->in.vwv, 7);
750 0 : param_count = IVAL(req->in.vwv, 11);
751 0 : param_ofs = IVAL(req->in.vwv, 15);
752 0 : param_disp = IVAL(req->in.vwv, 19);
753 0 : data_count = IVAL(req->in.vwv, 23);
754 0 : data_ofs = IVAL(req->in.vwv, 27);
755 0 : data_disp = IVAL(req->in.vwv, 31);
756 :
757 0 : if (!req_pull_blob(&req->in.bufinfo, req->in.hdr + param_ofs, param_count, ¶ms) ||
758 0 : !req_pull_blob(&req->in.bufinfo, req->in.hdr + data_ofs, data_count, &data)) {
759 0 : smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
760 0 : return;
761 : }
762 :
763 : /* only allow contiguous requests */
764 0 : if ((param_count != 0 &&
765 0 : param_disp != trans->in.params.length) ||
766 0 : (data_count != 0 &&
767 0 : data_disp != trans->in.data.length)) {
768 0 : smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
769 0 : return;
770 : }
771 :
772 : /* add to the existing request */
773 0 : if (param_count != 0) {
774 0 : trans->in.params.data = talloc_realloc(trans,
775 : trans->in.params.data,
776 : uint8_t,
777 : param_disp + param_count);
778 0 : if (trans->in.params.data == NULL) {
779 0 : smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
780 0 : return;
781 : }
782 0 : trans->in.params.length = param_disp + param_count;
783 : }
784 :
785 0 : if (data_count != 0) {
786 0 : trans->in.data.data = talloc_realloc(trans,
787 : trans->in.data.data,
788 : uint8_t,
789 : data_disp + data_count);
790 0 : if (trans->in.data.data == NULL) {
791 0 : smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
792 0 : return;
793 : }
794 0 : trans->in.data.length = data_disp + data_count;
795 : }
796 :
797 0 : memcpy(trans->in.params.data + param_disp, params.data, params.length);
798 0 : memcpy(trans->in.data.data + data_disp, data.data, data.length);
799 :
800 : /* the sequence number of the reply is taken from the last secondary
801 : response */
802 0 : tp->req->seq_num = req->seq_num;
803 :
804 : /* we don't reply to Transs2 requests */
805 0 : talloc_free(req);
806 :
807 0 : if (trans->in.params.length == param_total &&
808 0 : trans->in.data.length == data_total) {
809 : /* its now complete */
810 0 : req = tp->req;
811 0 : talloc_free(tp);
812 0 : reply_nttrans_complete(req, trans);
813 : }
814 0 : return;
815 : }
|