2 Unix SMB/CIFS implementation.
3 Main SMB reply routines
4 Copyright (C) Andrew Tridgell 1992-2003
5 Copyright (C) James J Myers 2003 <myersjj@samba.org>
6 Copyright (C) Stefan Metzmacher 2006
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 This file handles most of the reply_ calls that the server
23 makes to handle specific SMB commands
27 #include "smb_server/smb_server.h"
28 #include "ntvfs/ntvfs.h"
29 #include "librpc/gen_ndr/ndr_nbt.h"
32 /****************************************************************************
33 Reply to a simple request (async send)
34 ****************************************************************************/
35 static void reply_simple_send(struct ntvfs_request *ntvfs)
37 struct smbsrv_request *req;
39 SMBSRV_CHECK_ASYNC_STATUS_SIMPLE;
41 smbsrv_setup_reply(req, 0, 0);
42 smbsrv_send_reply(req);
46 /****************************************************************************
48 ****************************************************************************/
49 void smbsrv_reply_tcon(struct smbsrv_request *req)
56 SMBSRV_CHECK_WCT(req, 0);
58 con.tcon.level = RAW_TCON_TCON;
61 p += req_pull_ascii4(&req->in.bufinfo, &con.tcon.in.service, p, STR_TERMINATE);
62 p += req_pull_ascii4(&req->in.bufinfo, &con.tcon.in.password, p, STR_TERMINATE);
63 p += req_pull_ascii4(&req->in.bufinfo, &con.tcon.in.dev, p, STR_TERMINATE);
65 if (!con.tcon.in.service || !con.tcon.in.password || !con.tcon.in.dev) {
66 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
71 status = smbsrv_tcon_backend(req, &con);
73 if (!NT_STATUS_IS_OK(status)) {
74 smbsrv_send_error(req, status);
79 smbsrv_setup_reply(req, 2, 0);
81 SSVAL(req->out.vwv, VWV(0), con.tcon.out.max_xmit);
82 SSVAL(req->out.vwv, VWV(1), con.tcon.out.tid);
83 SSVAL(req->out.hdr, HDR_TID, req->tcon->tid);
85 smbsrv_send_reply(req);
89 /****************************************************************************
90 Reply to a tcon and X.
91 ****************************************************************************/
92 void smbsrv_reply_tcon_and_X(struct smbsrv_request *req)
99 con.tconx.level = RAW_TCON_TCONX;
102 SMBSRV_CHECK_WCT(req, 4);
104 con.tconx.in.flags = SVAL(req->in.vwv, VWV(2));
105 passlen = SVAL(req->in.vwv, VWV(3));
109 if (!req_pull_blob(&req->in.bufinfo, p, passlen, &con.tconx.in.password)) {
110 smbsrv_send_error(req, NT_STATUS_ILL_FORMED_PASSWORD);
115 p += req_pull_string(&req->in.bufinfo, &con.tconx.in.path, p, -1, STR_TERMINATE);
116 p += req_pull_string(&req->in.bufinfo, &con.tconx.in.device, p, -1, STR_ASCII);
118 if (!con.tconx.in.path || !con.tconx.in.device) {
119 smbsrv_send_error(req, NT_STATUS_BAD_DEVICE_TYPE);
124 status = smbsrv_tcon_backend(req, &con);
126 if (!NT_STATUS_IS_OK(status)) {
127 smbsrv_send_error(req, status);
131 /* construct reply - two variants */
132 if (req->smb_conn->negotiate.protocol < PROTOCOL_NT1) {
133 smbsrv_setup_reply(req, 2, 0);
135 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
136 SSVAL(req->out.vwv, VWV(1), 0);
138 req_push_str(req, NULL, con.tconx.out.dev_type, -1, STR_TERMINATE|STR_ASCII);
140 smbsrv_setup_reply(req, 3, 0);
142 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
143 SSVAL(req->out.vwv, VWV(1), 0);
144 SSVAL(req->out.vwv, VWV(2), con.tconx.out.options);
146 req_push_str(req, NULL, con.tconx.out.dev_type, -1, STR_TERMINATE|STR_ASCII);
147 req_push_str(req, NULL, con.tconx.out.fs_type, -1, STR_TERMINATE);
150 /* set the incoming and outgoing tid to the just created one */
151 SSVAL(req->in.hdr, HDR_TID, con.tconx.out.tid);
152 SSVAL(req->out.hdr,HDR_TID, con.tconx.out.tid);
154 smbsrv_chain_reply(req);
158 /****************************************************************************
159 Reply to an unknown request
160 ****************************************************************************/
161 void smbsrv_reply_unknown(struct smbsrv_request *req)
165 type = CVAL(req->in.hdr, HDR_COM);
167 DEBUG(0,("unknown command type %d (0x%X)\n", type, type));
169 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRunknownsmb));
173 /****************************************************************************
174 Reply to an ioctl (async reply)
175 ****************************************************************************/
176 static void reply_ioctl_send(struct ntvfs_request *ntvfs)
178 struct smbsrv_request *req;
181 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_ioctl);
183 /* the +1 is for nicer alignment */
184 smbsrv_setup_reply(req, 8, io->ioctl.out.blob.length+1);
185 SSVAL(req->out.vwv, VWV(1), io->ioctl.out.blob.length);
186 SSVAL(req->out.vwv, VWV(5), io->ioctl.out.blob.length);
187 SSVAL(req->out.vwv, VWV(6), PTR_DIFF(req->out.data, req->out.hdr) + 1);
189 memcpy(req->out.data+1, io->ioctl.out.blob.data, io->ioctl.out.blob.length);
191 smbsrv_send_reply(req);
194 /****************************************************************************
196 ****************************************************************************/
197 void smbsrv_reply_ioctl(struct smbsrv_request *req)
202 SMBSRV_CHECK_WCT(req, 3);
203 SMBSRV_TALLOC_IO_PTR(io, union smb_ioctl);
204 SMBSRV_SETUP_NTVFS_REQUEST(reply_ioctl_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
206 io->ioctl.level = RAW_IOCTL_IOCTL;
207 io->ioctl.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
208 io->ioctl.in.request = IVAL(req->in.vwv, VWV(1));
210 SMBSRV_CHECK_FILE_HANDLE_ERROR(io->ioctl.in.file.ntvfs,
211 NT_STATUS_DOS(ERRSRV, ERRerror));
212 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_ioctl(req->ntvfs, io));
216 /****************************************************************************
218 ****************************************************************************/
219 void smbsrv_reply_chkpth(struct smbsrv_request *req)
221 union smb_chkpath *io;
223 SMBSRV_TALLOC_IO_PTR(io, union smb_chkpath);
224 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
226 req_pull_ascii4(&req->in.bufinfo, &io->chkpath.in.path, req->in.data, STR_TERMINATE);
228 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_chkpath(req->ntvfs, io));
231 /****************************************************************************
232 Reply to a getatr (async reply)
233 ****************************************************************************/
234 static void reply_getatr_send(struct ntvfs_request *ntvfs)
236 struct smbsrv_request *req;
237 union smb_fileinfo *st;
239 SMBSRV_CHECK_ASYNC_STATUS(st, union smb_fileinfo);
241 /* construct reply */
242 smbsrv_setup_reply(req, 10, 0);
244 SSVAL(req->out.vwv, VWV(0), st->getattr.out.attrib);
245 srv_push_dos_date3(req->smb_conn, req->out.vwv, VWV(1), st->getattr.out.write_time);
246 SIVAL(req->out.vwv, VWV(3), st->getattr.out.size);
248 SMBSRV_VWV_RESERVED(5, 5);
250 smbsrv_send_reply(req);
254 /****************************************************************************
256 ****************************************************************************/
257 void smbsrv_reply_getatr(struct smbsrv_request *req)
259 union smb_fileinfo *st;
261 SMBSRV_TALLOC_IO_PTR(st, union smb_fileinfo);
262 SMBSRV_SETUP_NTVFS_REQUEST(reply_getatr_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
264 st->getattr.level = RAW_FILEINFO_GETATTR;
267 req_pull_ascii4(&req->in.bufinfo, &st->getattr.in.file.path, req->in.data, STR_TERMINATE);
268 if (!st->getattr.in.file.path) {
269 smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
273 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_qpathinfo(req->ntvfs, st));
277 /****************************************************************************
279 ****************************************************************************/
280 void smbsrv_reply_setatr(struct smbsrv_request *req)
282 union smb_setfileinfo *st;
285 SMBSRV_CHECK_WCT(req, 8);
286 SMBSRV_TALLOC_IO_PTR(st, union smb_setfileinfo);
287 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
289 st->setattr.level = RAW_SFILEINFO_SETATTR;
290 st->setattr.in.attrib = SVAL(req->in.vwv, VWV(0));
291 st->setattr.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(1));
293 req_pull_ascii4(&req->in.bufinfo, &st->setattr.in.file.path, req->in.data, STR_TERMINATE);
295 if (!st->setattr.in.file.path) {
296 smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
300 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_setpathinfo(req->ntvfs, st));
304 /****************************************************************************
305 Reply to a dskattr (async reply)
306 ****************************************************************************/
307 static void reply_dskattr_send(struct ntvfs_request *ntvfs)
309 struct smbsrv_request *req;
310 union smb_fsinfo *fs;
312 SMBSRV_CHECK_ASYNC_STATUS(fs, union smb_fsinfo);
314 /* construct reply */
315 smbsrv_setup_reply(req, 5, 0);
317 SSVAL(req->out.vwv, VWV(0), fs->dskattr.out.units_total);
318 SSVAL(req->out.vwv, VWV(1), fs->dskattr.out.blocks_per_unit);
319 SSVAL(req->out.vwv, VWV(2), fs->dskattr.out.block_size);
320 SSVAL(req->out.vwv, VWV(3), fs->dskattr.out.units_free);
322 SMBSRV_VWV_RESERVED(4, 1);
324 smbsrv_send_reply(req);
328 /****************************************************************************
330 ****************************************************************************/
331 void smbsrv_reply_dskattr(struct smbsrv_request *req)
333 union smb_fsinfo *fs;
335 SMBSRV_TALLOC_IO_PTR(fs, union smb_fsinfo);
336 SMBSRV_SETUP_NTVFS_REQUEST(reply_dskattr_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
338 fs->dskattr.level = RAW_QFS_DSKATTR;
340 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_fsinfo(req->ntvfs, fs));
344 /****************************************************************************
345 Reply to an open (async reply)
346 ****************************************************************************/
347 static void reply_open_send(struct ntvfs_request *ntvfs)
349 struct smbsrv_request *req;
352 SMBSRV_CHECK_ASYNC_STATUS(oi, union smb_open);
354 /* construct reply */
355 smbsrv_setup_reply(req, 7, 0);
357 smbsrv_push_fnum(req->out.vwv, VWV(0), oi->openold.out.file.ntvfs);
358 SSVAL(req->out.vwv, VWV(1), oi->openold.out.attrib);
359 srv_push_dos_date3(req->smb_conn, req->out.vwv, VWV(2), oi->openold.out.write_time);
360 SIVAL(req->out.vwv, VWV(4), oi->openold.out.size);
361 SSVAL(req->out.vwv, VWV(6), oi->openold.out.rmode);
363 smbsrv_send_reply(req);
366 /****************************************************************************
368 ****************************************************************************/
369 void smbsrv_reply_open(struct smbsrv_request *req)
374 SMBSRV_CHECK_WCT(req, 2);
375 SMBSRV_TALLOC_IO_PTR(oi, union smb_open);
376 SMBSRV_SETUP_NTVFS_REQUEST(reply_open_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
378 oi->openold.level = RAW_OPEN_OPEN;
379 oi->openold.in.open_mode = SVAL(req->in.vwv, VWV(0));
380 oi->openold.in.search_attrs = SVAL(req->in.vwv, VWV(1));
382 req_pull_ascii4(&req->in.bufinfo, &oi->openold.in.fname, req->in.data, STR_TERMINATE);
384 if (!oi->openold.in.fname) {
385 smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
389 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, oi));
393 /****************************************************************************
394 Reply to an open and X (async reply)
395 ****************************************************************************/
396 static void reply_open_and_X_send(struct ntvfs_request *ntvfs)
398 struct smbsrv_request *req;
401 SMBSRV_CHECK_ASYNC_STATUS(oi, union smb_open);
403 /* build the reply */
404 if (oi->openx.in.flags & OPENX_FLAGS_EXTENDED_RETURN) {
405 smbsrv_setup_reply(req, 19, 0);
407 smbsrv_setup_reply(req, 15, 0);
410 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
411 SSVAL(req->out.vwv, VWV(1), 0);
412 smbsrv_push_fnum(req->out.vwv, VWV(2), oi->openx.out.file.ntvfs);
413 SSVAL(req->out.vwv, VWV(3), oi->openx.out.attrib);
414 srv_push_dos_date3(req->smb_conn, req->out.vwv, VWV(4), oi->openx.out.write_time);
415 SIVAL(req->out.vwv, VWV(6), oi->openx.out.size);
416 SSVAL(req->out.vwv, VWV(8), oi->openx.out.access);
417 SSVAL(req->out.vwv, VWV(9), oi->openx.out.ftype);
418 SSVAL(req->out.vwv, VWV(10),oi->openx.out.devstate);
419 SSVAL(req->out.vwv, VWV(11),oi->openx.out.action);
420 SIVAL(req->out.vwv, VWV(12),oi->openx.out.unique_fid);
421 SSVAL(req->out.vwv, VWV(14),0); /* reserved */
422 if (oi->openx.in.flags & OPENX_FLAGS_EXTENDED_RETURN) {
423 SIVAL(req->out.vwv, VWV(15),oi->openx.out.access_mask);
424 SMBSRV_VWV_RESERVED(17, 2);
427 req->chained_fnum = SVAL(req->out.vwv, VWV(2));
429 smbsrv_chain_reply(req);
433 /****************************************************************************
434 Reply to an open and X.
435 ****************************************************************************/
436 void smbsrv_reply_open_and_X(struct smbsrv_request *req)
440 /* parse the request */
441 SMBSRV_CHECK_WCT(req, 15);
442 SMBSRV_TALLOC_IO_PTR(oi, union smb_open);
443 SMBSRV_SETUP_NTVFS_REQUEST(reply_open_and_X_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
445 oi->openx.level = RAW_OPEN_OPENX;
446 oi->openx.in.flags = SVAL(req->in.vwv, VWV(2));
447 oi->openx.in.open_mode = SVAL(req->in.vwv, VWV(3));
448 oi->openx.in.search_attrs = SVAL(req->in.vwv, VWV(4));
449 oi->openx.in.file_attrs = SVAL(req->in.vwv, VWV(5));
450 oi->openx.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(6));
451 oi->openx.in.open_func = SVAL(req->in.vwv, VWV(8));
452 oi->openx.in.size = IVAL(req->in.vwv, VWV(9));
453 oi->openx.in.timeout = IVAL(req->in.vwv, VWV(11));
455 req_pull_ascii4(&req->in.bufinfo, &oi->openx.in.fname, req->in.data, STR_TERMINATE);
457 if (!oi->openx.in.fname) {
458 smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
462 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, oi));
466 /****************************************************************************
467 Reply to a mknew or a create.
468 ****************************************************************************/
469 static void reply_mknew_send(struct ntvfs_request *ntvfs)
471 struct smbsrv_request *req;
474 SMBSRV_CHECK_ASYNC_STATUS(oi, union smb_open);
476 /* build the reply */
477 smbsrv_setup_reply(req, 1, 0);
479 smbsrv_push_fnum(req->out.vwv, VWV(0), oi->mknew.out.file.ntvfs);
481 smbsrv_send_reply(req);
485 /****************************************************************************
486 Reply to a mknew or a create.
487 ****************************************************************************/
488 void smbsrv_reply_mknew(struct smbsrv_request *req)
492 /* parse the request */
493 SMBSRV_CHECK_WCT(req, 3);
494 SMBSRV_TALLOC_IO_PTR(oi, union smb_open);
495 SMBSRV_SETUP_NTVFS_REQUEST(reply_mknew_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
497 if (CVAL(req->in.hdr, HDR_COM) == SMBmknew) {
498 oi->mknew.level = RAW_OPEN_MKNEW;
500 oi->mknew.level = RAW_OPEN_CREATE;
502 oi->mknew.in.attrib = SVAL(req->in.vwv, VWV(0));
503 oi->mknew.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(1));
505 req_pull_ascii4(&req->in.bufinfo, &oi->mknew.in.fname, req->in.data, STR_TERMINATE);
507 if (!oi->mknew.in.fname) {
508 smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
512 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, oi));
515 /****************************************************************************
516 Reply to a create temporary file (async reply)
517 ****************************************************************************/
518 static void reply_ctemp_send(struct ntvfs_request *ntvfs)
520 struct smbsrv_request *req;
523 SMBSRV_CHECK_ASYNC_STATUS(oi, union smb_open);
525 /* build the reply */
526 smbsrv_setup_reply(req, 1, 0);
528 smbsrv_push_fnum(req->out.vwv, VWV(0), oi->ctemp.out.file.ntvfs);
530 /* the returned filename is relative to the directory */
531 req_push_str(req, NULL, oi->ctemp.out.name, -1, STR_TERMINATE | STR_ASCII);
533 smbsrv_send_reply(req);
536 /****************************************************************************
537 Reply to a create temporary file.
538 ****************************************************************************/
539 void smbsrv_reply_ctemp(struct smbsrv_request *req)
543 /* parse the request */
544 SMBSRV_CHECK_WCT(req, 3);
545 SMBSRV_TALLOC_IO_PTR(oi, union smb_open);
546 SMBSRV_SETUP_NTVFS_REQUEST(reply_ctemp_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
548 oi->ctemp.level = RAW_OPEN_CTEMP;
549 oi->ctemp.in.attrib = SVAL(req->in.vwv, VWV(0));
550 oi->ctemp.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(1));
552 /* the filename is actually a directory name, the server provides a filename
554 req_pull_ascii4(&req->in.bufinfo, &oi->ctemp.in.directory, req->in.data, STR_TERMINATE);
556 if (!oi->ctemp.in.directory) {
557 smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
561 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, oi));
565 /****************************************************************************
567 ****************************************************************************/
568 void smbsrv_reply_unlink(struct smbsrv_request *req)
570 union smb_unlink *unl;
572 /* parse the request */
573 SMBSRV_CHECK_WCT(req, 1);
574 SMBSRV_TALLOC_IO_PTR(unl, union smb_unlink);
575 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
577 unl->unlink.in.attrib = SVAL(req->in.vwv, VWV(0));
579 req_pull_ascii4(&req->in.bufinfo, &unl->unlink.in.pattern, req->in.data, STR_TERMINATE);
581 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_unlink(req->ntvfs, unl));
585 /****************************************************************************
586 Reply to a readbraw (core+ protocol).
587 this is a strange packet because it doesn't use a standard SMB header in the reply,
588 only the 4 byte NBT header
589 This command must be replied to synchronously
590 ****************************************************************************/
591 void smbsrv_reply_readbraw(struct smbsrv_request *req)
596 io.readbraw.level = RAW_READ_READBRAW;
598 /* there are two variants, one with 10 and one with 8 command words */
599 if (req->in.wct < 8) {
603 io.readbraw.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
604 io.readbraw.in.offset = IVAL(req->in.vwv, VWV(1));
605 io.readbraw.in.maxcnt = SVAL(req->in.vwv, VWV(3));
606 io.readbraw.in.mincnt = SVAL(req->in.vwv, VWV(4));
607 io.readbraw.in.timeout = IVAL(req->in.vwv, VWV(5));
609 if (!io.readbraw.in.file.ntvfs) {
613 /* the 64 bit variant */
614 if (req->in.wct == 10) {
615 uint32_t offset_high = IVAL(req->in.vwv, VWV(8));
616 io.readbraw.in.offset |= (((off_t)offset_high) << 32);
619 /* before calling the backend we setup the raw buffer. This
620 * saves a copy later */
621 req->out.size = io.readbraw.in.maxcnt + NBT_HDR_SIZE;
622 req->out.buffer = talloc_size(req, req->out.size);
623 if (req->out.buffer == NULL) {
626 SIVAL(req->out.buffer, 0, 0); /* init NBT header */
628 /* tell the backend where to put the data */
629 io.readbraw.out.data = req->out.buffer + NBT_HDR_SIZE;
631 /* prepare the ntvfs request */
632 req->ntvfs = ntvfs_request_create(req->tcon->ntvfs, req,
633 req->session->session_info,
634 SVAL(req->in.hdr,HDR_PID),
641 /* call the backend */
642 status = ntvfs_read(req->ntvfs, &io);
643 if (!NT_STATUS_IS_OK(status)) {
647 req->out.size = io.readbraw.out.nread + NBT_HDR_SIZE;
649 smbsrv_send_reply_nosign(req);
653 /* any failure in readbraw is equivalent to reading zero bytes */
655 req->out.buffer = talloc_size(req, req->out.size);
656 SIVAL(req->out.buffer, 0, 0); /* init NBT header */
658 smbsrv_send_reply_nosign(req);
662 /****************************************************************************
663 Reply to a lockread (async reply)
664 ****************************************************************************/
665 static void reply_lockread_send(struct ntvfs_request *ntvfs)
667 struct smbsrv_request *req;
670 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_read);
673 io->lockread.out.nread = MIN(io->lockread.out.nread,
674 req_max_data(req) - 3);
675 req_grow_data(req, 3 + io->lockread.out.nread);
677 /* construct reply */
678 SSVAL(req->out.vwv, VWV(0), io->lockread.out.nread);
679 SMBSRV_VWV_RESERVED(1, 4);
681 SCVAL(req->out.data, 0, SMB_DATA_BLOCK);
682 SSVAL(req->out.data, 1, io->lockread.out.nread);
684 smbsrv_send_reply(req);
688 /****************************************************************************
689 Reply to a lockread (core+ protocol).
690 note that the lock is a write lock, not a read lock!
691 ****************************************************************************/
692 void smbsrv_reply_lockread(struct smbsrv_request *req)
697 SMBSRV_CHECK_WCT(req, 5);
698 SMBSRV_TALLOC_IO_PTR(io, union smb_read);
699 SMBSRV_SETUP_NTVFS_REQUEST(reply_lockread_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
701 io->lockread.level = RAW_READ_LOCKREAD;
702 io->lockread.in.file.ntvfs= smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
703 io->lockread.in.count = SVAL(req->in.vwv, VWV(1));
704 io->lockread.in.offset = IVAL(req->in.vwv, VWV(2));
705 io->lockread.in.remaining = SVAL(req->in.vwv, VWV(4));
707 /* setup the reply packet assuming the maximum possible read */
708 smbsrv_setup_reply(req, 5, 3 + io->lockread.in.count);
710 /* tell the backend where to put the data */
711 io->lockread.out.data = req->out.data + 3;
713 SMBSRV_CHECK_FILE_HANDLE(io->lockread.in.file.ntvfs);
714 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_read(req->ntvfs, io));
719 /****************************************************************************
720 Reply to a read (async reply)
721 ****************************************************************************/
722 static void reply_read_send(struct ntvfs_request *ntvfs)
724 struct smbsrv_request *req;
727 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_read);
730 io->read.out.nread = MIN(io->read.out.nread,
731 req_max_data(req) - 3);
732 req_grow_data(req, 3 + io->read.out.nread);
734 /* construct reply */
735 SSVAL(req->out.vwv, VWV(0), io->read.out.nread);
736 SMBSRV_VWV_RESERVED(1, 4);
738 SCVAL(req->out.data, 0, SMB_DATA_BLOCK);
739 SSVAL(req->out.data, 1, io->read.out.nread);
741 smbsrv_send_reply(req);
744 /****************************************************************************
746 ****************************************************************************/
747 void smbsrv_reply_read(struct smbsrv_request *req)
752 SMBSRV_CHECK_WCT(req, 5);
753 SMBSRV_TALLOC_IO_PTR(io, union smb_read);
754 SMBSRV_SETUP_NTVFS_REQUEST(reply_read_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
756 io->read.level = RAW_READ_READ;
757 io->read.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
758 io->read.in.count = SVAL(req->in.vwv, VWV(1));
759 io->read.in.offset = IVAL(req->in.vwv, VWV(2));
760 io->read.in.remaining = SVAL(req->in.vwv, VWV(4));
762 /* setup the reply packet assuming the maximum possible read */
763 smbsrv_setup_reply(req, 5, 3 + io->read.in.count);
765 /* tell the backend where to put the data */
766 io->read.out.data = req->out.data + 3;
768 SMBSRV_CHECK_FILE_HANDLE(io->read.in.file.ntvfs);
769 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_read(req->ntvfs, io));
772 /****************************************************************************
773 Reply to a read and X (async reply)
774 ****************************************************************************/
775 static void reply_read_and_X_send(struct ntvfs_request *ntvfs)
777 struct smbsrv_request *req;
780 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_read);
782 /* readx reply packets can be over-sized */
783 req->control_flags |= SMBSRV_REQ_CONTROL_LARGE;
784 if (io->readx.in.maxcnt != 0xFFFF &&
785 io->readx.in.mincnt != 0xFFFF) {
786 req_grow_data(req, 1 + io->readx.out.nread);
787 SCVAL(req->out.data, 0, 0); /* padding */
789 req_grow_data(req, io->readx.out.nread);
792 /* construct reply */
793 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
794 SSVAL(req->out.vwv, VWV(1), 0);
795 SSVAL(req->out.vwv, VWV(2), io->readx.out.remaining);
796 SSVAL(req->out.vwv, VWV(3), io->readx.out.compaction_mode);
797 SMBSRV_VWV_RESERVED(4, 1);
798 SSVAL(req->out.vwv, VWV(5), io->readx.out.nread);
799 SSVAL(req->out.vwv, VWV(6), PTR_DIFF(io->readx.out.data, req->out.hdr));
800 SMBSRV_VWV_RESERVED(7, 5);
802 smbsrv_chain_reply(req);
805 /****************************************************************************
806 Reply to a read and X.
807 ****************************************************************************/
808 void smbsrv_reply_read_and_X(struct smbsrv_request *req)
813 if (req->in.wct != 12) {
814 SMBSRV_CHECK_WCT(req, 10);
817 SMBSRV_TALLOC_IO_PTR(io, union smb_read);
818 SMBSRV_SETUP_NTVFS_REQUEST(reply_read_and_X_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
820 io->readx.level = RAW_READ_READX;
821 io->readx.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(2));
822 io->readx.in.offset = IVAL(req->in.vwv, VWV(3));
823 io->readx.in.maxcnt = SVAL(req->in.vwv, VWV(5));
824 io->readx.in.mincnt = SVAL(req->in.vwv, VWV(6));
825 io->readx.in.remaining = SVAL(req->in.vwv, VWV(9));
826 if (req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) {
827 io->readx.in.read_for_execute = true;
829 io->readx.in.read_for_execute = false;
832 if (req->smb_conn->negotiate.client_caps & CAP_LARGE_READX) {
833 uint32_t high_part = IVAL(req->in.vwv, VWV(7));
834 if (high_part == 1) {
835 io->readx.in.maxcnt |= high_part << 16;
839 /* the 64 bit variant */
840 if (req->in.wct == 12) {
841 uint32_t offset_high = IVAL(req->in.vwv, VWV(10));
842 io->readx.in.offset |= (((uint64_t)offset_high) << 32);
845 /* setup the reply packet assuming the maximum possible read */
846 smbsrv_setup_reply(req, 12, 1 + io->readx.in.maxcnt);
848 /* tell the backend where to put the data. Notice the pad byte. */
849 if (io->readx.in.maxcnt != 0xFFFF &&
850 io->readx.in.mincnt != 0xFFFF) {
851 io->readx.out.data = req->out.data + 1;
853 io->readx.out.data = req->out.data;
856 SMBSRV_CHECK_FILE_HANDLE(io->readx.in.file.ntvfs);
857 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_read(req->ntvfs, io));
861 /****************************************************************************
862 Reply to a writebraw (core+ or LANMAN1.0 protocol).
863 ****************************************************************************/
864 void smbsrv_reply_writebraw(struct smbsrv_request *req)
866 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRuseSTD));
870 /****************************************************************************
871 Reply to a writeunlock (async reply)
872 ****************************************************************************/
873 static void reply_writeunlock_send(struct ntvfs_request *ntvfs)
875 struct smbsrv_request *req;
878 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_write);
880 /* construct reply */
881 smbsrv_setup_reply(req, 1, 0);
883 SSVAL(req->out.vwv, VWV(0), io->writeunlock.out.nwritten);
885 smbsrv_send_reply(req);
888 /****************************************************************************
889 Reply to a writeunlock (core+).
890 ****************************************************************************/
891 void smbsrv_reply_writeunlock(struct smbsrv_request *req)
895 SMBSRV_CHECK_WCT(req, 5);
896 SMBSRV_TALLOC_IO_PTR(io, union smb_write);
897 SMBSRV_SETUP_NTVFS_REQUEST(reply_writeunlock_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
899 io->writeunlock.level = RAW_WRITE_WRITEUNLOCK;
900 io->writeunlock.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
901 io->writeunlock.in.count = SVAL(req->in.vwv, VWV(1));
902 io->writeunlock.in.offset = IVAL(req->in.vwv, VWV(2));
903 io->writeunlock.in.remaining = SVAL(req->in.vwv, VWV(4));
904 io->writeunlock.in.data = req->in.data + 3;
906 /* make sure they gave us the data they promised */
907 if (io->writeunlock.in.count+3 > req->in.data_size) {
908 smbsrv_send_error(req, NT_STATUS_FOOBAR);
912 /* make sure the data block is big enough */
913 if (SVAL(req->in.data, 1) < io->writeunlock.in.count) {
914 smbsrv_send_error(req, NT_STATUS_FOOBAR);
918 SMBSRV_CHECK_FILE_HANDLE(io->writeunlock.in.file.ntvfs);
919 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
924 /****************************************************************************
925 Reply to a write (async reply)
926 ****************************************************************************/
927 static void reply_write_send(struct ntvfs_request *ntvfs)
929 struct smbsrv_request *req;
932 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_write);
934 /* construct reply */
935 smbsrv_setup_reply(req, 1, 0);
937 SSVAL(req->out.vwv, VWV(0), io->write.out.nwritten);
939 smbsrv_send_reply(req);
942 /****************************************************************************
944 ****************************************************************************/
945 void smbsrv_reply_write(struct smbsrv_request *req)
949 SMBSRV_CHECK_WCT(req, 5);
950 SMBSRV_TALLOC_IO_PTR(io, union smb_write);
951 SMBSRV_SETUP_NTVFS_REQUEST(reply_write_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
953 io->write.level = RAW_WRITE_WRITE;
954 io->write.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
955 io->write.in.count = SVAL(req->in.vwv, VWV(1));
956 io->write.in.offset = IVAL(req->in.vwv, VWV(2));
957 io->write.in.remaining = SVAL(req->in.vwv, VWV(4));
958 io->write.in.data = req->in.data + 3;
960 /* make sure they gave us the data they promised */
961 if (req_data_oob(&req->in.bufinfo, io->write.in.data, io->write.in.count)) {
962 smbsrv_send_error(req, NT_STATUS_FOOBAR);
966 /* make sure the data block is big enough */
967 if (SVAL(req->in.data, 1) < io->write.in.count) {
968 smbsrv_send_error(req, NT_STATUS_FOOBAR);
972 SMBSRV_CHECK_FILE_HANDLE(io->write.in.file.ntvfs);
973 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
977 /****************************************************************************
978 Reply to a write and X (async reply)
979 ****************************************************************************/
980 static void reply_write_and_X_send(struct ntvfs_request *ntvfs)
982 struct smbsrv_request *req;
985 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_write);
987 /* construct reply */
988 smbsrv_setup_reply(req, 6, 0);
990 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
991 SSVAL(req->out.vwv, VWV(1), 0);
992 SSVAL(req->out.vwv, VWV(2), io->writex.out.nwritten & 0xFFFF);
993 SSVAL(req->out.vwv, VWV(3), io->writex.out.remaining);
994 SSVAL(req->out.vwv, VWV(4), io->writex.out.nwritten >> 16);
995 SMBSRV_VWV_RESERVED(5, 1);
997 smbsrv_chain_reply(req);
1000 /****************************************************************************
1001 Reply to a write and X.
1002 ****************************************************************************/
1003 void smbsrv_reply_write_and_X(struct smbsrv_request *req)
1005 union smb_write *io;
1007 if (req->in.wct != 14) {
1008 SMBSRV_CHECK_WCT(req, 12);
1011 SMBSRV_TALLOC_IO_PTR(io, union smb_write);
1012 SMBSRV_SETUP_NTVFS_REQUEST(reply_write_and_X_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1014 io->writex.level = RAW_WRITE_WRITEX;
1015 io->writex.in.file.ntvfs= smbsrv_pull_fnum(req, req->in.vwv, VWV(2));
1016 io->writex.in.offset = IVAL(req->in.vwv, VWV(3));
1017 io->writex.in.wmode = SVAL(req->in.vwv, VWV(7));
1018 io->writex.in.remaining = SVAL(req->in.vwv, VWV(8));
1019 io->writex.in.count = SVAL(req->in.vwv, VWV(10));
1020 io->writex.in.data = req->in.hdr + SVAL(req->in.vwv, VWV(11));
1022 if (req->in.wct == 14) {
1023 uint32_t offset_high = IVAL(req->in.vwv, VWV(12));
1024 uint16_t count_high = SVAL(req->in.vwv, VWV(9));
1025 io->writex.in.offset |= (((uint64_t)offset_high) << 32);
1026 io->writex.in.count |= ((uint32_t)count_high) << 16;
1029 /* make sure the data is in bounds */
1030 if (req_data_oob(&req->in.bufinfo, io->writex.in.data, io->writex.in.count)) {
1031 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1035 SMBSRV_CHECK_FILE_HANDLE(io->writex.in.file.ntvfs);
1036 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
1040 /****************************************************************************
1041 Reply to a lseek (async reply)
1042 ****************************************************************************/
1043 static void reply_lseek_send(struct ntvfs_request *ntvfs)
1045 struct smbsrv_request *req;
1048 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_seek);
1050 /* construct reply */
1051 smbsrv_setup_reply(req, 2, 0);
1053 SIVALS(req->out.vwv, VWV(0), io->lseek.out.offset);
1055 smbsrv_send_reply(req);
1058 /****************************************************************************
1060 ****************************************************************************/
1061 void smbsrv_reply_lseek(struct smbsrv_request *req)
1065 SMBSRV_CHECK_WCT(req, 4);
1066 SMBSRV_TALLOC_IO_PTR(io, union smb_seek);
1067 SMBSRV_SETUP_NTVFS_REQUEST(reply_lseek_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1069 io->lseek.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1070 io->lseek.in.mode = SVAL(req->in.vwv, VWV(1));
1071 io->lseek.in.offset = IVALS(req->in.vwv, VWV(2));
1073 SMBSRV_CHECK_FILE_HANDLE(io->lseek.in.file.ntvfs);
1074 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_seek(req->ntvfs, io));
1077 /****************************************************************************
1079 ****************************************************************************/
1080 void smbsrv_reply_flush(struct smbsrv_request *req)
1082 union smb_flush *io;
1086 SMBSRV_CHECK_WCT(req, 1);
1087 SMBSRV_TALLOC_IO_PTR(io, union smb_flush);
1088 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1090 fnum = SVAL(req->in.vwv, VWV(0));
1091 if (fnum == 0xFFFF) {
1092 io->flush_all.level = RAW_FLUSH_ALL;
1094 io->flush.level = RAW_FLUSH_FLUSH;
1095 io->flush.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1096 SMBSRV_CHECK_FILE_HANDLE(io->flush.in.file.ntvfs);
1099 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_flush(req->ntvfs, io));
1102 /****************************************************************************
1105 Note that this has to deal with closing a directory opened by NT SMB's.
1106 ****************************************************************************/
1107 void smbsrv_reply_close(struct smbsrv_request *req)
1109 union smb_close *io;
1112 SMBSRV_CHECK_WCT(req, 3);
1113 SMBSRV_TALLOC_IO_PTR(io, union smb_close);
1114 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1116 io->close.level = RAW_CLOSE_CLOSE;
1117 io->close.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1118 io->close.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(1));
1120 SMBSRV_CHECK_FILE_HANDLE(io->close.in.file.ntvfs);
1121 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_close(req->ntvfs, io));
1125 /****************************************************************************
1126 Reply to a writeclose (async reply)
1127 ****************************************************************************/
1128 static void reply_writeclose_send(struct ntvfs_request *ntvfs)
1130 struct smbsrv_request *req;
1131 union smb_write *io;
1133 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_write);
1135 /* construct reply */
1136 smbsrv_setup_reply(req, 1, 0);
1138 SSVAL(req->out.vwv, VWV(0), io->write.out.nwritten);
1140 smbsrv_send_reply(req);
1143 /****************************************************************************
1144 Reply to a writeclose (Core+ protocol).
1145 ****************************************************************************/
1146 void smbsrv_reply_writeclose(struct smbsrv_request *req)
1148 union smb_write *io;
1150 /* this one is pretty weird - the wct can be 6 or 12 */
1151 if (req->in.wct != 12) {
1152 SMBSRV_CHECK_WCT(req, 6);
1155 SMBSRV_TALLOC_IO_PTR(io, union smb_write);
1156 SMBSRV_SETUP_NTVFS_REQUEST(reply_writeclose_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1158 io->writeclose.level = RAW_WRITE_WRITECLOSE;
1159 io->writeclose.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1160 io->writeclose.in.count = SVAL(req->in.vwv, VWV(1));
1161 io->writeclose.in.offset = IVAL(req->in.vwv, VWV(2));
1162 io->writeclose.in.mtime = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(4));
1163 io->writeclose.in.data = req->in.data + 1;
1165 /* make sure they gave us the data they promised */
1166 if (req_data_oob(&req->in.bufinfo, io->writeclose.in.data, io->writeclose.in.count)) {
1167 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1171 SMBSRV_CHECK_FILE_HANDLE(io->writeclose.in.file.ntvfs);
1172 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
1175 /****************************************************************************
1177 ****************************************************************************/
1178 void smbsrv_reply_lock(struct smbsrv_request *req)
1180 union smb_lock *lck;
1183 SMBSRV_CHECK_WCT(req, 5);
1184 SMBSRV_TALLOC_IO_PTR(lck, union smb_lock);
1185 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1187 lck->lock.level = RAW_LOCK_LOCK;
1188 lck->lock.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1189 lck->lock.in.count = IVAL(req->in.vwv, VWV(1));
1190 lck->lock.in.offset = IVAL(req->in.vwv, VWV(3));
1192 SMBSRV_CHECK_FILE_HANDLE(lck->lock.in.file.ntvfs);
1193 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_lock(req->ntvfs, lck));
1197 /****************************************************************************
1199 ****************************************************************************/
1200 void smbsrv_reply_unlock(struct smbsrv_request *req)
1202 union smb_lock *lck;
1205 SMBSRV_CHECK_WCT(req, 5);
1206 SMBSRV_TALLOC_IO_PTR(lck, union smb_lock);
1207 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1209 lck->unlock.level = RAW_LOCK_UNLOCK;
1210 lck->unlock.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1211 lck->unlock.in.count = IVAL(req->in.vwv, VWV(1));
1212 lck->unlock.in.offset = IVAL(req->in.vwv, VWV(3));
1214 SMBSRV_CHECK_FILE_HANDLE(lck->unlock.in.file.ntvfs);
1215 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_lock(req->ntvfs, lck));
1219 /****************************************************************************
1221 ****************************************************************************/
1222 void smbsrv_reply_tdis(struct smbsrv_request *req)
1224 struct smbsrv_handle *h, *nh;
1226 SMBSRV_CHECK_WCT(req, 0);
1229 * TODO: cancel all pending requests on this tcon
1233 * close all handles on this tcon
1235 for (h=req->tcon->handles.list; h; h=nh) {
1240 /* finally destroy the tcon */
1241 talloc_free(req->tcon);
1244 smbsrv_setup_reply(req, 0, 0);
1245 smbsrv_send_reply(req);
1249 /****************************************************************************
1250 Reply to a echo. This is one of the few calls that is handled directly (the
1251 backends don't see it at all)
1252 ****************************************************************************/
1253 void smbsrv_reply_echo(struct smbsrv_request *req)
1258 SMBSRV_CHECK_WCT(req, 1);
1260 count = SVAL(req->in.vwv, VWV(0));
1262 smbsrv_setup_reply(req, 1, req->in.data_size);
1264 memcpy(req->out.data, req->in.data, req->in.data_size);
1266 for (i=1; i <= count;i++) {
1267 struct smbsrv_request *this_req;
1270 this_req = smbsrv_setup_secondary_request(req);
1275 SSVAL(this_req->out.vwv, VWV(0), i);
1276 smbsrv_send_reply(this_req);
1282 /****************************************************************************
1283 Reply to a printopen (async reply)
1284 ****************************************************************************/
1285 static void reply_printopen_send(struct ntvfs_request *ntvfs)
1287 struct smbsrv_request *req;
1290 SMBSRV_CHECK_ASYNC_STATUS(oi, union smb_open);
1292 /* construct reply */
1293 smbsrv_setup_reply(req, 1, 0);
1295 smbsrv_push_fnum(req->out.vwv, VWV(0), oi->openold.out.file.ntvfs);
1297 smbsrv_send_reply(req);
1300 /****************************************************************************
1301 Reply to a printopen.
1302 ****************************************************************************/
1303 void smbsrv_reply_printopen(struct smbsrv_request *req)
1308 SMBSRV_CHECK_WCT(req, 2);
1309 SMBSRV_TALLOC_IO_PTR(oi, union smb_open);
1310 SMBSRV_SETUP_NTVFS_REQUEST(reply_printopen_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1312 oi->splopen.level = RAW_OPEN_SPLOPEN;
1313 oi->splopen.in.setup_length = SVAL(req->in.vwv, VWV(0));
1314 oi->splopen.in.mode = SVAL(req->in.vwv, VWV(1));
1316 req_pull_ascii4(&req->in.bufinfo, &oi->splopen.in.ident, req->in.data, STR_TERMINATE);
1318 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, oi));
1321 /****************************************************************************
1322 Reply to a printclose.
1323 ****************************************************************************/
1324 void smbsrv_reply_printclose(struct smbsrv_request *req)
1326 union smb_close *io;
1329 SMBSRV_CHECK_WCT(req, 3);
1330 SMBSRV_TALLOC_IO_PTR(io, union smb_close);
1331 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1333 io->splclose.level = RAW_CLOSE_SPLCLOSE;
1334 io->splclose.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1336 SMBSRV_CHECK_FILE_HANDLE(io->splclose.in.file.ntvfs);
1337 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_close(req->ntvfs, io));
1340 /****************************************************************************
1341 Reply to a printqueue.
1342 ****************************************************************************/
1343 static void reply_printqueue_send(struct ntvfs_request *ntvfs)
1345 struct smbsrv_request *req;
1348 const uint_t el_size = 28;
1350 SMBSRV_CHECK_ASYNC_STATUS(lpq,union smb_lpq);
1352 /* construct reply */
1353 smbsrv_setup_reply(req, 2, 0);
1355 /* truncate the returned list to fit in the negotiated buffer size */
1356 maxcount = (req_max_data(req) - 3) / el_size;
1357 if (maxcount < lpq->retq.out.count) {
1358 lpq->retq.out.count = maxcount;
1361 /* setup enough space in the reply */
1362 req_grow_data(req, 3 + el_size*lpq->retq.out.count);
1364 /* and fill it in */
1365 SSVAL(req->out.vwv, VWV(0), lpq->retq.out.count);
1366 SSVAL(req->out.vwv, VWV(1), lpq->retq.out.restart_idx);
1368 SCVAL(req->out.data, 0, SMB_DATA_BLOCK);
1369 SSVAL(req->out.data, 1, el_size*lpq->retq.out.count);
1371 req->out.ptr = req->out.data + 3;
1373 for (i=0;i<lpq->retq.out.count;i++) {
1374 srv_push_dos_date2(req->smb_conn, req->out.ptr, 0 , lpq->retq.out.queue[i].time);
1375 SCVAL(req->out.ptr, 4, lpq->retq.out.queue[i].status);
1376 SSVAL(req->out.ptr, 5, lpq->retq.out.queue[i].job);
1377 SIVAL(req->out.ptr, 7, lpq->retq.out.queue[i].size);
1378 SCVAL(req->out.ptr, 11, 0); /* reserved */
1379 req_push_str(req, req->out.ptr+12, lpq->retq.out.queue[i].user, 16, STR_ASCII);
1380 req->out.ptr += el_size;
1383 smbsrv_send_reply(req);
1386 /****************************************************************************
1387 Reply to a printqueue.
1388 ****************************************************************************/
1389 void smbsrv_reply_printqueue(struct smbsrv_request *req)
1394 SMBSRV_CHECK_WCT(req, 2);
1395 SMBSRV_TALLOC_IO_PTR(lpq, union smb_lpq);
1396 SMBSRV_SETUP_NTVFS_REQUEST(reply_printqueue_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1398 lpq->retq.level = RAW_LPQ_RETQ;
1399 lpq->retq.in.maxcount = SVAL(req->in.vwv, VWV(0));
1400 lpq->retq.in.startidx = SVAL(req->in.vwv, VWV(1));
1402 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_lpq(req->ntvfs, lpq));
1406 /****************************************************************************
1407 Reply to a printwrite.
1408 ****************************************************************************/
1409 void smbsrv_reply_printwrite(struct smbsrv_request *req)
1411 union smb_write *io;
1414 SMBSRV_CHECK_WCT(req, 1);
1415 SMBSRV_TALLOC_IO_PTR(io, union smb_write);
1416 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1418 if (req->in.data_size < 3) {
1419 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1423 io->splwrite.level = RAW_WRITE_SPLWRITE;
1424 io->splwrite.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1425 io->splwrite.in.count = SVAL(req->in.data, 1);
1426 io->splwrite.in.data = req->in.data + 3;
1428 /* make sure they gave us the data they promised */
1429 if (req_data_oob(&req->in.bufinfo, io->splwrite.in.data, io->splwrite.in.count)) {
1430 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1434 SMBSRV_CHECK_FILE_HANDLE(io->splwrite.in.file.ntvfs);
1435 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
1439 /****************************************************************************
1441 ****************************************************************************/
1442 void smbsrv_reply_mkdir(struct smbsrv_request *req)
1444 union smb_mkdir *io;
1446 /* parse the request */
1447 SMBSRV_CHECK_WCT(req, 0);
1448 SMBSRV_TALLOC_IO_PTR(io, union smb_mkdir);
1449 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1451 io->generic.level = RAW_MKDIR_MKDIR;
1452 req_pull_ascii4(&req->in.bufinfo, &io->mkdir.in.path, req->in.data, STR_TERMINATE);
1454 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_mkdir(req->ntvfs, io));
1458 /****************************************************************************
1460 ****************************************************************************/
1461 void smbsrv_reply_rmdir(struct smbsrv_request *req)
1463 struct smb_rmdir *io;
1465 /* parse the request */
1466 SMBSRV_CHECK_WCT(req, 0);
1467 SMBSRV_TALLOC_IO_PTR(io, struct smb_rmdir);
1468 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1470 req_pull_ascii4(&req->in.bufinfo, &io->in.path, req->in.data, STR_TERMINATE);
1472 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_rmdir(req->ntvfs, io));
1476 /****************************************************************************
1478 ****************************************************************************/
1479 void smbsrv_reply_mv(struct smbsrv_request *req)
1481 union smb_rename *io;
1484 /* parse the request */
1485 SMBSRV_CHECK_WCT(req, 1);
1486 SMBSRV_TALLOC_IO_PTR(io, union smb_rename);
1487 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1489 io->generic.level = RAW_RENAME_RENAME;
1490 io->rename.in.attrib = SVAL(req->in.vwv, VWV(0));
1493 p += req_pull_ascii4(&req->in.bufinfo, &io->rename.in.pattern1, p, STR_TERMINATE);
1494 p += req_pull_ascii4(&req->in.bufinfo, &io->rename.in.pattern2, p, STR_TERMINATE);
1496 if (!io->rename.in.pattern1 || !io->rename.in.pattern2) {
1497 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1501 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_rename(req->ntvfs, io));
1505 /****************************************************************************
1506 Reply to an NT rename.
1507 ****************************************************************************/
1508 void smbsrv_reply_ntrename(struct smbsrv_request *req)
1510 union smb_rename *io;
1513 /* parse the request */
1514 SMBSRV_CHECK_WCT(req, 4);
1515 SMBSRV_TALLOC_IO_PTR(io, union smb_rename);
1516 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1518 io->generic.level = RAW_RENAME_NTRENAME;
1519 io->ntrename.in.attrib = SVAL(req->in.vwv, VWV(0));
1520 io->ntrename.in.flags = SVAL(req->in.vwv, VWV(1));
1521 io->ntrename.in.cluster_size = IVAL(req->in.vwv, VWV(2));
1524 p += req_pull_ascii4(&req->in.bufinfo, &io->ntrename.in.old_name, p, STR_TERMINATE);
1525 p += req_pull_ascii4(&req->in.bufinfo, &io->ntrename.in.new_name, p, STR_TERMINATE);
1527 if (!io->ntrename.in.old_name || !io->ntrename.in.new_name) {
1528 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1532 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_rename(req->ntvfs, io));
1535 /****************************************************************************
1536 Reply to a file copy (async reply)
1537 ****************************************************************************/
1538 static void reply_copy_send(struct ntvfs_request *ntvfs)
1540 struct smbsrv_request *req;
1541 struct smb_copy *cp;
1543 SMBSRV_CHECK_ASYNC_STATUS(cp, struct smb_copy);
1545 /* build the reply */
1546 smbsrv_setup_reply(req, 1, 0);
1548 SSVAL(req->out.vwv, VWV(0), cp->out.count);
1550 smbsrv_send_reply(req);
1553 /****************************************************************************
1554 Reply to a file copy.
1555 ****************************************************************************/
1556 void smbsrv_reply_copy(struct smbsrv_request *req)
1558 struct smb_copy *cp;
1562 SMBSRV_CHECK_WCT(req, 3);
1563 SMBSRV_TALLOC_IO_PTR(cp, struct smb_copy);
1564 SMBSRV_SETUP_NTVFS_REQUEST(reply_copy_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1566 cp->in.tid2 = SVAL(req->in.vwv, VWV(0));
1567 cp->in.ofun = SVAL(req->in.vwv, VWV(1));
1568 cp->in.flags = SVAL(req->in.vwv, VWV(2));
1571 p += req_pull_ascii4(&req->in.bufinfo, &cp->in.path1, p, STR_TERMINATE);
1572 p += req_pull_ascii4(&req->in.bufinfo, &cp->in.path2, p, STR_TERMINATE);
1574 if (!cp->in.path1 || !cp->in.path2) {
1575 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1579 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_copy(req->ntvfs, cp));
1582 /****************************************************************************
1583 Reply to a lockingX request (async send)
1584 ****************************************************************************/
1585 static void reply_lockingX_send(struct ntvfs_request *ntvfs)
1587 struct smbsrv_request *req;
1588 union smb_lock *lck;
1590 SMBSRV_CHECK_ASYNC_STATUS(lck, union smb_lock);
1592 /* if it was an oplock break ack then we only send a reply if
1593 there was an error */
1594 if (lck->lockx.in.ulock_cnt + lck->lockx.in.lock_cnt == 0) {
1599 /* construct reply */
1600 smbsrv_setup_reply(req, 2, 0);
1602 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1603 SSVAL(req->out.vwv, VWV(1), 0);
1605 smbsrv_chain_reply(req);
1609 /****************************************************************************
1610 Reply to a lockingX request.
1611 ****************************************************************************/
1612 void smbsrv_reply_lockingX(struct smbsrv_request *req)
1614 union smb_lock *lck;
1615 uint_t total_locks, i;
1620 SMBSRV_CHECK_WCT(req, 8);
1621 SMBSRV_TALLOC_IO_PTR(lck, union smb_lock);
1622 SMBSRV_SETUP_NTVFS_REQUEST(reply_lockingX_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1624 lck->lockx.level = RAW_LOCK_LOCKX;
1625 lck->lockx.in.file.ntvfs= smbsrv_pull_fnum(req, req->in.vwv, VWV(2));
1626 lck->lockx.in.mode = SVAL(req->in.vwv, VWV(3));
1627 lck->lockx.in.timeout = IVAL(req->in.vwv, VWV(4));
1628 lck->lockx.in.ulock_cnt = SVAL(req->in.vwv, VWV(6));
1629 lck->lockx.in.lock_cnt = SVAL(req->in.vwv, VWV(7));
1631 total_locks = lck->lockx.in.ulock_cnt + lck->lockx.in.lock_cnt;
1633 /* there are two variants, one with 64 bit offsets and counts */
1634 if (lck->lockx.in.mode & LOCKING_ANDX_LARGE_FILES) {
1640 /* make sure we got the promised data */
1641 if (req_data_oob(&req->in.bufinfo, req->in.data, total_locks * lck_size)) {
1642 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1646 /* allocate the locks array */
1648 lck->lockx.in.locks = talloc_array(req, struct smb_lock_entry,
1650 if (lck->lockx.in.locks == NULL) {
1651 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
1658 /* construct the locks array */
1659 for (i=0;i<total_locks;i++) {
1660 uint32_t ofs_high=0, count_high=0;
1662 lck->lockx.in.locks[i].pid = SVAL(p, 0);
1664 if (lck->lockx.in.mode & LOCKING_ANDX_LARGE_FILES) {
1665 ofs_high = IVAL(p, 4);
1666 lck->lockx.in.locks[i].offset = IVAL(p, 8);
1667 count_high = IVAL(p, 12);
1668 lck->lockx.in.locks[i].count = IVAL(p, 16);
1670 lck->lockx.in.locks[i].offset = IVAL(p, 2);
1671 lck->lockx.in.locks[i].count = IVAL(p, 6);
1673 if (ofs_high != 0 || count_high != 0) {
1674 lck->lockx.in.locks[i].count |= ((uint64_t)count_high) << 32;
1675 lck->lockx.in.locks[i].offset |= ((uint64_t)ofs_high) << 32;
1680 SMBSRV_CHECK_FILE_HANDLE(lck->lockx.in.file.ntvfs);
1681 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_lock(req->ntvfs, lck));
1684 /****************************************************************************
1685 Reply to a SMBreadbmpx (read block multiplex) request.
1686 ****************************************************************************/
1687 void smbsrv_reply_readbmpx(struct smbsrv_request *req)
1689 /* tell the client to not use a multiplexed read - its too broken to use */
1690 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRuseSTD));
1694 /****************************************************************************
1695 Reply to a SMBsetattrE.
1696 ****************************************************************************/
1697 void smbsrv_reply_setattrE(struct smbsrv_request *req)
1699 union smb_setfileinfo *info;
1702 SMBSRV_CHECK_WCT(req, 7);
1703 SMBSRV_TALLOC_IO_PTR(info, union smb_setfileinfo);
1704 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1706 info->setattre.level = RAW_SFILEINFO_SETATTRE;
1707 info->setattre.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1708 info->setattre.in.create_time = srv_pull_dos_date2(req->smb_conn, req->in.vwv + VWV(1));
1709 info->setattre.in.access_time = srv_pull_dos_date2(req->smb_conn, req->in.vwv + VWV(3));
1710 info->setattre.in.write_time = srv_pull_dos_date2(req->smb_conn, req->in.vwv + VWV(5));
1712 SMBSRV_CHECK_FILE_HANDLE(info->setattre.in.file.ntvfs);
1713 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_setfileinfo(req->ntvfs, info));
1717 /****************************************************************************
1718 Reply to a SMBwritebmpx (write block multiplex primary) request.
1719 ****************************************************************************/
1720 void smbsrv_reply_writebmpx(struct smbsrv_request *req)
1722 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRuseSTD));
1726 /****************************************************************************
1727 Reply to a SMBwritebs (write block multiplex secondary) request.
1728 ****************************************************************************/
1729 void smbsrv_reply_writebs(struct smbsrv_request *req)
1731 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRuseSTD));
1736 /****************************************************************************
1737 Reply to a SMBgetattrE (async reply)
1738 ****************************************************************************/
1739 static void reply_getattrE_send(struct ntvfs_request *ntvfs)
1741 struct smbsrv_request *req;
1742 union smb_fileinfo *info;
1744 SMBSRV_CHECK_ASYNC_STATUS(info, union smb_fileinfo);
1747 smbsrv_setup_reply(req, 11, 0);
1749 srv_push_dos_date2(req->smb_conn, req->out.vwv, VWV(0), info->getattre.out.create_time);
1750 srv_push_dos_date2(req->smb_conn, req->out.vwv, VWV(2), info->getattre.out.access_time);
1751 srv_push_dos_date2(req->smb_conn, req->out.vwv, VWV(4), info->getattre.out.write_time);
1752 SIVAL(req->out.vwv, VWV(6), info->getattre.out.size);
1753 SIVAL(req->out.vwv, VWV(8), info->getattre.out.alloc_size);
1754 SSVAL(req->out.vwv, VWV(10), info->getattre.out.attrib);
1756 smbsrv_send_reply(req);
1759 /****************************************************************************
1760 Reply to a SMBgetattrE.
1761 ****************************************************************************/
1762 void smbsrv_reply_getattrE(struct smbsrv_request *req)
1764 union smb_fileinfo *info;
1767 SMBSRV_CHECK_WCT(req, 1);
1768 SMBSRV_TALLOC_IO_PTR(info, union smb_fileinfo);
1769 SMBSRV_SETUP_NTVFS_REQUEST(reply_getattrE_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1771 info->getattr.level = RAW_FILEINFO_GETATTRE;
1772 info->getattr.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1774 SMBSRV_CHECK_FILE_HANDLE(info->getattr.in.file.ntvfs);
1775 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_qfileinfo(req->ntvfs, info));
1778 void smbsrv_reply_sesssetup_send(struct smbsrv_request *req,
1779 union smb_sesssetup *io,
1782 switch (io->old.level) {
1783 case RAW_SESSSETUP_OLD:
1784 if (!NT_STATUS_IS_OK(status)) {
1785 smbsrv_send_error(req, status);
1789 /* construct reply */
1790 smbsrv_setup_reply(req, 3, 0);
1792 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1793 SSVAL(req->out.vwv, VWV(1), 0);
1794 SSVAL(req->out.vwv, VWV(2), io->old.out.action);
1796 SSVAL(req->out.hdr, HDR_UID, io->old.out.vuid);
1798 smbsrv_chain_reply(req);
1801 case RAW_SESSSETUP_NT1:
1802 if (!NT_STATUS_IS_OK(status)) {
1803 smbsrv_send_error(req, status);
1807 /* construct reply */
1808 smbsrv_setup_reply(req, 3, 0);
1810 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1811 SSVAL(req->out.vwv, VWV(1), 0);
1812 SSVAL(req->out.vwv, VWV(2), io->nt1.out.action);
1814 SSVAL(req->out.hdr, HDR_UID, io->nt1.out.vuid);
1816 req_push_str(req, NULL, io->nt1.out.os, -1, STR_TERMINATE);
1817 req_push_str(req, NULL, io->nt1.out.lanman, -1, STR_TERMINATE);
1818 req_push_str(req, NULL, io->nt1.out.domain, -1, STR_TERMINATE);
1820 smbsrv_chain_reply(req);
1823 case RAW_SESSSETUP_SPNEGO:
1824 if (!NT_STATUS_IS_OK(status) &&
1825 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1826 smbsrv_send_error(req, status);
1830 /* construct reply */
1831 smbsrv_setup_reply(req, 4, io->spnego.out.secblob.length);
1833 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1834 smbsrv_setup_error(req, status);
1837 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1838 SSVAL(req->out.vwv, VWV(1), 0);
1839 SSVAL(req->out.vwv, VWV(2), io->spnego.out.action);
1840 SSVAL(req->out.vwv, VWV(3), io->spnego.out.secblob.length);
1842 SSVAL(req->out.hdr, HDR_UID, io->spnego.out.vuid);
1844 memcpy(req->out.data, io->spnego.out.secblob.data, io->spnego.out.secblob.length);
1845 req_push_str(req, NULL, io->spnego.out.os, -1, STR_TERMINATE);
1846 req_push_str(req, NULL, io->spnego.out.lanman, -1, STR_TERMINATE);
1847 req_push_str(req, NULL, io->spnego.out.workgroup, -1, STR_TERMINATE);
1849 smbsrv_chain_reply(req);
1852 case RAW_SESSSETUP_SMB2:
1856 smbsrv_send_error(req, NT_STATUS_INTERNAL_ERROR);
1859 /****************************************************************************
1860 reply to an old style session setup command
1861 ****************************************************************************/
1862 static void reply_sesssetup_old(struct smbsrv_request *req)
1866 union smb_sesssetup *io;
1868 SMBSRV_TALLOC_IO_PTR(io, union smb_sesssetup);
1870 io->old.level = RAW_SESSSETUP_OLD;
1873 io->old.in.bufsize = SVAL(req->in.vwv, VWV(2));
1874 io->old.in.mpx_max = SVAL(req->in.vwv, VWV(3));
1875 io->old.in.vc_num = SVAL(req->in.vwv, VWV(4));
1876 io->old.in.sesskey = IVAL(req->in.vwv, VWV(5));
1877 passlen = SVAL(req->in.vwv, VWV(7));
1879 /* check the request isn't malformed */
1880 if (req_data_oob(&req->in.bufinfo, req->in.data, passlen)) {
1881 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1886 if (!req_pull_blob(&req->in.bufinfo, p, passlen, &io->old.in.password)) {
1887 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1892 p += req_pull_string(&req->in.bufinfo, &io->old.in.user, p, -1, STR_TERMINATE);
1893 p += req_pull_string(&req->in.bufinfo, &io->old.in.domain, p, -1, STR_TERMINATE);
1894 p += req_pull_string(&req->in.bufinfo, &io->old.in.os, p, -1, STR_TERMINATE);
1895 p += req_pull_string(&req->in.bufinfo, &io->old.in.lanman, p, -1, STR_TERMINATE);
1897 /* call the generic handler */
1898 smbsrv_sesssetup_backend(req, io);
1901 /****************************************************************************
1902 reply to an NT1 style session setup command
1903 ****************************************************************************/
1904 static void reply_sesssetup_nt1(struct smbsrv_request *req)
1907 uint16_t passlen1, passlen2;
1908 union smb_sesssetup *io;
1910 SMBSRV_TALLOC_IO_PTR(io, union smb_sesssetup);
1912 io->nt1.level = RAW_SESSSETUP_NT1;
1915 io->nt1.in.bufsize = SVAL(req->in.vwv, VWV(2));
1916 io->nt1.in.mpx_max = SVAL(req->in.vwv, VWV(3));
1917 io->nt1.in.vc_num = SVAL(req->in.vwv, VWV(4));
1918 io->nt1.in.sesskey = IVAL(req->in.vwv, VWV(5));
1919 passlen1 = SVAL(req->in.vwv, VWV(7));
1920 passlen2 = SVAL(req->in.vwv, VWV(8));
1921 io->nt1.in.capabilities = IVAL(req->in.vwv, VWV(11));
1923 /* check the request isn't malformed */
1924 if (req_data_oob(&req->in.bufinfo, req->in.data, passlen1) ||
1925 req_data_oob(&req->in.bufinfo, req->in.data + passlen1, passlen2)) {
1926 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1931 if (!req_pull_blob(&req->in.bufinfo, p, passlen1, &io->nt1.in.password1)) {
1932 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1936 if (!req_pull_blob(&req->in.bufinfo, p, passlen2, &io->nt1.in.password2)) {
1937 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1942 p += req_pull_string(&req->in.bufinfo, &io->nt1.in.user, p, -1, STR_TERMINATE);
1943 p += req_pull_string(&req->in.bufinfo, &io->nt1.in.domain, p, -1, STR_TERMINATE);
1944 p += req_pull_string(&req->in.bufinfo, &io->nt1.in.os, p, -1, STR_TERMINATE);
1945 p += req_pull_string(&req->in.bufinfo, &io->nt1.in.lanman, p, -1, STR_TERMINATE);
1947 /* call the generic handler */
1948 smbsrv_sesssetup_backend(req, io);
1952 /****************************************************************************
1953 reply to an SPNEGO style session setup command
1954 ****************************************************************************/
1955 static void reply_sesssetup_spnego(struct smbsrv_request *req)
1959 union smb_sesssetup *io;
1961 SMBSRV_TALLOC_IO_PTR(io, union smb_sesssetup);
1963 io->spnego.level = RAW_SESSSETUP_SPNEGO;
1966 io->spnego.in.bufsize = SVAL(req->in.vwv, VWV(2));
1967 io->spnego.in.mpx_max = SVAL(req->in.vwv, VWV(3));
1968 io->spnego.in.vc_num = SVAL(req->in.vwv, VWV(4));
1969 io->spnego.in.sesskey = IVAL(req->in.vwv, VWV(5));
1970 blob_len = SVAL(req->in.vwv, VWV(7));
1971 io->spnego.in.capabilities = IVAL(req->in.vwv, VWV(10));
1974 if (!req_pull_blob(&req->in.bufinfo, p, blob_len, &io->spnego.in.secblob)) {
1975 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1980 p += req_pull_string(&req->in.bufinfo, &io->spnego.in.os, p, -1, STR_TERMINATE);
1981 p += req_pull_string(&req->in.bufinfo, &io->spnego.in.lanman, p, -1, STR_TERMINATE);
1982 p += req_pull_string(&req->in.bufinfo, &io->spnego.in.workgroup, p, -1, STR_TERMINATE);
1984 /* call the generic handler */
1985 smbsrv_sesssetup_backend(req, io);
1989 /****************************************************************************
1990 reply to a session setup command
1991 ****************************************************************************/
1992 void smbsrv_reply_sesssetup(struct smbsrv_request *req)
1994 switch (req->in.wct) {
1996 /* a pre-NT1 call */
1997 reply_sesssetup_old(req);
2001 reply_sesssetup_nt1(req);
2005 reply_sesssetup_spnego(req);
2009 /* unsupported variant */
2010 smbsrv_send_error(req, NT_STATUS_FOOBAR);
2013 /****************************************************************************
2014 Reply to a exit. This closes all files open by a smbpid
2015 ****************************************************************************/
2016 void smbsrv_reply_exit(struct smbsrv_request *req)
2018 struct smbsrv_handle_session_item *i, *ni;
2019 struct smbsrv_handle *h;
2020 struct smbsrv_tcon *tcon;
2023 SMBSRV_CHECK_WCT(req, 0);
2025 smbpid = SVAL(req->in.hdr,HDR_PID);
2027 /* first destroy all handles, which have the same PID as the request */
2028 for (i=req->session->handles; i; i=ni) {
2031 if (h->smbpid != smbpid) continue;
2037 * then let the ntvfs backends proxy the call if they want to,
2038 * but we didn't check the return value of the backends,
2039 * as for the SMB client the call succeed
2041 for (tcon=req->smb_conn->smb_tcons.list;tcon;tcon=tcon->next) {
2043 SMBSRV_SETUP_NTVFS_REQUEST(NULL,0);
2044 ntvfs_exit(req->ntvfs);
2045 talloc_free(req->ntvfs);
2050 smbsrv_setup_reply(req, 0, 0);
2051 smbsrv_send_reply(req);
2054 /****************************************************************************
2055 Reply to a SMBulogoffX.
2056 ****************************************************************************/
2057 void smbsrv_reply_ulogoffX(struct smbsrv_request *req)
2059 struct smbsrv_handle_session_item *i, *ni;
2060 struct smbsrv_handle *h;
2061 struct smbsrv_tcon *tcon;
2063 SMBSRV_CHECK_WCT(req, 2);
2066 * TODO: cancel all pending requests
2070 /* destroy all handles */
2071 for (i=req->session->handles; i; i=ni) {
2078 * then let the ntvfs backends proxy the call if they want to,
2079 * but we didn't check the return value of the backends,
2080 * as for the SMB client the call succeed
2082 for (tcon=req->smb_conn->smb_tcons.list;tcon;tcon=tcon->next) {
2084 SMBSRV_SETUP_NTVFS_REQUEST(NULL,0);
2085 ntvfs_logoff(req->ntvfs);
2086 talloc_free(req->ntvfs);
2091 talloc_free(req->session);
2092 req->session = NULL; /* it is now invalid, don't use on
2093 any chained packets */
2095 smbsrv_setup_reply(req, 2, 0);
2097 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
2098 SSVAL(req->out.vwv, VWV(1), 0);
2100 smbsrv_chain_reply(req);
2103 /****************************************************************************
2104 Reply to an SMBfindclose request
2105 ****************************************************************************/
2106 void smbsrv_reply_findclose(struct smbsrv_request *req)
2108 union smb_search_close *io;
2111 SMBSRV_CHECK_WCT(req, 1);
2112 SMBSRV_TALLOC_IO_PTR(io, union smb_search_close);
2113 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
2115 io->findclose.level = RAW_FINDCLOSE_FINDCLOSE;
2116 io->findclose.in.handle = SVAL(req->in.vwv, VWV(0));
2118 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_search_close(req->ntvfs, io));
2121 /****************************************************************************
2122 Reply to an SMBfindnclose request
2123 ****************************************************************************/
2124 void smbsrv_reply_findnclose(struct smbsrv_request *req)
2126 smbsrv_send_error(req, NT_STATUS_FOOBAR);
2130 /****************************************************************************
2131 Reply to an SMBntcreateX request (async send)
2132 ****************************************************************************/
2133 static void reply_ntcreate_and_X_send(struct ntvfs_request *ntvfs)
2135 struct smbsrv_request *req;
2138 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_open);
2140 /* construct reply */
2141 smbsrv_setup_reply(req, 34, 0);
2143 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
2144 SSVAL(req->out.vwv, VWV(1), 0);
2145 SCVAL(req->out.vwv, VWV(2), io->ntcreatex.out.oplock_level);
2147 /* the rest of the parameters are not aligned! */
2148 smbsrv_push_fnum(req->out.vwv, 5, io->ntcreatex.out.file.ntvfs);
2149 SIVAL(req->out.vwv, 7, io->ntcreatex.out.create_action);
2150 push_nttime(req->out.vwv, 11, io->ntcreatex.out.create_time);
2151 push_nttime(req->out.vwv, 19, io->ntcreatex.out.access_time);
2152 push_nttime(req->out.vwv, 27, io->ntcreatex.out.write_time);
2153 push_nttime(req->out.vwv, 35, io->ntcreatex.out.change_time);
2154 SIVAL(req->out.vwv, 43, io->ntcreatex.out.attrib);
2155 SBVAL(req->out.vwv, 47, io->ntcreatex.out.alloc_size);
2156 SBVAL(req->out.vwv, 55, io->ntcreatex.out.size);
2157 SSVAL(req->out.vwv, 63, io->ntcreatex.out.file_type);
2158 SSVAL(req->out.vwv, 65, io->ntcreatex.out.ipc_state);
2159 SCVAL(req->out.vwv, 67, io->ntcreatex.out.is_directory);
2161 req->chained_fnum = SVAL(req->out.vwv, 5);
2163 smbsrv_chain_reply(req);
2166 /****************************************************************************
2167 Reply to an SMBntcreateX request
2168 ****************************************************************************/
2169 void smbsrv_reply_ntcreate_and_X(struct smbsrv_request *req)
2174 /* parse the request */
2175 SMBSRV_CHECK_WCT(req, 24);
2176 SMBSRV_TALLOC_IO_PTR(io, union smb_open);
2177 SMBSRV_SETUP_NTVFS_REQUEST(reply_ntcreate_and_X_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
2179 io->ntcreatex.level = RAW_OPEN_NTCREATEX;
2181 /* notice that the word parameters are not word aligned, so we don't use VWV() */
2182 fname_len = SVAL(req->in.vwv, 5);
2183 io->ntcreatex.in.flags = IVAL(req->in.vwv, 7);
2184 io->ntcreatex.in.root_fid = IVAL(req->in.vwv, 11);
2185 io->ntcreatex.in.access_mask = IVAL(req->in.vwv, 15);
2186 io->ntcreatex.in.alloc_size = BVAL(req->in.vwv, 19);
2187 io->ntcreatex.in.file_attr = IVAL(req->in.vwv, 27);
2188 io->ntcreatex.in.share_access = IVAL(req->in.vwv, 31);
2189 io->ntcreatex.in.open_disposition = IVAL(req->in.vwv, 35);
2190 io->ntcreatex.in.create_options = IVAL(req->in.vwv, 39);
2191 io->ntcreatex.in.impersonation = IVAL(req->in.vwv, 43);
2192 io->ntcreatex.in.security_flags = CVAL(req->in.vwv, 47);
2193 io->ntcreatex.in.ea_list = NULL;
2194 io->ntcreatex.in.sec_desc = NULL;
2196 /* we need a neater way to handle this alignment */
2197 if ((req->flags2 & FLAGS2_UNICODE_STRINGS) &&
2198 ucs2_align(req->in.buffer, req->in.data, STR_TERMINATE|STR_UNICODE)) {
2202 req_pull_string(&req->in.bufinfo, &io->ntcreatex.in.fname, req->in.data, fname_len, STR_TERMINATE);
2203 if (!io->ntcreatex.in.fname) {
2204 smbsrv_send_error(req, NT_STATUS_FOOBAR);
2208 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, io));
2212 /****************************************************************************
2213 Reply to an SMBntcancel request
2214 ****************************************************************************/
2215 void smbsrv_reply_ntcancel(struct smbsrv_request *req)
2217 struct smbsrv_request *r;
2218 uint16_t tid = SVAL(req->in.hdr,HDR_TID);
2219 uint16_t uid = SVAL(req->in.hdr,HDR_UID);
2220 uint16_t mid = SVAL(req->in.hdr,HDR_MID);
2221 uint16_t pid = SVAL(req->in.hdr,HDR_PID);
2223 for (r = req->smb_conn->requests; r; r = r->next) {
2224 if (tid != SVAL(r->in.hdr,HDR_TID)) continue;
2225 if (uid != SVAL(r->in.hdr,HDR_UID)) continue;
2226 if (mid != SVAL(r->in.hdr,HDR_MID)) continue;
2227 if (pid != SVAL(r->in.hdr,HDR_PID)) continue;
2229 SMBSRV_CHECK(ntvfs_cancel(r->ntvfs));
2231 /* NOTE: this request does not generate a reply */
2236 /* TODO: workout the correct error code,
2237 * until we know how the smb signing works
2238 * for ntcancel replies, don't send an error
2240 /*smbsrv_send_error(req, NT_STATUS_FOOBAR);*/
2245 parse the called/calling names from session request
2247 static NTSTATUS parse_session_request(struct smbsrv_request *req)
2252 blob.data = req->in.buffer + 4;
2253 blob.length = ascii_len_n((const char *)blob.data, req->in.size - PTR_DIFF(blob.data, req->in.buffer));
2254 if (blob.length == 0) return NT_STATUS_BAD_NETWORK_NAME;
2256 req->smb_conn->negotiate.called_name = talloc(req->smb_conn, struct nbt_name);
2257 req->smb_conn->negotiate.calling_name = talloc(req->smb_conn, struct nbt_name);
2258 if (req->smb_conn->negotiate.called_name == NULL ||
2259 req->smb_conn->negotiate.calling_name == NULL) {
2260 return NT_STATUS_NO_MEMORY;
2263 status = nbt_name_from_blob(req->smb_conn, &blob,
2264 req->smb_conn->negotiate.called_name);
2265 NT_STATUS_NOT_OK_RETURN(status);
2267 blob.data += blob.length;
2268 blob.length = ascii_len_n((const char *)blob.data, req->in.size - PTR_DIFF(blob.data, req->in.buffer));
2269 if (blob.length == 0) return NT_STATUS_BAD_NETWORK_NAME;
2271 status = nbt_name_from_blob(req->smb_conn, &blob,
2272 req->smb_conn->negotiate.calling_name);
2273 NT_STATUS_NOT_OK_RETURN(status);
2275 req->smb_conn->negotiate.done_nbt_session = true;
2277 return NT_STATUS_OK;
2282 /****************************************************************************
2283 Reply to a special message - a SMB packet with non zero NBT message type
2284 ****************************************************************************/
2285 void smbsrv_reply_special(struct smbsrv_request *req)
2288 uint8_t *buf = talloc_zero_array(req, uint8_t, 4);
2290 msg_type = CVAL(req->in.buffer,0);
2295 case 0x81: /* session request */
2296 if (req->smb_conn->negotiate.done_nbt_session) {
2297 DEBUG(0,("Warning: ignoring secondary session request\n"));
2304 /* we don't check the status - samba always accepts session
2305 requests for any name */
2306 parse_session_request(req);
2308 req->out.buffer = buf;
2310 smbsrv_send_reply_nosign(req);
2313 case 0x89: /* session keepalive request
2314 (some old clients produce this?) */
2315 SCVAL(buf, 0, SMBkeepalive);
2317 req->out.buffer = buf;
2319 smbsrv_send_reply_nosign(req);
2323 /* session keepalive - swallow it */
2328 DEBUG(0,("Unexpected NBT session packet (%d)\n", msg_type));