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>
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 2 of the License, or
10 (at your option) any later version.
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.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 This file handles most of the reply_ calls that the server
23 makes to handle specific protocols
28 /* useful way of catching wct errors with file and line number */
29 #define REQ_CHECK_WCT(req, wcount) do { \
30 if ((req)->in.wct != (wcount)) { \
31 DEBUG(1,("Unexpected WCT %d at %s(%d) - expected %d\n", \
32 (req)->in.wct, __FILE__, __LINE__, wcount)); \
33 req_reply_dos_error(req, ERRSRV, ERRerror); \
37 /* check req->async.status and if not OK then send an error reply */
38 #define CHECK_ASYNC_STATUS do { \
39 if (!NT_STATUS_IS_OK(req->async.status)) { \
40 req_reply_error(req, req->async.status); \
44 /* useful wrapper for talloc with NO_MEMORY reply */
45 #define REQ_TALLOC(ptr, size) do { \
46 ptr = talloc(req, size); \
48 req_reply_error(req, NT_STATUS_NO_MEMORY); \
53 check if the backend wants to handle the request asynchronously.
54 if it wants it handled synchronously then call the send function
57 #define REQ_ASYNC_TAIL do { \
58 if (!(req->control_flags & REQ_CONTROL_ASYNC)) { \
59 req->async.send_fn(req); \
62 /* zero out some reserved fields in a reply */
63 #define REQ_VWV_RESERVED(start, count) memset(req->out.vwv + VWV(start), 0, (count)*2)
65 /****************************************************************************
66 Reply to a simple request (async send)
67 ****************************************************************************/
68 static void reply_simple_send(struct smbsrv_request *req)
72 req_setup_reply(req, 0, 0);
77 /****************************************************************************
79 ****************************************************************************/
80 void reply_tcon(struct smbsrv_request *req)
87 REQ_CHECK_WCT(req, 0);
89 con.tcon.level = RAW_TCON_TCON;
92 p += req_pull_ascii4(req, &con.tcon.in.service, p, STR_TERMINATE);
93 p += req_pull_ascii4(req, &con.tcon.in.password, p, STR_TERMINATE);
94 p += req_pull_ascii4(req, &con.tcon.in.dev, p, STR_TERMINATE);
96 if (!con.tcon.in.service || !con.tcon.in.password || !con.tcon.in.dev) {
97 req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
102 status = tcon_backend(req, &con);
104 if (!NT_STATUS_IS_OK(status)) {
105 req_reply_error(req, status);
109 /* construct reply */
110 req_setup_reply(req, 2, 0);
112 SSVAL(req->out.vwv, VWV(0), con.tcon.out.max_xmit);
113 SSVAL(req->out.vwv, VWV(1), con.tcon.out.cnum);
114 SSVAL(req->out.hdr, HDR_TID, req->tcon->cnum);
120 /****************************************************************************
121 Reply to a tcon and X.
122 ****************************************************************************/
123 void reply_tcon_and_X(struct smbsrv_request *req)
130 con.tconx.level = RAW_TCON_TCONX;
133 REQ_CHECK_WCT(req, 4);
135 con.tconx.in.flags = SVAL(req->in.vwv, VWV(2));
136 passlen = SVAL(req->in.vwv, VWV(3));
140 if (!req_pull_blob(req, p, passlen, &con.tconx.in.password)) {
141 req_reply_error(req, NT_STATUS_ILL_FORMED_PASSWORD);
146 p += req_pull_string(req, &con.tconx.in.path, p, -1, STR_TERMINATE);
147 p += req_pull_string(req, &con.tconx.in.device, p, -1, STR_ASCII);
149 if (!con.tconx.in.path || !con.tconx.in.device) {
150 req_reply_error(req, NT_STATUS_BAD_DEVICE_TYPE);
155 status = tcon_backend(req, &con);
157 if (!NT_STATUS_IS_OK(status)) {
158 req_reply_error(req, status);
162 /* construct reply - two variants */
163 if (req->smb_conn->negotiate.protocol < PROTOCOL_NT1) {
164 req_setup_reply(req, 2, 0);
166 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
167 SSVAL(req->out.vwv, VWV(1), 0);
169 req_push_str(req, NULL, con.tconx.out.dev_type, -1, STR_TERMINATE|STR_ASCII);
171 req_setup_reply(req, 3, 0);
173 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
174 SSVAL(req->out.vwv, VWV(1), 0);
175 SSVAL(req->out.vwv, VWV(2), con.tconx.out.options);
177 req_push_str(req, NULL, con.tconx.out.dev_type, -1, STR_TERMINATE|STR_ASCII);
178 req_push_str(req, NULL, con.tconx.out.fs_type, -1, STR_TERMINATE);
181 /* set the incoming and outgoing tid to the just created one */
182 SSVAL(req->in.hdr, HDR_TID, con.tconx.out.cnum);
183 SSVAL(req->out.hdr,HDR_TID, con.tconx.out.cnum);
189 /****************************************************************************
190 Reply to an unknown request
191 ****************************************************************************/
192 void reply_unknown(struct smbsrv_request *req)
196 type = CVAL(req->in.hdr, HDR_COM);
198 DEBUG(0,("unknown command type %d (0x%X)\n", type, type));
200 req_reply_dos_error(req, ERRSRV, ERRunknownsmb);
204 /****************************************************************************
205 Reply to an ioctl (async reply)
206 ****************************************************************************/
207 static void reply_ioctl_send(struct smbsrv_request *req)
209 union smb_ioctl *io = req->async.private;
213 /* the +1 is for nicer alignment */
214 req_setup_reply(req, 8, io->ioctl.out.blob.length+1);
215 SSVAL(req->out.vwv, VWV(1), io->ioctl.out.blob.length);
216 SSVAL(req->out.vwv, VWV(5), io->ioctl.out.blob.length);
217 SSVAL(req->out.vwv, VWV(6), PTR_DIFF(req->out.data, req->out.hdr) + 1);
219 memcpy(req->out.data+1, io->ioctl.out.blob.data, io->ioctl.out.blob.length);
224 /****************************************************************************
226 ****************************************************************************/
227 void reply_ioctl(struct smbsrv_request *req)
232 REQ_CHECK_WCT(req, 3);
233 REQ_TALLOC(io, sizeof(*io));
235 io->ioctl.level = RAW_IOCTL_IOCTL;
236 io->ioctl.in.fnum = req_fnum(req, req->in.vwv, VWV(0));
237 io->ioctl.in.request = IVAL(req->in.vwv, VWV(1));
239 req->async.send_fn = reply_ioctl_send;
240 req->async.private = io;
243 req->async.status = req->tcon->ntvfs_ops->ioctl(req, io);
249 /****************************************************************************
251 ****************************************************************************/
252 void reply_chkpth(struct smbsrv_request *req)
254 struct smb_chkpath *io;
256 REQ_TALLOC(io, sizeof(*io));
258 req_pull_ascii4(req, &io->in.path, req->in.data, STR_TERMINATE);
260 req->async.send_fn = reply_simple_send;
262 req->async.status = req->tcon->ntvfs_ops->chkpath(req, io);
267 /****************************************************************************
268 Reply to a getatr (async reply)
269 ****************************************************************************/
270 static void reply_getatr_send(struct smbsrv_request *req)
272 union smb_fileinfo *st = req->async.private;
276 /* construct reply */
277 req_setup_reply(req, 10, 0);
279 SSVAL(req->out.vwv, VWV(0), st->getattr.out.attrib);
280 srv_push_dos_date3(req->smb_conn, req->out.vwv, VWV(1), st->getattr.out.write_time);
281 SIVAL(req->out.vwv, VWV(3), st->getattr.out.size);
283 REQ_VWV_RESERVED(5, 5);
289 /****************************************************************************
291 ****************************************************************************/
292 void reply_getatr(struct smbsrv_request *req)
294 union smb_fileinfo *st;
296 REQ_TALLOC(st, sizeof(*st));
298 st->getattr.level = RAW_FILEINFO_GETATTR;
301 req_pull_ascii4(req, &st->getattr.in.fname, req->in.data, STR_TERMINATE);
302 if (!st->getattr.in.fname) {
303 req_reply_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
307 req->async.send_fn = reply_getatr_send;
308 req->async.private = st;
311 req->async.status = req->tcon->ntvfs_ops->qpathinfo(req, st);
317 /****************************************************************************
319 ****************************************************************************/
320 void reply_setatr(struct smbsrv_request *req)
322 union smb_setfileinfo *st;
325 REQ_CHECK_WCT(req, 8);
326 REQ_TALLOC(st, sizeof(*st));
328 st->setattr.level = RAW_SFILEINFO_SETATTR;
329 st->setattr.in.attrib = SVAL(req->in.vwv, VWV(0));
330 st->setattr.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(1));
332 req_pull_ascii4(req, &st->setattr.file.fname, req->in.data, STR_TERMINATE);
334 if (!st->setattr.file.fname) {
335 req_reply_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
339 req->async.send_fn = reply_simple_send;
342 req->async.status = req->tcon->ntvfs_ops->setpathinfo(req, st);
348 /****************************************************************************
349 Reply to a dskattr (async reply)
350 ****************************************************************************/
351 static void reply_dskattr_send(struct smbsrv_request *req)
353 union smb_fsinfo *fs = req->async.private;
357 /* construct reply */
358 req_setup_reply(req, 5, 0);
360 SSVAL(req->out.vwv, VWV(0), fs->dskattr.out.units_total);
361 SSVAL(req->out.vwv, VWV(1), fs->dskattr.out.blocks_per_unit);
362 SSVAL(req->out.vwv, VWV(2), fs->dskattr.out.block_size);
363 SSVAL(req->out.vwv, VWV(3), fs->dskattr.out.units_free);
365 REQ_VWV_RESERVED(4, 1);
371 /****************************************************************************
373 ****************************************************************************/
374 void reply_dskattr(struct smbsrv_request *req)
376 union smb_fsinfo *fs;
378 REQ_TALLOC(fs, sizeof(*fs));
380 fs->dskattr.level = RAW_QFS_DSKATTR;
382 req->async.send_fn = reply_dskattr_send;
383 req->async.private = fs;
386 req->async.status = req->tcon->ntvfs_ops->fsinfo(req, fs);
393 /****************************************************************************
394 Reply to an open (async reply)
395 ****************************************************************************/
396 static void reply_open_send(struct smbsrv_request *req)
398 union smb_open *oi = req->async.private;
402 /* construct reply */
403 req_setup_reply(req, 7, 0);
405 SSVAL(req->out.vwv, VWV(0), oi->open.out.fnum);
406 SSVAL(req->out.vwv, VWV(1), oi->open.out.attrib);
407 srv_push_dos_date3(req->smb_conn, req->out.vwv, VWV(2), oi->open.out.write_time);
408 SIVAL(req->out.vwv, VWV(4), oi->open.out.size);
409 SSVAL(req->out.vwv, VWV(6), oi->open.out.rmode);
414 /****************************************************************************
416 ****************************************************************************/
417 void reply_open(struct smbsrv_request *req)
422 REQ_CHECK_WCT(req, 2);
423 REQ_TALLOC(oi, sizeof(*oi));
425 oi->open.level = RAW_OPEN_OPEN;
426 oi->open.in.flags = SVAL(req->in.vwv, VWV(0));
427 oi->open.in.search_attrs = SVAL(req->in.vwv, VWV(1));
429 req_pull_ascii4(req, &oi->open.in.fname, req->in.data, STR_TERMINATE);
431 if (!oi->open.in.fname) {
432 req_reply_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
436 req->async.send_fn = reply_open_send;
437 req->async.private = oi;
440 req->async.status = req->tcon->ntvfs_ops->open(req, oi);
446 /****************************************************************************
447 Reply to an open and X (async reply)
448 ****************************************************************************/
449 static void reply_open_and_X_send(struct smbsrv_request *req)
451 union smb_open *oi = req->async.private;
455 /* build the reply */
456 if (oi->openx.in.flags & OPENX_FLAGS_EXTENDED_RETURN) {
457 req_setup_reply(req, 19, 0);
459 req_setup_reply(req, 15, 0);
462 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
463 SSVAL(req->out.vwv, VWV(1), 0);
464 SSVAL(req->out.vwv, VWV(2), oi->openx.out.fnum);
465 SSVAL(req->out.vwv, VWV(3), oi->openx.out.attrib);
466 srv_push_dos_date3(req->smb_conn, req->out.vwv, VWV(4), oi->openx.out.write_time);
467 SIVAL(req->out.vwv, VWV(6), oi->openx.out.size);
468 SSVAL(req->out.vwv, VWV(8), oi->openx.out.access);
469 SSVAL(req->out.vwv, VWV(9), oi->openx.out.ftype);
470 SSVAL(req->out.vwv, VWV(10),oi->openx.out.devstate);
471 SSVAL(req->out.vwv, VWV(11),oi->openx.out.action);
472 SIVAL(req->out.vwv, VWV(12),oi->openx.out.unique_fid);
473 SSVAL(req->out.vwv, VWV(14),0); /* reserved */
474 if (oi->openx.in.flags & OPENX_FLAGS_EXTENDED_RETURN) {
475 SIVAL(req->out.vwv, VWV(15),oi->openx.out.access_mask);
476 REQ_VWV_RESERVED(17, 2);
483 /****************************************************************************
484 Reply to an open and X.
485 ****************************************************************************/
486 void reply_open_and_X(struct smbsrv_request *req)
490 /* parse the request */
491 REQ_CHECK_WCT(req, 15);
492 REQ_TALLOC(oi, sizeof(*oi));
494 oi->openx.level = RAW_OPEN_OPENX;
495 oi->openx.in.flags = SVAL(req->in.vwv, VWV(2));
496 oi->openx.in.open_mode = SVAL(req->in.vwv, VWV(3));
497 oi->openx.in.search_attrs = SVAL(req->in.vwv, VWV(4));
498 oi->openx.in.file_attrs = SVAL(req->in.vwv, VWV(5));
499 oi->openx.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(6));
500 oi->openx.in.open_func = SVAL(req->in.vwv, VWV(8));
501 oi->openx.in.size = IVAL(req->in.vwv, VWV(9));
502 oi->openx.in.timeout = IVAL(req->in.vwv, VWV(11));
504 req_pull_ascii4(req, &oi->openx.in.fname, req->in.data, STR_TERMINATE);
506 if (!oi->openx.in.fname) {
507 req_reply_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
511 req->async.send_fn = reply_open_and_X_send;
512 req->async.private = oi;
514 /* call the backend */
515 req->async.status = req->tcon->ntvfs_ops->open(req, oi);
521 /****************************************************************************
522 Reply to a mknew or a create.
523 ****************************************************************************/
524 static void reply_mknew_send(struct smbsrv_request *req)
526 union smb_open *oi = req->async.private;
530 /* build the reply */
531 req_setup_reply(req, 1, 0);
533 SSVAL(req->out.vwv, VWV(0), oi->mknew.out.fnum);
539 /****************************************************************************
540 Reply to a mknew or a create.
541 ****************************************************************************/
542 void reply_mknew(struct smbsrv_request *req)
546 /* parse the request */
547 REQ_CHECK_WCT(req, 3);
548 REQ_TALLOC(oi, sizeof(*oi));
550 oi->mknew.level = RAW_OPEN_MKNEW;
551 oi->mknew.in.attrib = SVAL(req->in.vwv, VWV(0));
552 oi->mknew.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(1));
554 req_pull_ascii4(req, &oi->mknew.in.fname, req->in.data, STR_TERMINATE);
556 if (!oi->mknew.in.fname) {
557 req_reply_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
561 req->async.send_fn = reply_mknew_send;
562 req->async.private = oi;
564 /* call the backend */
565 req->async.status = req->tcon->ntvfs_ops->open(req, oi);
570 /****************************************************************************
571 Reply to a create temporary file (async reply)
572 ****************************************************************************/
573 static void reply_ctemp_send(struct smbsrv_request *req)
575 union smb_open *oi = req->async.private;
579 /* build the reply */
580 req_setup_reply(req, 1, 0);
582 SSVAL(req->out.vwv, VWV(0), oi->ctemp.out.fnum);
584 /* the returned filename is relative to the directory */
585 req_push_str(req, NULL, oi->ctemp.out.name, -1, STR_TERMINATE);
590 /****************************************************************************
591 Reply to a create temporary file.
592 ****************************************************************************/
593 void reply_ctemp(struct smbsrv_request *req)
597 /* parse the request */
598 REQ_CHECK_WCT(req, 3);
599 REQ_TALLOC(oi, sizeof(*oi));
601 oi->ctemp.level = RAW_OPEN_CTEMP;
602 oi->ctemp.in.attrib = SVAL(req->in.vwv, VWV(0));
603 oi->ctemp.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(1));
605 /* the filename is actually a directory name, the server provides a filename
607 req_pull_ascii4(req, &oi->ctemp.in.directory, req->in.data, STR_TERMINATE);
609 if (!oi->ctemp.in.directory) {
610 req_reply_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
614 req->async.send_fn = reply_ctemp_send;
615 req->async.private = oi;
617 /* call the backend */
618 req->async.status = req->tcon->ntvfs_ops->open(req, oi);
624 /****************************************************************************
626 ****************************************************************************/
627 void reply_unlink(struct smbsrv_request *req)
629 struct smb_unlink *unl;
631 /* parse the request */
632 REQ_CHECK_WCT(req, 1);
633 REQ_TALLOC(unl, sizeof(*unl));
635 unl->in.attrib = SVAL(req->in.vwv, VWV(0));
637 req_pull_ascii4(req, &unl->in.pattern, req->in.data, STR_TERMINATE);
639 req->async.send_fn = reply_simple_send;
642 req->async.status = req->tcon->ntvfs_ops->unlink(req, unl);
648 /****************************************************************************
649 Reply to a readbraw (core+ protocol).
650 this is a strange packet because it doesn't use a standard SMB header in the reply,
651 only the 4 byte NBT header
652 This command must be replied to synchronously
653 ****************************************************************************/
654 void reply_readbraw(struct smbsrv_request *req)
659 io.readbraw.level = RAW_READ_READBRAW;
661 /* there are two variants, one with 10 and one with 8 command words */
662 if (req->in.wct != 10) {
663 REQ_CHECK_WCT(req, 8);
666 io.readbraw.in.fnum = req_fnum(req, req->in.vwv, VWV(0));
667 io.readbraw.in.offset = IVAL(req->in.vwv, VWV(1));
668 io.readbraw.in.mincnt = SVAL(req->in.vwv, VWV(3));
669 io.readbraw.in.maxcnt = SVAL(req->in.vwv, VWV(4));
670 io.readbraw.in.timeout = IVAL(req->in.vwv, VWV(5));
672 /* the 64 bit variant */
673 if (req->in.wct == 10) {
674 uint32_t offset_high = IVAL(req->in.vwv, VWV(8));
675 io.readbraw.in.offset |= (((SMB_OFF_T)offset_high) << 32);
678 /* before calling the backend we setup the raw buffer. This
679 * saves a copy later */
680 req->out.size = io.readbraw.in.maxcnt + NBT_HDR_SIZE;
681 req->out.buffer = talloc(req, req->out.size);
682 if (req->out.buffer == NULL) {
685 SIVAL(req->out.buffer, 0, 0); /* init NBT header */
687 /* tell the backend where to put the data */
688 io.readbraw.out.data = req->out.buffer + NBT_HDR_SIZE;
690 /* call the backend */
691 status = req->tcon->ntvfs_ops->read(req, &io);
693 if (!NT_STATUS_IS_OK(status)) {
697 req->out.size = io.readbraw.out.nread + NBT_HDR_SIZE;
703 /* any failure in readbraw is equivalent to reading zero bytes */
705 req->out.buffer = talloc(req, req->out.size);
706 SIVAL(req->out.buffer, 0, 0); /* init NBT header */
708 req_send_reply_nosign(req);
712 /****************************************************************************
713 Reply to a lockread (async reply)
714 ****************************************************************************/
715 static void reply_lockread_send(struct smbsrv_request *req)
717 union smb_read *io = req->async.private;
722 io->lockread.out.nread = MIN(io->lockread.out.nread,
723 req_max_data(req) - 3);
724 req_grow_data(req, 3 + io->lockread.out.nread);
726 /* construct reply */
727 SSVAL(req->out.vwv, VWV(0), io->lockread.out.nread);
728 REQ_VWV_RESERVED(1, 4);
730 SCVAL(req->out.data, 0, SMB_DATA_BLOCK);
731 SSVAL(req->out.data, 1, io->lockread.out.nread);
737 /****************************************************************************
738 Reply to a lockread (core+ protocol).
739 note that the lock is a write lock, not a read lock!
740 ****************************************************************************/
741 void reply_lockread(struct smbsrv_request *req)
746 REQ_CHECK_WCT(req, 5);
747 REQ_TALLOC(io, sizeof(*io));
749 io->lockread.level = RAW_READ_LOCKREAD;
750 io->lockread.in.fnum = req_fnum(req, req->in.vwv, VWV(0));
751 io->lockread.in.count = SVAL(req->in.vwv, VWV(1));
752 io->lockread.in.offset = IVAL(req->in.vwv, VWV(2));
753 io->lockread.in.remaining = SVAL(req->in.vwv, VWV(4));
755 /* setup the reply packet assuming the maximum possible read */
756 req_setup_reply(req, 5, 3 + io->lockread.in.count);
758 /* tell the backend where to put the data */
759 io->lockread.out.data = req->out.data + 3;
761 req->async.send_fn = reply_lockread_send;
762 req->async.private = io;
765 req->async.status = req->tcon->ntvfs_ops->read(req, io);
772 /****************************************************************************
773 Reply to a read (async reply)
774 ****************************************************************************/
775 static void reply_read_send(struct smbsrv_request *req)
777 union smb_read *io = req->async.private;
782 io->read.out.nread = MIN(io->read.out.nread,
783 req_max_data(req) - 3);
784 req_grow_data(req, 3 + io->read.out.nread);
786 /* construct reply */
787 SSVAL(req->out.vwv, VWV(0), io->read.out.nread);
788 REQ_VWV_RESERVED(1, 4);
790 SCVAL(req->out.data, 0, SMB_DATA_BLOCK);
791 SSVAL(req->out.data, 1, io->read.out.nread);
796 /****************************************************************************
798 ****************************************************************************/
799 void reply_read(struct smbsrv_request *req)
804 REQ_CHECK_WCT(req, 5);
805 REQ_TALLOC(io, sizeof(*io));
807 io->read.level = RAW_READ_READ;
808 io->read.in.fnum = req_fnum(req, req->in.vwv, VWV(0));
809 io->read.in.count = SVAL(req->in.vwv, VWV(1));
810 io->read.in.offset = IVAL(req->in.vwv, VWV(2));
811 io->read.in.remaining = SVAL(req->in.vwv, VWV(4));
813 /* setup the reply packet assuming the maximum possible read */
814 req_setup_reply(req, 5, 3 + io->read.in.count);
816 /* tell the backend where to put the data */
817 io->read.out.data = req->out.data + 3;
819 req->async.send_fn = reply_read_send;
820 req->async.private = io;
823 req->async.status = req->tcon->ntvfs_ops->read(req, io);
830 /****************************************************************************
831 Reply to a read and X (async reply)
832 ****************************************************************************/
833 static void reply_read_and_X_send(struct smbsrv_request *req)
835 union smb_read *io = req->async.private;
839 /* readx reply packets can be over-sized */
840 req->control_flags |= REQ_CONTROL_LARGE;
841 req_grow_data(req, 1 + io->readx.out.nread);
843 /* construct reply */
844 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
845 SSVAL(req->out.vwv, VWV(1), 0);
846 SSVAL(req->out.vwv, VWV(2), io->readx.out.remaining);
847 SSVAL(req->out.vwv, VWV(3), io->readx.out.compaction_mode);
848 REQ_VWV_RESERVED(4, 1);
849 SSVAL(req->out.vwv, VWV(5), io->readx.out.nread);
850 SSVAL(req->out.vwv, VWV(6), PTR_DIFF(io->readx.out.data, req->out.hdr));
851 SCVAL(req->out.data, 0, 0); /* padding */
852 REQ_VWV_RESERVED(7, 5);
857 /****************************************************************************
858 Reply to a read and X.
859 ****************************************************************************/
860 void reply_read_and_X(struct smbsrv_request *req)
865 if (req->in.wct != 12) {
866 REQ_CHECK_WCT(req, 10);
869 REQ_TALLOC(io, sizeof(*io));
871 io->readx.level = RAW_READ_READX;
872 io->readx.in.fnum = req_fnum(req, req->in.vwv, VWV(2));
873 io->readx.in.offset = IVAL(req->in.vwv, VWV(3));
874 io->readx.in.maxcnt = SVAL(req->in.vwv, VWV(5));
875 io->readx.in.mincnt = SVAL(req->in.vwv, VWV(6));
876 io->readx.in.remaining = SVAL(req->in.vwv, VWV(9));
878 /* the 64 bit variant */
879 if (req->in.wct == 12) {
880 uint32_t offset_high = IVAL(req->in.vwv, VWV(10));
881 io->readx.in.offset |= (((uint64_t)offset_high) << 32);
884 /* setup the reply packet assuming the maximum possible read */
885 req_setup_reply(req, 12, 1 + io->readx.in.maxcnt);
887 /* tell the backend where to put the data. Notice the pad byte. */
888 io->readx.out.data = req->out.data + 1;
890 req->async.send_fn = reply_read_and_X_send;
891 req->async.private = io;
894 req->async.status = req->tcon->ntvfs_ops->read(req, io);
900 /****************************************************************************
901 Reply to a writebraw (core+ or LANMAN1.0 protocol).
902 ****************************************************************************/
903 void reply_writebraw(struct smbsrv_request *req)
905 /* this one is damn complex - put it off for now */
906 req_reply_error(req, NT_STATUS_FOOBAR);
910 /****************************************************************************
911 Reply to a writeunlock (async reply)
912 ****************************************************************************/
913 static void reply_writeunlock_send(struct smbsrv_request *req)
915 union smb_write *io = req->async.private;
919 /* construct reply */
920 req_setup_reply(req, 1, 0);
922 SSVAL(req->out.vwv, VWV(0), io->writeunlock.out.nwritten);
927 /****************************************************************************
928 Reply to a writeunlock (core+).
929 ****************************************************************************/
930 void reply_writeunlock(struct smbsrv_request *req)
934 REQ_CHECK_WCT(req, 5);
935 REQ_TALLOC(io, sizeof(*io));
937 io->writeunlock.level = RAW_WRITE_WRITEUNLOCK;
938 io->writeunlock.in.fnum = req_fnum(req, req->in.vwv, VWV(0));
939 io->writeunlock.in.count = SVAL(req->in.vwv, VWV(1));
940 io->writeunlock.in.offset = IVAL(req->in.vwv, VWV(2));
941 io->writeunlock.in.remaining = SVAL(req->in.vwv, VWV(4));
942 io->writeunlock.in.data = req->in.data + 3;
944 /* make sure they gave us the data they promised */
945 if (io->writeunlock.in.count+3 > req->in.data_size) {
946 req_reply_error(req, NT_STATUS_FOOBAR);
950 /* make sure the data block is big enough */
951 if (SVAL(req->in.data, 1) < io->writeunlock.in.count) {
952 req_reply_error(req, NT_STATUS_FOOBAR);
956 req->async.send_fn = reply_writeunlock_send;
957 req->async.private = io;
960 req->async.status = req->tcon->ntvfs_ops->write(req, io);
967 /****************************************************************************
968 Reply to a write (async reply)
969 ****************************************************************************/
970 static void reply_write_send(struct smbsrv_request *req)
972 union smb_write *io = req->async.private;
976 /* construct reply */
977 req_setup_reply(req, 1, 0);
979 SSVAL(req->out.vwv, VWV(0), io->write.out.nwritten);
984 /****************************************************************************
986 ****************************************************************************/
987 void reply_write(struct smbsrv_request *req)
991 REQ_CHECK_WCT(req, 5);
992 REQ_TALLOC(io, sizeof(*io));
994 io->write.level = RAW_WRITE_WRITE;
995 io->write.in.fnum = req_fnum(req, req->in.vwv, VWV(0));
996 io->write.in.count = SVAL(req->in.vwv, VWV(1));
997 io->write.in.offset = IVAL(req->in.vwv, VWV(2));
998 io->write.in.remaining = SVAL(req->in.vwv, VWV(4));
999 io->write.in.data = req->in.data + 3;
1001 /* make sure they gave us the data they promised */
1002 if (req_data_oob(req, io->write.in.data, io->write.in.count)) {
1003 req_reply_error(req, NT_STATUS_FOOBAR);
1007 /* make sure the data block is big enough */
1008 if (SVAL(req->in.data, 1) < io->write.in.count) {
1009 req_reply_error(req, NT_STATUS_FOOBAR);
1013 req->async.send_fn = reply_write_send;
1014 req->async.private = io;
1017 req->async.status = req->tcon->ntvfs_ops->write(req, io);
1023 /****************************************************************************
1024 Reply to a write and X (async reply)
1025 ****************************************************************************/
1026 static void reply_write_and_X_send(struct smbsrv_request *req)
1028 union smb_write *io = req->async.private;
1032 /* construct reply */
1033 req_setup_reply(req, 6, 0);
1035 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1036 SSVAL(req->out.vwv, VWV(1), 0);
1037 SSVAL(req->out.vwv, VWV(2), io->writex.out.nwritten & 0xFFFF);
1038 SSVAL(req->out.vwv, VWV(3), io->writex.out.remaining);
1039 SSVAL(req->out.vwv, VWV(4), io->writex.out.nwritten >> 16);
1040 REQ_VWV_RESERVED(5, 1);
1045 /****************************************************************************
1046 Reply to a write and X.
1047 ****************************************************************************/
1048 void reply_write_and_X(struct smbsrv_request *req)
1050 union smb_write *io;
1052 if (req->in.wct != 14) {
1053 REQ_CHECK_WCT(req, 12);
1056 REQ_TALLOC(io, sizeof(*io));
1058 io->writex.level = RAW_WRITE_WRITEX;
1059 io->writex.in.fnum = req_fnum(req, req->in.vwv, VWV(2));
1060 io->writex.in.offset = IVAL(req->in.vwv, VWV(3));
1061 io->writex.in.wmode = SVAL(req->in.vwv, VWV(7));
1062 io->writex.in.remaining = SVAL(req->in.vwv, VWV(8));
1063 io->writex.in.count = SVAL(req->in.vwv, VWV(10));
1064 io->writex.in.data = req->in.hdr + SVAL(req->in.vwv, VWV(11));
1066 if (req->in.wct == 14) {
1067 uint32_t offset_high = IVAL(req->in.vwv, VWV(12));
1068 uint16_t count_high = SVAL(req->in.vwv, VWV(9));
1069 io->writex.in.offset |= (((uint64_t)offset_high) << 32);
1070 io->writex.in.count |= ((uint32_t)count_high) << 16;
1073 /* make sure the data is in bounds */
1074 if (req_data_oob(req, io->writex.in.data, io->writex.in.count)) {
1075 req_reply_error(req, NT_STATUS_FOOBAR);
1079 req->async.send_fn = reply_write_and_X_send;
1080 req->async.private = io;
1083 req->async.status = req->tcon->ntvfs_ops->write(req, io);
1089 /****************************************************************************
1090 Reply to a lseek (async reply)
1091 ****************************************************************************/
1092 static void reply_lseek_send(struct smbsrv_request *req)
1094 struct smb_seek *io = req->async.private;
1098 /* construct reply */
1099 req_setup_reply(req, 2, 0);
1101 SIVALS(req->out.vwv, VWV(0), io->out.offset);
1103 req_send_reply(req);
1106 /****************************************************************************
1108 ****************************************************************************/
1109 void reply_lseek(struct smbsrv_request *req)
1111 struct smb_seek *io;
1113 REQ_CHECK_WCT(req, 4);
1114 REQ_TALLOC(io, sizeof(*io));
1116 io->in.fnum = req_fnum(req, req->in.vwv, VWV(0));
1117 io->in.mode = SVAL(req->in.vwv, VWV(1));
1118 io->in.offset = IVALS(req->in.vwv, VWV(2));
1120 req->async.send_fn = reply_lseek_send;
1121 req->async.private = io;
1124 req->async.status = req->tcon->ntvfs_ops->seek(req, io);
1129 /****************************************************************************
1131 ****************************************************************************/
1132 void reply_flush(struct smbsrv_request *req)
1134 struct smb_flush *io;
1137 REQ_CHECK_WCT(req, 1);
1138 REQ_TALLOC(io, sizeof(*io));
1140 io->in.fnum = req_fnum(req, req->in.vwv, VWV(0));
1142 req->async.send_fn = reply_simple_send;
1145 req->async.status = req->tcon->ntvfs_ops->flush(req, io);
1151 /****************************************************************************
1152 Reply to a exit. This closes all files open by a smbpid
1153 ****************************************************************************/
1154 void reply_exit(struct smbsrv_request *req)
1157 struct smbsrv_tcon *tcon;
1158 REQ_CHECK_WCT(req, 0);
1160 for (tcon=req->smb_conn->tree.tcons;tcon;tcon=tcon->next) {
1162 status = tcon->ntvfs_ops->exit(req);
1164 if (!NT_STATUS_IS_OK(status)) {
1165 req_reply_error(req, status);
1170 req_setup_reply(req, 0, 0);
1171 req_send_reply(req);
1175 /****************************************************************************
1178 Note that this has to deal with closing a directory opened by NT SMB's.
1179 ****************************************************************************/
1180 void reply_close(struct smbsrv_request *req)
1182 union smb_close *io;
1185 REQ_CHECK_WCT(req, 3);
1186 REQ_TALLOC(io, sizeof(*io));
1188 io->close.level = RAW_CLOSE_CLOSE;
1189 io->close.in.fnum = req_fnum(req, req->in.vwv, VWV(0));
1190 io->close.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(1));
1192 req->async.send_fn = reply_simple_send;
1195 req->async.status = req->tcon->ntvfs_ops->close(req, io);
1202 /****************************************************************************
1203 Reply to a writeclose (async reply)
1204 ****************************************************************************/
1205 static void reply_writeclose_send(struct smbsrv_request *req)
1207 union smb_write *io = req->async.private;
1211 /* construct reply */
1212 req_setup_reply(req, 1, 0);
1214 SSVAL(req->out.vwv, VWV(0), io->write.out.nwritten);
1216 req_send_reply(req);
1219 /****************************************************************************
1220 Reply to a writeclose (Core+ protocol).
1221 ****************************************************************************/
1222 void reply_writeclose(struct smbsrv_request *req)
1224 union smb_write *io;
1226 /* this one is pretty weird - the wct can be 6 or 12 */
1227 if (req->in.wct != 12) {
1228 REQ_CHECK_WCT(req, 6);
1231 REQ_TALLOC(io, sizeof(*io));
1233 io->writeclose.level = RAW_WRITE_WRITECLOSE;
1234 io->writeclose.in.fnum = req_fnum(req, req->in.vwv, VWV(0));
1235 io->writeclose.in.count = SVAL(req->in.vwv, VWV(1));
1236 io->writeclose.in.offset = IVAL(req->in.vwv, VWV(2));
1237 io->writeclose.in.mtime = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(4));
1238 io->writeclose.in.data = req->in.data + 1;
1240 /* make sure they gave us the data they promised */
1241 if (req_data_oob(req, io->writeclose.in.data, io->writeclose.in.count)) {
1242 req_reply_error(req, NT_STATUS_FOOBAR);
1246 req->async.send_fn = reply_writeclose_send;
1247 req->async.private = io;
1250 req->async.status = req->tcon->ntvfs_ops->write(req, io);
1255 /****************************************************************************
1257 ****************************************************************************/
1258 void reply_lock(struct smbsrv_request *req)
1260 union smb_lock *lck;
1263 REQ_CHECK_WCT(req, 5);
1264 REQ_TALLOC(lck, sizeof(*lck));
1266 lck->lock.level = RAW_LOCK_LOCK;
1267 lck->lock.in.fnum = req_fnum(req, req->in.vwv, VWV(0));
1268 lck->lock.in.count = IVAL(req->in.vwv, VWV(1));
1269 lck->lock.in.offset = IVAL(req->in.vwv, VWV(3));
1271 req->async.send_fn = reply_simple_send;
1274 req->async.status = req->tcon->ntvfs_ops->lock(req, lck);
1280 /****************************************************************************
1282 ****************************************************************************/
1283 void reply_unlock(struct smbsrv_request *req)
1285 union smb_lock *lck;
1288 REQ_CHECK_WCT(req, 5);
1289 REQ_TALLOC(lck, sizeof(*lck));
1291 lck->unlock.level = RAW_LOCK_UNLOCK;
1292 lck->unlock.in.fnum = req_fnum(req, req->in.vwv, VWV(0));
1293 lck->unlock.in.count = IVAL(req->in.vwv, VWV(1));
1294 lck->unlock.in.offset = IVAL(req->in.vwv, VWV(3));
1296 req->async.send_fn = reply_simple_send;
1299 req->async.status = req->tcon->ntvfs_ops->lock(req, lck);
1305 /****************************************************************************
1307 ****************************************************************************/
1308 void reply_tdis(struct smbsrv_request *req)
1310 REQ_CHECK_WCT(req, 0);
1312 close_cnum(req->tcon);
1314 /* construct reply */
1315 req_setup_reply(req, 0, 0);
1317 req_send_reply(req);
1321 /****************************************************************************
1322 Reply to a echo. This is one of the few calls that is handled directly (the
1323 backends don't see it at all)
1324 ****************************************************************************/
1325 void reply_echo(struct smbsrv_request *req)
1330 REQ_CHECK_WCT(req, 0);
1332 count = SVAL(req->in.vwv, VWV(0));
1334 req_setup_reply(req, 1, req->in.data_size);
1336 memcpy(req->out.data, req->in.data, req->in.data_size);
1338 for (i=1; i <= count;i++) {
1340 talloc_increase_ref_count(req);
1343 SSVAL(req->out.vwv, VWV(0), i);
1344 req_send_reply(req);
1350 /****************************************************************************
1351 Reply to a printopen (async reply)
1352 ****************************************************************************/
1353 static void reply_printopen_send(struct smbsrv_request *req)
1355 union smb_open *oi = req->async.private;
1359 /* construct reply */
1360 req_setup_reply(req, 1, 0);
1362 SSVAL(req->out.vwv, VWV(0), oi->open.out.fnum);
1364 req_send_reply(req);
1367 /****************************************************************************
1368 Reply to a printopen.
1369 ****************************************************************************/
1370 void reply_printopen(struct smbsrv_request *req)
1375 REQ_CHECK_WCT(req, 2);
1376 REQ_TALLOC(oi, sizeof(*oi));
1378 oi->splopen.level = RAW_OPEN_SPLOPEN;
1379 oi->splopen.in.setup_length = SVAL(req->in.vwv, VWV(0));
1380 oi->splopen.in.mode = SVAL(req->in.vwv, VWV(1));
1382 req_pull_ascii4(req, &oi->splopen.in.ident, req->in.data, STR_TERMINATE);
1384 req->async.send_fn = reply_printopen_send;
1385 req->async.private = oi;
1388 req->async.status = req->tcon->ntvfs_ops->open(req, oi);
1393 /****************************************************************************
1394 Reply to a printclose.
1395 ****************************************************************************/
1396 void reply_printclose(struct smbsrv_request *req)
1398 union smb_close *io;
1401 REQ_CHECK_WCT(req, 3);
1402 REQ_TALLOC(io, sizeof(*io));
1404 io->splclose.level = RAW_CLOSE_SPLCLOSE;
1405 io->splclose.in.fnum = req_fnum(req, req->in.vwv, VWV(0));
1407 req->async.send_fn = reply_simple_send;
1410 req->async.status = req->tcon->ntvfs_ops->close(req, io);
1415 /****************************************************************************
1416 Reply to a printqueue.
1417 ****************************************************************************/
1418 void reply_printqueue_send(struct smbsrv_request *req)
1420 union smb_lpq *lpq = req->async.private;
1422 const uint_t el_size = 28;
1426 /* construct reply */
1427 req_setup_reply(req, 2, 0);
1429 /* truncate the returned list to fit in the negotiated buffer size */
1430 maxcount = (req_max_data(req) - 3) / el_size;
1431 if (maxcount < lpq->retq.out.count) {
1432 lpq->retq.out.count = maxcount;
1435 /* setup enough space in the reply */
1436 req_grow_data(req, 3 + el_size*lpq->retq.out.count);
1438 /* and fill it in */
1439 SSVAL(req->out.vwv, VWV(0), lpq->retq.out.count);
1440 SSVAL(req->out.vwv, VWV(1), lpq->retq.out.restart_idx);
1442 SCVAL(req->out.data, 0, SMB_DATA_BLOCK);
1443 SSVAL(req->out.data, 1, el_size*lpq->retq.out.count);
1445 req->out.ptr = req->out.data + 3;
1447 for (i=0;i<lpq->retq.out.count;i++) {
1448 srv_push_dos_date2(req->smb_conn, req->out.ptr, 0 , lpq->retq.out.queue[i].time);
1449 SCVAL(req->out.ptr, 4, lpq->retq.out.queue[i].status);
1450 SSVAL(req->out.ptr, 5, lpq->retq.out.queue[i].job);
1451 SIVAL(req->out.ptr, 7, lpq->retq.out.queue[i].size);
1452 SCVAL(req->out.ptr, 11, 0); /* reserved */
1453 req_push_str(req, req->out.ptr+12, lpq->retq.out.queue[i].user, 16, STR_ASCII);
1454 req->out.ptr += el_size;
1457 req_send_reply(req);
1460 /****************************************************************************
1461 Reply to a printqueue.
1462 ****************************************************************************/
1463 void reply_printqueue(struct smbsrv_request *req)
1468 REQ_CHECK_WCT(req, 2);
1469 REQ_TALLOC(lpq, sizeof(*lpq));
1471 lpq->retq.level = RAW_LPQ_RETQ;
1472 lpq->retq.in.maxcount = SVAL(req->in.vwv, VWV(0));
1473 lpq->retq.in.startidx = SVAL(req->in.vwv, VWV(1));
1475 req->async.send_fn = reply_printqueue_send;
1476 req->async.private = lpq;
1479 req->async.status = req->tcon->ntvfs_ops->lpq(req, lpq);
1485 /****************************************************************************
1486 Reply to a printwrite.
1487 ****************************************************************************/
1488 void reply_printwrite(struct smbsrv_request *req)
1490 union smb_write *io;
1493 REQ_CHECK_WCT(req, 1);
1494 REQ_TALLOC(io, sizeof(*io));
1496 io->splwrite.level = RAW_WRITE_SPLWRITE;
1498 if (req->in.data_size < 3) {
1499 req_reply_error(req, NT_STATUS_FOOBAR);
1503 io->splwrite.in.fnum = req_fnum(req, req->in.vwv, VWV(0));
1504 io->splwrite.in.count = SVAL(req->in.data, 1);
1505 io->splwrite.in.data = req->in.data + 3;
1507 /* make sure they gave us the data they promised */
1508 if (req_data_oob(req, io->splwrite.in.data, io->splwrite.in.count)) {
1509 req_reply_error(req, NT_STATUS_FOOBAR);
1513 req->async.send_fn = reply_simple_send;
1516 req->async.status = req->tcon->ntvfs_ops->write(req, io);
1522 /****************************************************************************
1524 ****************************************************************************/
1525 void reply_mkdir(struct smbsrv_request *req)
1527 union smb_mkdir *io;
1529 /* parse the request */
1530 REQ_CHECK_WCT(req, 0);
1531 REQ_TALLOC(io, sizeof(*io));
1533 io->generic.level = RAW_MKDIR_MKDIR;
1534 req_pull_ascii4(req, &io->mkdir.in.path, req->in.data, STR_TERMINATE);
1536 req->async.send_fn = reply_simple_send;
1539 req->async.status = req->tcon->ntvfs_ops->mkdir(req, io);
1545 /****************************************************************************
1547 ****************************************************************************/
1548 void reply_rmdir(struct smbsrv_request *req)
1550 struct smb_rmdir *io;
1552 /* parse the request */
1553 REQ_CHECK_WCT(req, 0);
1554 REQ_TALLOC(io, sizeof(*io));
1556 req_pull_ascii4(req, &io->in.path, req->in.data, STR_TERMINATE);
1558 req->async.send_fn = reply_simple_send;
1561 req->async.status = req->tcon->ntvfs_ops->rmdir(req, io);
1567 /****************************************************************************
1569 ****************************************************************************/
1570 void reply_mv(struct smbsrv_request *req)
1572 union smb_rename *io;
1575 /* parse the request */
1576 REQ_CHECK_WCT(req, 1);
1577 REQ_TALLOC(io, sizeof(*io));
1579 io->generic.level = RAW_RENAME_RENAME;
1580 io->rename.in.attrib = SVAL(req->in.vwv, VWV(0));
1583 p += req_pull_ascii4(req, &io->rename.in.pattern1, p, STR_TERMINATE);
1584 p += req_pull_ascii4(req, &io->rename.in.pattern2, p, STR_TERMINATE);
1586 if (!io->rename.in.pattern1 || !io->rename.in.pattern2) {
1587 req_reply_error(req, NT_STATUS_FOOBAR);
1591 req->async.send_fn = reply_simple_send;
1594 req->async.status = req->tcon->ntvfs_ops->rename(req, io);
1600 /****************************************************************************
1601 Reply to an NT rename.
1602 ****************************************************************************/
1603 void reply_ntrename(struct smbsrv_request *req)
1605 union smb_rename *io;
1608 /* parse the request */
1609 REQ_CHECK_WCT(req, 4);
1610 REQ_TALLOC(io, sizeof(*io));
1612 io->generic.level = RAW_RENAME_NTRENAME;
1613 io->ntrename.in.attrib = SVAL(req->in.vwv, VWV(0));
1614 io->ntrename.in.flags = SVAL(req->in.vwv, VWV(1));
1615 io->ntrename.in.cluster_size = IVAL(req->in.vwv, VWV(2));
1618 p += req_pull_ascii4(req, &io->ntrename.in.old_name, p, STR_TERMINATE);
1619 p += req_pull_ascii4(req, &io->ntrename.in.new_name, p, STR_TERMINATE);
1621 if (!io->ntrename.in.old_name || !io->ntrename.in.new_name) {
1622 req_reply_error(req, NT_STATUS_FOOBAR);
1626 req->async.send_fn = reply_simple_send;
1629 req->async.status = req->tcon->ntvfs_ops->rename(req, io);
1634 /****************************************************************************
1635 Reply to a file copy (async reply)
1636 ****************************************************************************/
1637 static void reply_copy_send(struct smbsrv_request *req)
1639 struct smb_copy *cp = req->async.private;
1643 /* build the reply */
1644 req_setup_reply(req, 1, 0);
1646 SSVAL(req->out.vwv, VWV(0), cp->out.count);
1648 req_send_reply(req);
1651 /****************************************************************************
1652 Reply to a file copy.
1653 ****************************************************************************/
1654 void reply_copy(struct smbsrv_request *req)
1656 struct smb_copy *cp;
1660 REQ_CHECK_WCT(req, 3);
1661 REQ_TALLOC(cp, sizeof(*cp));
1663 cp->in.tid2 = SVAL(req->in.vwv, VWV(0));
1664 cp->in.ofun = SVAL(req->in.vwv, VWV(1));
1665 cp->in.flags = SVAL(req->in.vwv, VWV(2));
1668 p += req_pull_ascii4(req, &cp->in.path1, p, STR_TERMINATE);
1669 p += req_pull_ascii4(req, &cp->in.path2, p, STR_TERMINATE);
1671 if (!cp->in.path1 || !cp->in.path2) {
1672 req_reply_error(req, NT_STATUS_FOOBAR);
1676 req->async.send_fn = reply_copy_send;
1677 req->async.private = cp;
1680 req->async.status = req->tcon->ntvfs_ops->copy(req, cp);
1685 /****************************************************************************
1686 Reply to a lockingX request (async send)
1687 ****************************************************************************/
1688 static void reply_lockingX_send(struct smbsrv_request *req)
1690 union smb_lock *lck = req->async.private;
1694 /* if it was an oplock break ack then we only send a reply if
1695 there was an error */
1696 if (lck->lockx.in.ulock_cnt + lck->lockx.in.lock_cnt == 0) {
1701 /* construct reply */
1702 req_setup_reply(req, 2, 0);
1704 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1705 SSVAL(req->out.vwv, VWV(1), 0);
1711 /****************************************************************************
1712 Reply to a lockingX request.
1713 ****************************************************************************/
1714 void reply_lockingX(struct smbsrv_request *req)
1716 union smb_lock *lck;
1717 uint_t total_locks, i;
1722 REQ_CHECK_WCT(req, 8);
1723 REQ_TALLOC(lck, sizeof(*lck));
1725 lck->lockx.level = RAW_LOCK_LOCKX;
1726 lck->lockx.in.fnum = req_fnum(req, req->in.vwv, VWV(2));
1727 lck->lockx.in.mode = SVAL(req->in.vwv, VWV(3));
1728 lck->lockx.in.timeout = IVAL(req->in.vwv, VWV(4));
1729 lck->lockx.in.ulock_cnt = SVAL(req->in.vwv, VWV(6));
1730 lck->lockx.in.lock_cnt = SVAL(req->in.vwv, VWV(7));
1732 total_locks = lck->lockx.in.ulock_cnt + lck->lockx.in.lock_cnt;
1734 /* there are two variants, one with 64 bit offsets and counts */
1735 if (lck->lockx.in.mode & LOCKING_ANDX_LARGE_FILES) {
1741 /* make sure we got the promised data */
1742 if (req_data_oob(req, req->in.data, total_locks * lck_size)) {
1743 req_reply_error(req, NT_STATUS_FOOBAR);
1747 /* allocate the locks array */
1749 REQ_TALLOC(lck->lockx.in.locks, total_locks * sizeof(lck->lockx.in.locks[0]));
1754 /* construct the locks array */
1755 for (i=0;i<total_locks;i++) {
1756 uint32_t ofs_high=0, count_high=0;
1758 lck->lockx.in.locks[i].pid = SVAL(p, 0);
1760 if (lck->lockx.in.mode & LOCKING_ANDX_LARGE_FILES) {
1761 ofs_high = IVAL(p, 4);
1762 lck->lockx.in.locks[i].offset = IVAL(p, 8);
1763 count_high = IVAL(p, 12);
1764 lck->lockx.in.locks[i].count = IVAL(p, 16);
1766 lck->lockx.in.locks[i].offset = IVAL(p, 2);
1767 lck->lockx.in.locks[i].count = IVAL(p, 6);
1769 if (ofs_high != 0 || count_high != 0) {
1770 lck->lockx.in.locks[i].count |= ((uint64_t)count_high) << 32;
1771 lck->lockx.in.locks[i].offset |= ((uint64_t)ofs_high) << 32;
1776 req->async.send_fn = reply_lockingX_send;
1777 req->async.private = lck;
1780 req->async.status = req->tcon->ntvfs_ops->lock(req, lck);
1785 /****************************************************************************
1786 Reply to a SMBreadbmpx (read block multiplex) request.
1787 ****************************************************************************/
1788 void reply_readbmpx(struct smbsrv_request *req)
1790 /* tell the client to not use a multiplexed read - its too broken to use */
1791 req_reply_dos_error(req, ERRSRV, ERRuseSTD);
1795 /****************************************************************************
1796 Reply to a SMBsetattrE.
1797 ****************************************************************************/
1798 void reply_setattrE(struct smbsrv_request *req)
1800 union smb_setfileinfo *info;
1803 REQ_CHECK_WCT(req, 7);
1804 REQ_TALLOC(info, sizeof(*info));
1806 info->setattre.level = RAW_SFILEINFO_SETATTRE;
1807 info->setattre.file.fnum = req_fnum(req, req->in.vwv, VWV(0));
1808 info->setattre.in.create_time = srv_pull_dos_date2(req->smb_conn, req->in.vwv + VWV(1));
1809 info->setattre.in.access_time = srv_pull_dos_date2(req->smb_conn, req->in.vwv + VWV(3));
1810 info->setattre.in.write_time = srv_pull_dos_date2(req->smb_conn, req->in.vwv + VWV(5));
1812 req->async.send_fn = reply_simple_send;
1815 req->async.status = req->tcon->ntvfs_ops->setfileinfo(req, info);
1821 /****************************************************************************
1822 Reply to a SMBwritebmpx (write block multiplex primary) request.
1823 ****************************************************************************/
1824 void reply_writebmpx(struct smbsrv_request *req)
1826 /* we will need to implement this one for OS/2, but right now I can't be bothered */
1827 req_reply_error(req, NT_STATUS_FOOBAR);
1831 /****************************************************************************
1832 Reply to a SMBwritebs (write block multiplex secondary) request.
1833 ****************************************************************************/
1834 void reply_writebs(struct smbsrv_request *req)
1836 /* see reply_writebmpx */
1837 req_reply_error(req, NT_STATUS_FOOBAR);
1842 /****************************************************************************
1843 Reply to a SMBgetattrE (async reply)
1844 ****************************************************************************/
1845 static void reply_getattrE_send(struct smbsrv_request *req)
1847 union smb_fileinfo *info = req->async.private;
1852 req_setup_reply(req, 11, 0);
1854 srv_push_dos_date2(req->smb_conn, req->out.vwv, VWV(0), info->getattre.out.create_time);
1855 srv_push_dos_date2(req->smb_conn, req->out.vwv, VWV(2), info->getattre.out.access_time);
1856 srv_push_dos_date2(req->smb_conn, req->out.vwv, VWV(4), info->getattre.out.write_time);
1857 SIVAL(req->out.vwv, VWV(6), info->getattre.out.size);
1858 SIVAL(req->out.vwv, VWV(8), info->getattre.out.alloc_size);
1859 SSVAL(req->out.vwv, VWV(10), info->getattre.out.attrib);
1861 req_send_reply(req);
1864 /****************************************************************************
1865 Reply to a SMBgetattrE.
1866 ****************************************************************************/
1867 void reply_getattrE(struct smbsrv_request *req)
1869 union smb_fileinfo *info;
1872 REQ_CHECK_WCT(req, 1);
1873 REQ_TALLOC(info, sizeof(*info));
1875 info->getattr.level = RAW_FILEINFO_GETATTRE;
1876 info->getattr.in.fnum = req_fnum(req, req->in.vwv, VWV(0));
1878 req->async.send_fn = reply_getattrE_send;
1879 req->async.private = info;
1882 req->async.status = req->tcon->ntvfs_ops->qfileinfo(req, info);
1888 /****************************************************************************
1889 reply to an old style session setup command
1890 ****************************************************************************/
1891 static void reply_sesssetup_old(struct smbsrv_request *req)
1894 union smb_sesssetup sess;
1898 sess.old.level = RAW_SESSSETUP_OLD;
1901 sess.old.in.bufsize = SVAL(req->in.vwv, VWV(2));
1902 sess.old.in.mpx_max = SVAL(req->in.vwv, VWV(3));
1903 sess.old.in.vc_num = SVAL(req->in.vwv, VWV(4));
1904 sess.old.in.sesskey = IVAL(req->in.vwv, VWV(5));
1905 passlen = SVAL(req->in.vwv, VWV(7));
1907 /* check the request isn't malformed */
1908 if (req_data_oob(req, req->in.data, passlen)) {
1909 req_reply_error(req, NT_STATUS_FOOBAR);
1914 if (!req_pull_blob(req, p, passlen, &sess.old.in.password)) {
1915 req_reply_error(req, NT_STATUS_FOOBAR);
1920 p += req_pull_string(req, &sess.old.in.user, p, -1, STR_TERMINATE);
1921 p += req_pull_string(req, &sess.old.in.domain, p, -1, STR_TERMINATE);
1922 p += req_pull_string(req, &sess.old.in.os, p, -1, STR_TERMINATE);
1923 p += req_pull_string(req, &sess.old.in.lanman, p, -1, STR_TERMINATE);
1925 /* call the generic handler */
1926 status = sesssetup_backend(req, &sess);
1928 if (!NT_STATUS_IS_OK(status)) {
1929 req_reply_error(req, status);
1933 /* construct reply */
1934 req_setup_reply(req, 3, 0);
1936 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1937 SSVAL(req->out.vwv, VWV(1), 0);
1938 SSVAL(req->out.vwv, VWV(2), sess.old.out.action);
1940 SSVAL(req->out.hdr, HDR_UID, sess.old.out.vuid);
1946 /****************************************************************************
1947 reply to an NT1 style session setup command
1948 ****************************************************************************/
1949 static void reply_sesssetup_nt1(struct smbsrv_request *req)
1952 union smb_sesssetup sess;
1954 uint16_t passlen1, passlen2;
1956 sess.nt1.level = RAW_SESSSETUP_NT1;
1959 sess.nt1.in.bufsize = SVAL(req->in.vwv, VWV(2));
1960 sess.nt1.in.mpx_max = SVAL(req->in.vwv, VWV(3));
1961 sess.nt1.in.vc_num = SVAL(req->in.vwv, VWV(4));
1962 sess.nt1.in.sesskey = IVAL(req->in.vwv, VWV(5));
1963 passlen1 = SVAL(req->in.vwv, VWV(7));
1964 passlen2 = SVAL(req->in.vwv, VWV(8));
1965 sess.nt1.in.capabilities = IVAL(req->in.vwv, VWV(11));
1967 /* check the request isn't malformed */
1968 if (req_data_oob(req, req->in.data, passlen1) ||
1969 req_data_oob(req, req->in.data + passlen1, passlen2)) {
1970 req_reply_error(req, NT_STATUS_FOOBAR);
1975 if (!req_pull_blob(req, p, passlen1, &sess.nt1.in.password1)) {
1976 req_reply_error(req, NT_STATUS_FOOBAR);
1980 if (!req_pull_blob(req, p, passlen2, &sess.nt1.in.password2)) {
1981 req_reply_error(req, NT_STATUS_FOOBAR);
1986 p += req_pull_string(req, &sess.nt1.in.user, p, -1, STR_TERMINATE);
1987 p += req_pull_string(req, &sess.nt1.in.domain, p, -1, STR_TERMINATE);
1988 p += req_pull_string(req, &sess.nt1.in.os, p, -1, STR_TERMINATE);
1989 p += req_pull_string(req, &sess.nt1.in.lanman, p, -1, STR_TERMINATE);
1991 /* call the generic handler */
1992 status = sesssetup_backend(req, &sess);
1994 if (!NT_STATUS_IS_OK(status)) {
1995 req_reply_error(req, status);
1999 /* construct reply */
2000 req_setup_reply(req, 3, 0);
2002 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
2003 SSVAL(req->out.vwv, VWV(1), 0);
2004 SSVAL(req->out.vwv, VWV(2), sess.nt1.out.action);
2006 SSVAL(req->out.hdr, HDR_UID, sess.nt1.out.vuid);
2008 req_push_str(req, NULL, sess.nt1.out.os, -1, STR_TERMINATE);
2009 req_push_str(req, NULL, sess.nt1.out.lanman, -1, STR_TERMINATE);
2010 req_push_str(req, NULL, sess.nt1.out.domain, -1, STR_TERMINATE);
2016 /****************************************************************************
2017 reply to an SPNEGO style session setup command
2018 ****************************************************************************/
2019 static void reply_sesssetup_spnego(struct smbsrv_request *req)
2022 union smb_sesssetup sess;
2026 sess.spnego.level = RAW_SESSSETUP_SPNEGO;
2029 sess.spnego.in.bufsize = SVAL(req->in.vwv, VWV(2));
2030 sess.spnego.in.mpx_max = SVAL(req->in.vwv, VWV(3));
2031 sess.spnego.in.vc_num = SVAL(req->in.vwv, VWV(4));
2032 sess.spnego.in.sesskey = IVAL(req->in.vwv, VWV(5));
2033 blob_len = SVAL(req->in.vwv, VWV(7));
2034 sess.spnego.in.capabilities = IVAL(req->in.vwv, VWV(10));
2037 if (!req_pull_blob(req, p, blob_len, &sess.spnego.in.secblob)) {
2038 req_reply_error(req, NT_STATUS_FOOBAR);
2043 p += req_pull_string(req, &sess.spnego.in.os, p, -1, STR_TERMINATE);
2044 p += req_pull_string(req, &sess.spnego.in.lanman, p, -1, STR_TERMINATE);
2045 p += req_pull_string(req, &sess.spnego.in.domain, p, -1, STR_TERMINATE);
2047 /* call the generic handler */
2048 status = sesssetup_backend(req, &sess);
2050 if (!NT_STATUS_IS_OK(status) &&
2051 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
2052 req_reply_error(req, status);
2056 /* construct reply */
2057 req_setup_reply(req, 4, sess.spnego.out.secblob.length);
2059 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
2060 req_setup_error(req, status);
2063 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
2064 SSVAL(req->out.vwv, VWV(1), 0);
2065 SSVAL(req->out.vwv, VWV(2), sess.spnego.out.action);
2066 SSVAL(req->out.vwv, VWV(3), sess.spnego.out.secblob.length);
2068 SSVAL(req->out.hdr, HDR_UID, sess.spnego.out.vuid);
2070 memcpy(req->out.data, sess.spnego.out.secblob.data, sess.spnego.out.secblob.length);
2071 req_push_str(req, NULL, sess.spnego.out.os, -1, STR_TERMINATE);
2072 req_push_str(req, NULL, sess.spnego.out.lanman, -1, STR_TERMINATE);
2073 req_push_str(req, NULL, sess.spnego.out.domain, -1, STR_TERMINATE);
2079 /****************************************************************************
2080 reply to a session setup command
2081 ****************************************************************************/
2082 void reply_sesssetup(struct smbsrv_request *req)
2084 switch (req->in.wct) {
2086 /* a pre-NT1 call */
2087 reply_sesssetup_old(req);
2091 reply_sesssetup_nt1(req);
2095 reply_sesssetup_spnego(req);
2099 /* unsupported variant */
2100 req_reply_error(req, NT_STATUS_FOOBAR);
2103 /****************************************************************************
2104 Reply to a SMBulogoffX.
2105 ****************************************************************************/
2106 void reply_ulogoffX(struct smbsrv_request *req)
2108 struct smbsrv_tcon *tcon;
2112 vuid = SVAL(req->in.hdr, HDR_UID);
2114 /* in user level security we are supposed to close any files
2115 open by this user on all open tree connects */
2116 if ((vuid != 0) && (lp_security() != SEC_SHARE)) {
2117 for (tcon=req->smb_conn->tree.tcons;tcon;tcon=tcon->next) {
2119 status = tcon->ntvfs_ops->logoff(req);
2121 if (!NT_STATUS_IS_OK(status)) {
2122 req_reply_error(req, status);
2128 smbsrv_invalidate_vuid(req->smb_conn, vuid);
2130 req_setup_reply(req, 2, 0);
2132 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
2133 SSVAL(req->out.vwv, VWV(1), 0);
2139 /****************************************************************************
2140 Reply to an SMBfindclose request
2141 ****************************************************************************/
2142 void reply_findclose(struct smbsrv_request *req)
2145 union smb_search_close io;
2147 io.findclose.level = RAW_FINDCLOSE_FINDCLOSE;
2150 REQ_CHECK_WCT(req, 1);
2152 io.findclose.in.handle = SVAL(req->in.vwv, VWV(0));
2155 status = req->tcon->ntvfs_ops->search_close(req, &io);
2157 if (!NT_STATUS_IS_OK(status)) {
2158 req_reply_error(req, status);
2162 /* construct reply */
2163 req_setup_reply(req, 0, 0);
2165 req_send_reply(req);
2168 /****************************************************************************
2169 Reply to an SMBfindnclose request
2170 ****************************************************************************/
2171 void reply_findnclose(struct smbsrv_request *req)
2173 req_reply_error(req, NT_STATUS_FOOBAR);
2177 /****************************************************************************
2178 Reply to an SMBntcreateX request (async send)
2179 ****************************************************************************/
2180 static void reply_ntcreate_and_X_send(struct smbsrv_request *req)
2182 union smb_open *io = req->async.private;
2186 /* construct reply */
2187 req_setup_reply(req, 34, 0);
2189 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
2190 SSVAL(req->out.vwv, VWV(1), 0);
2191 SCVAL(req->out.vwv, VWV(2), io->ntcreatex.out.oplock_level);
2193 /* the rest of the parameters are not aligned! */
2194 SSVAL(req->out.vwv, 5, io->ntcreatex.out.fnum);
2195 SIVAL(req->out.vwv, 7, io->ntcreatex.out.create_action);
2196 push_nttime(req->out.vwv, 11, io->ntcreatex.out.create_time);
2197 push_nttime(req->out.vwv, 19, io->ntcreatex.out.access_time);
2198 push_nttime(req->out.vwv, 27, io->ntcreatex.out.write_time);
2199 push_nttime(req->out.vwv, 35, io->ntcreatex.out.change_time);
2200 SIVAL(req->out.vwv, 43, io->ntcreatex.out.attrib);
2201 SBVAL(req->out.vwv, 47, io->ntcreatex.out.alloc_size);
2202 SBVAL(req->out.vwv, 55, io->ntcreatex.out.size);
2203 SSVAL(req->out.vwv, 63, io->ntcreatex.out.file_type);
2204 SSVAL(req->out.vwv, 65, io->ntcreatex.out.ipc_state);
2205 SCVAL(req->out.vwv, 67, io->ntcreatex.out.is_directory);
2210 /****************************************************************************
2211 Reply to an SMBntcreateX request
2212 ****************************************************************************/
2213 void reply_ntcreate_and_X(struct smbsrv_request *req)
2218 /* parse the request */
2219 REQ_CHECK_WCT(req, 24);
2220 REQ_TALLOC(io, sizeof(*io));
2222 io->ntcreatex.level = RAW_OPEN_NTCREATEX;
2224 /* notice that the word parameters are not word aligned, so we don't use VWV() */
2225 fname_len = SVAL(req->in.vwv, 5);
2226 io->ntcreatex.in.flags = IVAL(req->in.vwv, 7);
2227 io->ntcreatex.in.root_fid = IVAL(req->in.vwv, 11);
2228 io->ntcreatex.in.access_mask = IVAL(req->in.vwv, 15);
2229 io->ntcreatex.in.alloc_size = BVAL(req->in.vwv, 19);
2230 io->ntcreatex.in.file_attr = IVAL(req->in.vwv, 27);
2231 io->ntcreatex.in.share_access = IVAL(req->in.vwv, 31);
2232 io->ntcreatex.in.open_disposition = IVAL(req->in.vwv, 35);
2233 io->ntcreatex.in.create_options = IVAL(req->in.vwv, 39);
2234 io->ntcreatex.in.impersonation = IVAL(req->in.vwv, 43);
2235 io->ntcreatex.in.security_flags = CVAL(req->in.vwv, 47);
2237 /* we need a neater way to handle this alignment */
2238 if ((req->flags2 & FLAGS2_UNICODE_STRINGS) &&
2239 ucs2_align(req->in.buffer, req->in.data, STR_TERMINATE|STR_UNICODE)) {
2243 req_pull_string(req, &io->ntcreatex.in.fname, req->in.data, fname_len, STR_TERMINATE);
2244 if (!io->ntcreatex.in.fname) {
2245 req_reply_error(req, NT_STATUS_FOOBAR);
2249 req->async.send_fn = reply_ntcreate_and_X_send;
2250 req->async.private = io;
2252 /* call the backend */
2253 req->async.status = req->tcon->ntvfs_ops->open(req, io);
2259 /****************************************************************************
2260 Reply to an SMBntcancel request
2261 ****************************************************************************/
2262 void reply_ntcancel(struct smbsrv_request *req)
2264 req_reply_error(req, NT_STATUS_FOOBAR);
2267 /****************************************************************************
2268 Reply to an SMBsends request
2269 ****************************************************************************/
2270 void reply_sends(struct smbsrv_request *req)
2272 req_reply_error(req, NT_STATUS_FOOBAR);
2275 /****************************************************************************
2276 Reply to an SMBsendstrt request
2277 ****************************************************************************/
2278 void reply_sendstrt(struct smbsrv_request *req)
2280 req_reply_error(req, NT_STATUS_FOOBAR);
2283 /****************************************************************************
2284 Reply to an SMBsendend request
2285 ****************************************************************************/
2286 void reply_sendend(struct smbsrv_request *req)
2288 req_reply_error(req, NT_STATUS_FOOBAR);
2291 /****************************************************************************
2292 Reply to an SMBsendtxt request
2293 ****************************************************************************/
2294 void reply_sendtxt(struct smbsrv_request *req)
2296 req_reply_error(req, NT_STATUS_FOOBAR);
2301 /****************************************************************************
2302 Reply to a special message - a SMB packet with non zero NBT message type
2303 ****************************************************************************/
2304 void reply_special(struct smbsrv_request *req)
2309 msg_type = CVAL(req->in.buffer,0);
2314 case 0x81: /* session request */
2315 if (req->smb_conn->negotiate.done_nbt_session) {
2316 smbsrv_terminate_connection(req->smb_conn, "multiple session request not permitted");
2322 DEBUG(0,("REWRITE: not parsing netbios names in NBT session request!\n"));
2323 /* TODO: store the name for the session setup 'remote machine' code, as well as smbstatus */
2325 req->smb_conn->negotiate.done_nbt_session = True;
2327 req->out.buffer = buf;
2329 req_send_reply_nosign(req);
2332 case 0x89: /* session keepalive request
2333 (some old clients produce this?) */
2334 SCVAL(buf, 0, SMBkeepalive);
2336 req->out.buffer = buf;
2338 req_send_reply_nosign(req);
2342 /* session keepalive - swallow it */
2347 DEBUG(0,("Unexpected NBT session packet (%d)\n", msg_type));