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 2 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, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 This file handles most of the reply_ calls that the server
24 makes to handle specific SMB commands
28 #include "smb_server/smb_server.h"
29 #include "ntvfs/ntvfs.h"
30 #include "librpc/gen_ndr/ndr_nbt.h"
33 /****************************************************************************
34 Reply to a simple request (async send)
35 ****************************************************************************/
36 static void reply_simple_send(struct ntvfs_request *ntvfs)
38 struct smbsrv_request *req;
40 SMBSRV_CHECK_ASYNC_STATUS_SIMPLE;
42 smbsrv_setup_reply(req, 0, 0);
43 smbsrv_send_reply(req);
47 /****************************************************************************
49 ****************************************************************************/
50 void smbsrv_reply_tcon(struct smbsrv_request *req)
57 SMBSRV_CHECK_WCT(req, 0);
59 con.tcon.level = RAW_TCON_TCON;
62 p += req_pull_ascii4(req, &con.tcon.in.service, p, STR_TERMINATE);
63 p += req_pull_ascii4(req, &con.tcon.in.password, p, STR_TERMINATE);
64 p += req_pull_ascii4(req, &con.tcon.in.dev, p, STR_TERMINATE);
66 if (!con.tcon.in.service || !con.tcon.in.password || !con.tcon.in.dev) {
67 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
72 status = smbsrv_tcon_backend(req, &con);
74 if (!NT_STATUS_IS_OK(status)) {
75 smbsrv_send_error(req, status);
80 smbsrv_setup_reply(req, 2, 0);
82 SSVAL(req->out.vwv, VWV(0), con.tcon.out.max_xmit);
83 SSVAL(req->out.vwv, VWV(1), con.tcon.out.tid);
84 SSVAL(req->out.hdr, HDR_TID, req->tcon->tid);
86 smbsrv_send_reply(req);
90 /****************************************************************************
91 Reply to a tcon and X.
92 ****************************************************************************/
93 void smbsrv_reply_tcon_and_X(struct smbsrv_request *req)
100 con.tconx.level = RAW_TCON_TCONX;
103 SMBSRV_CHECK_WCT(req, 4);
105 con.tconx.in.flags = SVAL(req->in.vwv, VWV(2));
106 passlen = SVAL(req->in.vwv, VWV(3));
110 if (!req_pull_blob(req, p, passlen, &con.tconx.in.password)) {
111 smbsrv_send_error(req, NT_STATUS_ILL_FORMED_PASSWORD);
116 p += req_pull_string(req, &con.tconx.in.path, p, -1, STR_TERMINATE);
117 p += req_pull_string(req, &con.tconx.in.device, p, -1, STR_ASCII);
119 if (!con.tconx.in.path || !con.tconx.in.device) {
120 smbsrv_send_error(req, NT_STATUS_BAD_DEVICE_TYPE);
125 status = smbsrv_tcon_backend(req, &con);
127 if (!NT_STATUS_IS_OK(status)) {
128 smbsrv_send_error(req, status);
132 /* construct reply - two variants */
133 if (req->smb_conn->negotiate.protocol < PROTOCOL_NT1) {
134 smbsrv_setup_reply(req, 2, 0);
136 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
137 SSVAL(req->out.vwv, VWV(1), 0);
139 req_push_str(req, NULL, con.tconx.out.dev_type, -1, STR_TERMINATE|STR_ASCII);
141 smbsrv_setup_reply(req, 3, 0);
143 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
144 SSVAL(req->out.vwv, VWV(1), 0);
145 SSVAL(req->out.vwv, VWV(2), con.tconx.out.options);
147 req_push_str(req, NULL, con.tconx.out.dev_type, -1, STR_TERMINATE|STR_ASCII);
148 req_push_str(req, NULL, con.tconx.out.fs_type, -1, STR_TERMINATE);
151 /* set the incoming and outgoing tid to the just created one */
152 SSVAL(req->in.hdr, HDR_TID, con.tconx.out.tid);
153 SSVAL(req->out.hdr,HDR_TID, con.tconx.out.tid);
155 smbsrv_chain_reply(req);
159 /****************************************************************************
160 Reply to an unknown request
161 ****************************************************************************/
162 void smbsrv_reply_unknown(struct smbsrv_request *req)
166 type = CVAL(req->in.hdr, HDR_COM);
168 DEBUG(0,("unknown command type %d (0x%X)\n", type, type));
170 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRunknownsmb));
174 /****************************************************************************
175 Reply to an ioctl (async reply)
176 ****************************************************************************/
177 static void reply_ioctl_send(struct ntvfs_request *ntvfs)
179 struct smbsrv_request *req;
182 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_ioctl);
184 /* the +1 is for nicer alignment */
185 smbsrv_setup_reply(req, 8, io->ioctl.out.blob.length+1);
186 SSVAL(req->out.vwv, VWV(1), io->ioctl.out.blob.length);
187 SSVAL(req->out.vwv, VWV(5), io->ioctl.out.blob.length);
188 SSVAL(req->out.vwv, VWV(6), PTR_DIFF(req->out.data, req->out.hdr) + 1);
190 memcpy(req->out.data+1, io->ioctl.out.blob.data, io->ioctl.out.blob.length);
192 smbsrv_send_reply(req);
195 /****************************************************************************
197 ****************************************************************************/
198 void smbsrv_reply_ioctl(struct smbsrv_request *req)
203 SMBSRV_CHECK_WCT(req, 3);
204 SMBSRV_TALLOC_IO_PTR(io, union smb_ioctl);
205 SMBSRV_SETUP_NTVFS_REQUEST(reply_ioctl_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
207 io->ioctl.level = RAW_IOCTL_IOCTL;
208 io->ioctl.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
209 io->ioctl.in.request = IVAL(req->in.vwv, VWV(1));
211 SMBSRV_CHECK_FILE_HANDLE_ERROR(io->ioctl.in.file.ntvfs,
212 NT_STATUS_DOS(ERRSRV, ERRerror));
213 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_ioctl(req->ntvfs, io));
217 /****************************************************************************
219 ****************************************************************************/
220 void smbsrv_reply_chkpth(struct smbsrv_request *req)
222 union smb_chkpath *io;
224 SMBSRV_TALLOC_IO_PTR(io, union smb_chkpath);
225 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
227 req_pull_ascii4(req, &io->chkpath.in.path, req->in.data, STR_TERMINATE);
229 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_chkpath(req->ntvfs, io));
232 /****************************************************************************
233 Reply to a getatr (async reply)
234 ****************************************************************************/
235 static void reply_getatr_send(struct ntvfs_request *ntvfs)
237 struct smbsrv_request *req;
238 union smb_fileinfo *st;
240 SMBSRV_CHECK_ASYNC_STATUS(st, union smb_fileinfo);
242 /* construct reply */
243 smbsrv_setup_reply(req, 10, 0);
245 SSVAL(req->out.vwv, VWV(0), st->getattr.out.attrib);
246 srv_push_dos_date3(req->smb_conn, req->out.vwv, VWV(1), st->getattr.out.write_time);
247 SIVAL(req->out.vwv, VWV(3), st->getattr.out.size);
249 SMBSRV_VWV_RESERVED(5, 5);
251 smbsrv_send_reply(req);
255 /****************************************************************************
257 ****************************************************************************/
258 void smbsrv_reply_getatr(struct smbsrv_request *req)
260 union smb_fileinfo *st;
262 SMBSRV_TALLOC_IO_PTR(st, union smb_fileinfo);
263 SMBSRV_SETUP_NTVFS_REQUEST(reply_getatr_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
265 st->getattr.level = RAW_FILEINFO_GETATTR;
268 req_pull_ascii4(req, &st->getattr.in.file.path, req->in.data, STR_TERMINATE);
269 if (!st->getattr.in.file.path) {
270 smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
274 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_qpathinfo(req->ntvfs, st));
278 /****************************************************************************
280 ****************************************************************************/
281 void smbsrv_reply_setatr(struct smbsrv_request *req)
283 union smb_setfileinfo *st;
286 SMBSRV_CHECK_WCT(req, 8);
287 SMBSRV_TALLOC_IO_PTR(st, union smb_setfileinfo);
288 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
290 st->setattr.level = RAW_SFILEINFO_SETATTR;
291 st->setattr.in.attrib = SVAL(req->in.vwv, VWV(0));
292 st->setattr.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(1));
294 req_pull_ascii4(req, &st->setattr.in.file.path, req->in.data, STR_TERMINATE);
296 if (!st->setattr.in.file.path) {
297 smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
301 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_setpathinfo(req->ntvfs, st));
305 /****************************************************************************
306 Reply to a dskattr (async reply)
307 ****************************************************************************/
308 static void reply_dskattr_send(struct ntvfs_request *ntvfs)
310 struct smbsrv_request *req;
311 union smb_fsinfo *fs;
313 SMBSRV_CHECK_ASYNC_STATUS(fs, union smb_fsinfo);
315 /* construct reply */
316 smbsrv_setup_reply(req, 5, 0);
318 SSVAL(req->out.vwv, VWV(0), fs->dskattr.out.units_total);
319 SSVAL(req->out.vwv, VWV(1), fs->dskattr.out.blocks_per_unit);
320 SSVAL(req->out.vwv, VWV(2), fs->dskattr.out.block_size);
321 SSVAL(req->out.vwv, VWV(3), fs->dskattr.out.units_free);
323 SMBSRV_VWV_RESERVED(4, 1);
325 smbsrv_send_reply(req);
329 /****************************************************************************
331 ****************************************************************************/
332 void smbsrv_reply_dskattr(struct smbsrv_request *req)
334 union smb_fsinfo *fs;
336 SMBSRV_TALLOC_IO_PTR(fs, union smb_fsinfo);
337 SMBSRV_SETUP_NTVFS_REQUEST(reply_dskattr_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
339 fs->dskattr.level = RAW_QFS_DSKATTR;
341 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_fsinfo(req->ntvfs, fs));
345 /****************************************************************************
346 Reply to an open (async reply)
347 ****************************************************************************/
348 static void reply_open_send(struct ntvfs_request *ntvfs)
350 struct smbsrv_request *req;
353 SMBSRV_CHECK_ASYNC_STATUS(oi, union smb_open);
355 /* construct reply */
356 smbsrv_setup_reply(req, 7, 0);
358 smbsrv_push_fnum(req->out.vwv, VWV(0), oi->openold.out.file.ntvfs);
359 SSVAL(req->out.vwv, VWV(1), oi->openold.out.attrib);
360 srv_push_dos_date3(req->smb_conn, req->out.vwv, VWV(2), oi->openold.out.write_time);
361 SIVAL(req->out.vwv, VWV(4), oi->openold.out.size);
362 SSVAL(req->out.vwv, VWV(6), oi->openold.out.rmode);
364 smbsrv_send_reply(req);
367 /****************************************************************************
369 ****************************************************************************/
370 void smbsrv_reply_open(struct smbsrv_request *req)
375 SMBSRV_CHECK_WCT(req, 2);
376 SMBSRV_TALLOC_IO_PTR(oi, union smb_open);
377 SMBSRV_SETUP_NTVFS_REQUEST(reply_open_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
379 oi->openold.level = RAW_OPEN_OPEN;
380 oi->openold.in.open_mode = SVAL(req->in.vwv, VWV(0));
381 oi->openold.in.search_attrs = SVAL(req->in.vwv, VWV(1));
383 req_pull_ascii4(req, &oi->openold.in.fname, req->in.data, STR_TERMINATE);
385 if (!oi->openold.in.fname) {
386 smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
390 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, oi));
394 /****************************************************************************
395 Reply to an open and X (async reply)
396 ****************************************************************************/
397 static void reply_open_and_X_send(struct ntvfs_request *ntvfs)
399 struct smbsrv_request *req;
402 SMBSRV_CHECK_ASYNC_STATUS(oi, union smb_open);
404 /* build the reply */
405 if (oi->openx.in.flags & OPENX_FLAGS_EXTENDED_RETURN) {
406 smbsrv_setup_reply(req, 19, 0);
408 smbsrv_setup_reply(req, 15, 0);
411 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
412 SSVAL(req->out.vwv, VWV(1), 0);
413 smbsrv_push_fnum(req->out.vwv, VWV(2), oi->openx.out.file.ntvfs);
414 SSVAL(req->out.vwv, VWV(3), oi->openx.out.attrib);
415 srv_push_dos_date3(req->smb_conn, req->out.vwv, VWV(4), oi->openx.out.write_time);
416 SIVAL(req->out.vwv, VWV(6), oi->openx.out.size);
417 SSVAL(req->out.vwv, VWV(8), oi->openx.out.access);
418 SSVAL(req->out.vwv, VWV(9), oi->openx.out.ftype);
419 SSVAL(req->out.vwv, VWV(10),oi->openx.out.devstate);
420 SSVAL(req->out.vwv, VWV(11),oi->openx.out.action);
421 SIVAL(req->out.vwv, VWV(12),oi->openx.out.unique_fid);
422 SSVAL(req->out.vwv, VWV(14),0); /* reserved */
423 if (oi->openx.in.flags & OPENX_FLAGS_EXTENDED_RETURN) {
424 SIVAL(req->out.vwv, VWV(15),oi->openx.out.access_mask);
425 SMBSRV_VWV_RESERVED(17, 2);
428 req->chained_fnum = SVAL(req->out.vwv, VWV(2));
430 smbsrv_chain_reply(req);
434 /****************************************************************************
435 Reply to an open and X.
436 ****************************************************************************/
437 void smbsrv_reply_open_and_X(struct smbsrv_request *req)
441 /* parse the request */
442 SMBSRV_CHECK_WCT(req, 15);
443 SMBSRV_TALLOC_IO_PTR(oi, union smb_open);
444 SMBSRV_SETUP_NTVFS_REQUEST(reply_open_and_X_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
446 oi->openx.level = RAW_OPEN_OPENX;
447 oi->openx.in.flags = SVAL(req->in.vwv, VWV(2));
448 oi->openx.in.open_mode = SVAL(req->in.vwv, VWV(3));
449 oi->openx.in.search_attrs = SVAL(req->in.vwv, VWV(4));
450 oi->openx.in.file_attrs = SVAL(req->in.vwv, VWV(5));
451 oi->openx.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(6));
452 oi->openx.in.open_func = SVAL(req->in.vwv, VWV(8));
453 oi->openx.in.size = IVAL(req->in.vwv, VWV(9));
454 oi->openx.in.timeout = IVAL(req->in.vwv, VWV(11));
456 req_pull_ascii4(req, &oi->openx.in.fname, req->in.data, STR_TERMINATE);
458 if (!oi->openx.in.fname) {
459 smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
463 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, oi));
467 /****************************************************************************
468 Reply to a mknew or a create.
469 ****************************************************************************/
470 static void reply_mknew_send(struct ntvfs_request *ntvfs)
472 struct smbsrv_request *req;
475 SMBSRV_CHECK_ASYNC_STATUS(oi, union smb_open);
477 /* build the reply */
478 smbsrv_setup_reply(req, 1, 0);
480 smbsrv_push_fnum(req->out.vwv, VWV(0), oi->mknew.out.file.ntvfs);
482 smbsrv_send_reply(req);
486 /****************************************************************************
487 Reply to a mknew or a create.
488 ****************************************************************************/
489 void smbsrv_reply_mknew(struct smbsrv_request *req)
493 /* parse the request */
494 SMBSRV_CHECK_WCT(req, 3);
495 SMBSRV_TALLOC_IO_PTR(oi, union smb_open);
496 SMBSRV_SETUP_NTVFS_REQUEST(reply_mknew_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
498 if (CVAL(req->in.hdr, HDR_COM) == SMBmknew) {
499 oi->mknew.level = RAW_OPEN_MKNEW;
501 oi->mknew.level = RAW_OPEN_CREATE;
503 oi->mknew.in.attrib = SVAL(req->in.vwv, VWV(0));
504 oi->mknew.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(1));
506 req_pull_ascii4(req, &oi->mknew.in.fname, req->in.data, STR_TERMINATE);
508 if (!oi->mknew.in.fname) {
509 smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
513 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, oi));
516 /****************************************************************************
517 Reply to a create temporary file (async reply)
518 ****************************************************************************/
519 static void reply_ctemp_send(struct ntvfs_request *ntvfs)
521 struct smbsrv_request *req;
524 SMBSRV_CHECK_ASYNC_STATUS(oi, union smb_open);
526 /* build the reply */
527 smbsrv_setup_reply(req, 1, 0);
529 smbsrv_push_fnum(req->out.vwv, VWV(0), oi->ctemp.out.file.ntvfs);
531 /* the returned filename is relative to the directory */
532 req_push_str(req, NULL, oi->ctemp.out.name, -1, STR_TERMINATE | STR_ASCII);
534 smbsrv_send_reply(req);
537 /****************************************************************************
538 Reply to a create temporary file.
539 ****************************************************************************/
540 void smbsrv_reply_ctemp(struct smbsrv_request *req)
544 /* parse the request */
545 SMBSRV_CHECK_WCT(req, 3);
546 SMBSRV_TALLOC_IO_PTR(oi, union smb_open);
547 SMBSRV_SETUP_NTVFS_REQUEST(reply_ctemp_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
549 oi->ctemp.level = RAW_OPEN_CTEMP;
550 oi->ctemp.in.attrib = SVAL(req->in.vwv, VWV(0));
551 oi->ctemp.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(1));
553 /* the filename is actually a directory name, the server provides a filename
555 req_pull_ascii4(req, &oi->ctemp.in.directory, req->in.data, STR_TERMINATE);
557 if (!oi->ctemp.in.directory) {
558 smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
562 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, oi));
566 /****************************************************************************
568 ****************************************************************************/
569 void smbsrv_reply_unlink(struct smbsrv_request *req)
571 union smb_unlink *unl;
573 /* parse the request */
574 SMBSRV_CHECK_WCT(req, 1);
575 SMBSRV_TALLOC_IO_PTR(unl, union smb_unlink);
576 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
578 unl->unlink.in.attrib = SVAL(req->in.vwv, VWV(0));
580 req_pull_ascii4(req, &unl->unlink.in.pattern, req->in.data, STR_TERMINATE);
582 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_unlink(req->ntvfs, unl));
586 /****************************************************************************
587 Reply to a readbraw (core+ protocol).
588 this is a strange packet because it doesn't use a standard SMB header in the reply,
589 only the 4 byte NBT header
590 This command must be replied to synchronously
591 ****************************************************************************/
592 void smbsrv_reply_readbraw(struct smbsrv_request *req)
597 io.readbraw.level = RAW_READ_READBRAW;
599 /* there are two variants, one with 10 and one with 8 command words */
600 if (req->in.wct < 8) {
604 io.readbraw.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
605 io.readbraw.in.offset = IVAL(req->in.vwv, VWV(1));
606 io.readbraw.in.maxcnt = SVAL(req->in.vwv, VWV(3));
607 io.readbraw.in.mincnt = SVAL(req->in.vwv, VWV(4));
608 io.readbraw.in.timeout = IVAL(req->in.vwv, VWV(5));
610 if (!io.readbraw.in.file.ntvfs) {
614 /* the 64 bit variant */
615 if (req->in.wct == 10) {
616 uint32_t offset_high = IVAL(req->in.vwv, VWV(8));
617 io.readbraw.in.offset |= (((off_t)offset_high) << 32);
620 /* before calling the backend we setup the raw buffer. This
621 * saves a copy later */
622 req->out.size = io.readbraw.in.maxcnt + NBT_HDR_SIZE;
623 req->out.buffer = talloc_size(req, req->out.size);
624 if (req->out.buffer == NULL) {
627 SIVAL(req->out.buffer, 0, 0); /* init NBT header */
629 /* tell the backend where to put the data */
630 io.readbraw.out.data = req->out.buffer + NBT_HDR_SIZE;
632 /* prepare the ntvfs request */
633 req->ntvfs = ntvfs_request_create(req->tcon->ntvfs, req,
634 req->session->session_info,
635 SVAL(req->in.hdr,HDR_PID),
642 /* call the backend */
643 status = ntvfs_read(req->ntvfs, &io);
644 if (!NT_STATUS_IS_OK(status)) {
648 req->out.size = io.readbraw.out.nread + NBT_HDR_SIZE;
650 smbsrv_send_reply_nosign(req);
654 /* any failure in readbraw is equivalent to reading zero bytes */
656 req->out.buffer = talloc_size(req, req->out.size);
657 SIVAL(req->out.buffer, 0, 0); /* init NBT header */
659 smbsrv_send_reply_nosign(req);
663 /****************************************************************************
664 Reply to a lockread (async reply)
665 ****************************************************************************/
666 static void reply_lockread_send(struct ntvfs_request *ntvfs)
668 struct smbsrv_request *req;
671 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_read);
674 io->lockread.out.nread = MIN(io->lockread.out.nread,
675 req_max_data(req) - 3);
676 req_grow_data(req, 3 + io->lockread.out.nread);
678 /* construct reply */
679 SSVAL(req->out.vwv, VWV(0), io->lockread.out.nread);
680 SMBSRV_VWV_RESERVED(1, 4);
682 SCVAL(req->out.data, 0, SMB_DATA_BLOCK);
683 SSVAL(req->out.data, 1, io->lockread.out.nread);
685 smbsrv_send_reply(req);
689 /****************************************************************************
690 Reply to a lockread (core+ protocol).
691 note that the lock is a write lock, not a read lock!
692 ****************************************************************************/
693 void smbsrv_reply_lockread(struct smbsrv_request *req)
698 SMBSRV_CHECK_WCT(req, 5);
699 SMBSRV_TALLOC_IO_PTR(io, union smb_read);
700 SMBSRV_SETUP_NTVFS_REQUEST(reply_lockread_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
702 io->lockread.level = RAW_READ_LOCKREAD;
703 io->lockread.in.file.ntvfs= smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
704 io->lockread.in.count = SVAL(req->in.vwv, VWV(1));
705 io->lockread.in.offset = IVAL(req->in.vwv, VWV(2));
706 io->lockread.in.remaining = SVAL(req->in.vwv, VWV(4));
708 /* setup the reply packet assuming the maximum possible read */
709 smbsrv_setup_reply(req, 5, 3 + io->lockread.in.count);
711 /* tell the backend where to put the data */
712 io->lockread.out.data = req->out.data + 3;
714 SMBSRV_CHECK_FILE_HANDLE(io->lockread.in.file.ntvfs);
715 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_read(req->ntvfs, io));
720 /****************************************************************************
721 Reply to a read (async reply)
722 ****************************************************************************/
723 static void reply_read_send(struct ntvfs_request *ntvfs)
725 struct smbsrv_request *req;
728 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_read);
731 io->read.out.nread = MIN(io->read.out.nread,
732 req_max_data(req) - 3);
733 req_grow_data(req, 3 + io->read.out.nread);
735 /* construct reply */
736 SSVAL(req->out.vwv, VWV(0), io->read.out.nread);
737 SMBSRV_VWV_RESERVED(1, 4);
739 SCVAL(req->out.data, 0, SMB_DATA_BLOCK);
740 SSVAL(req->out.data, 1, io->read.out.nread);
742 smbsrv_send_reply(req);
745 /****************************************************************************
747 ****************************************************************************/
748 void smbsrv_reply_read(struct smbsrv_request *req)
753 SMBSRV_CHECK_WCT(req, 5);
754 SMBSRV_TALLOC_IO_PTR(io, union smb_read);
755 SMBSRV_SETUP_NTVFS_REQUEST(reply_read_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
757 io->read.level = RAW_READ_READ;
758 io->read.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
759 io->read.in.count = SVAL(req->in.vwv, VWV(1));
760 io->read.in.offset = IVAL(req->in.vwv, VWV(2));
761 io->read.in.remaining = SVAL(req->in.vwv, VWV(4));
763 /* setup the reply packet assuming the maximum possible read */
764 smbsrv_setup_reply(req, 5, 3 + io->read.in.count);
766 /* tell the backend where to put the data */
767 io->read.out.data = req->out.data + 3;
769 SMBSRV_CHECK_FILE_HANDLE(io->read.in.file.ntvfs);
770 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_read(req->ntvfs, io));
773 /****************************************************************************
774 Reply to a read and X (async reply)
775 ****************************************************************************/
776 static void reply_read_and_X_send(struct ntvfs_request *ntvfs)
778 struct smbsrv_request *req;
781 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_read);
783 /* readx reply packets can be over-sized */
784 req->control_flags |= SMBSRV_REQ_CONTROL_LARGE;
785 if (io->readx.in.maxcnt != 0xFFFF &&
786 io->readx.in.mincnt != 0xFFFF) {
787 req_grow_data(req, 1 + io->readx.out.nread);
788 SCVAL(req->out.data, 0, 0); /* padding */
790 req_grow_data(req, io->readx.out.nread);
793 /* construct reply */
794 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
795 SSVAL(req->out.vwv, VWV(1), 0);
796 SSVAL(req->out.vwv, VWV(2), io->readx.out.remaining);
797 SSVAL(req->out.vwv, VWV(3), io->readx.out.compaction_mode);
798 SMBSRV_VWV_RESERVED(4, 1);
799 SSVAL(req->out.vwv, VWV(5), io->readx.out.nread);
800 SSVAL(req->out.vwv, VWV(6), PTR_DIFF(io->readx.out.data, req->out.hdr));
801 SMBSRV_VWV_RESERVED(7, 5);
803 smbsrv_chain_reply(req);
806 /****************************************************************************
807 Reply to a read and X.
808 ****************************************************************************/
809 void smbsrv_reply_read_and_X(struct smbsrv_request *req)
814 if (req->in.wct != 12) {
815 SMBSRV_CHECK_WCT(req, 10);
818 SMBSRV_TALLOC_IO_PTR(io, union smb_read);
819 SMBSRV_SETUP_NTVFS_REQUEST(reply_read_and_X_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
821 io->readx.level = RAW_READ_READX;
822 io->readx.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(2));
823 io->readx.in.offset = IVAL(req->in.vwv, VWV(3));
824 io->readx.in.maxcnt = SVAL(req->in.vwv, VWV(5));
825 io->readx.in.mincnt = SVAL(req->in.vwv, VWV(6));
826 io->readx.in.remaining = SVAL(req->in.vwv, VWV(9));
827 if (req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) {
828 io->readx.in.read_for_execute = True;
830 io->readx.in.read_for_execute = False;
833 if (req->smb_conn->negotiate.client_caps & CAP_LARGE_READX) {
834 uint32_t high_part = IVAL(req->in.vwv, VWV(7));
835 if (high_part == 1) {
836 io->readx.in.maxcnt |= high_part << 16;
840 /* the 64 bit variant */
841 if (req->in.wct == 12) {
842 uint32_t offset_high = IVAL(req->in.vwv, VWV(10));
843 io->readx.in.offset |= (((uint64_t)offset_high) << 32);
846 /* setup the reply packet assuming the maximum possible read */
847 smbsrv_setup_reply(req, 12, 1 + io->readx.in.maxcnt);
849 /* tell the backend where to put the data. Notice the pad byte. */
850 if (io->readx.in.maxcnt != 0xFFFF &&
851 io->readx.in.mincnt != 0xFFFF) {
852 io->readx.out.data = req->out.data + 1;
854 io->readx.out.data = req->out.data;
857 SMBSRV_CHECK_FILE_HANDLE(io->readx.in.file.ntvfs);
858 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_read(req->ntvfs, io));
862 /****************************************************************************
863 Reply to a writebraw (core+ or LANMAN1.0 protocol).
864 ****************************************************************************/
865 void smbsrv_reply_writebraw(struct smbsrv_request *req)
867 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRuseSTD));
871 /****************************************************************************
872 Reply to a writeunlock (async reply)
873 ****************************************************************************/
874 static void reply_writeunlock_send(struct ntvfs_request *ntvfs)
876 struct smbsrv_request *req;
879 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_write);
881 /* construct reply */
882 smbsrv_setup_reply(req, 1, 0);
884 SSVAL(req->out.vwv, VWV(0), io->writeunlock.out.nwritten);
886 smbsrv_send_reply(req);
889 /****************************************************************************
890 Reply to a writeunlock (core+).
891 ****************************************************************************/
892 void smbsrv_reply_writeunlock(struct smbsrv_request *req)
896 SMBSRV_CHECK_WCT(req, 5);
897 SMBSRV_TALLOC_IO_PTR(io, union smb_write);
898 SMBSRV_SETUP_NTVFS_REQUEST(reply_writeunlock_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
900 io->writeunlock.level = RAW_WRITE_WRITEUNLOCK;
901 io->writeunlock.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
902 io->writeunlock.in.count = SVAL(req->in.vwv, VWV(1));
903 io->writeunlock.in.offset = IVAL(req->in.vwv, VWV(2));
904 io->writeunlock.in.remaining = SVAL(req->in.vwv, VWV(4));
905 io->writeunlock.in.data = req->in.data + 3;
907 /* make sure they gave us the data they promised */
908 if (io->writeunlock.in.count+3 > req->in.data_size) {
909 smbsrv_send_error(req, NT_STATUS_FOOBAR);
913 /* make sure the data block is big enough */
914 if (SVAL(req->in.data, 1) < io->writeunlock.in.count) {
915 smbsrv_send_error(req, NT_STATUS_FOOBAR);
919 SMBSRV_CHECK_FILE_HANDLE(io->writeunlock.in.file.ntvfs);
920 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
925 /****************************************************************************
926 Reply to a write (async reply)
927 ****************************************************************************/
928 static void reply_write_send(struct ntvfs_request *ntvfs)
930 struct smbsrv_request *req;
933 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_write);
935 /* construct reply */
936 smbsrv_setup_reply(req, 1, 0);
938 SSVAL(req->out.vwv, VWV(0), io->write.out.nwritten);
940 smbsrv_send_reply(req);
943 /****************************************************************************
945 ****************************************************************************/
946 void smbsrv_reply_write(struct smbsrv_request *req)
950 SMBSRV_CHECK_WCT(req, 5);
951 SMBSRV_TALLOC_IO_PTR(io, union smb_write);
952 SMBSRV_SETUP_NTVFS_REQUEST(reply_write_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
954 io->write.level = RAW_WRITE_WRITE;
955 io->write.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
956 io->write.in.count = SVAL(req->in.vwv, VWV(1));
957 io->write.in.offset = IVAL(req->in.vwv, VWV(2));
958 io->write.in.remaining = SVAL(req->in.vwv, VWV(4));
959 io->write.in.data = req->in.data + 3;
961 /* make sure they gave us the data they promised */
962 if (req_data_oob(req, io->write.in.data, io->write.in.count)) {
963 smbsrv_send_error(req, NT_STATUS_FOOBAR);
967 /* make sure the data block is big enough */
968 if (SVAL(req->in.data, 1) < io->write.in.count) {
969 smbsrv_send_error(req, NT_STATUS_FOOBAR);
973 SMBSRV_CHECK_FILE_HANDLE(io->write.in.file.ntvfs);
974 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
978 /****************************************************************************
979 Reply to a write and X (async reply)
980 ****************************************************************************/
981 static void reply_write_and_X_send(struct ntvfs_request *ntvfs)
983 struct smbsrv_request *req;
986 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_write);
988 /* construct reply */
989 smbsrv_setup_reply(req, 6, 0);
991 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
992 SSVAL(req->out.vwv, VWV(1), 0);
993 SSVAL(req->out.vwv, VWV(2), io->writex.out.nwritten & 0xFFFF);
994 SSVAL(req->out.vwv, VWV(3), io->writex.out.remaining);
995 SSVAL(req->out.vwv, VWV(4), io->writex.out.nwritten >> 16);
996 SMBSRV_VWV_RESERVED(5, 1);
998 smbsrv_chain_reply(req);
1001 /****************************************************************************
1002 Reply to a write and X.
1003 ****************************************************************************/
1004 void smbsrv_reply_write_and_X(struct smbsrv_request *req)
1006 union smb_write *io;
1008 if (req->in.wct != 14) {
1009 SMBSRV_CHECK_WCT(req, 12);
1012 SMBSRV_TALLOC_IO_PTR(io, union smb_write);
1013 SMBSRV_SETUP_NTVFS_REQUEST(reply_write_and_X_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1015 io->writex.level = RAW_WRITE_WRITEX;
1016 io->writex.in.file.ntvfs= smbsrv_pull_fnum(req, req->in.vwv, VWV(2));
1017 io->writex.in.offset = IVAL(req->in.vwv, VWV(3));
1018 io->writex.in.wmode = SVAL(req->in.vwv, VWV(7));
1019 io->writex.in.remaining = SVAL(req->in.vwv, VWV(8));
1020 io->writex.in.count = SVAL(req->in.vwv, VWV(10));
1021 io->writex.in.data = req->in.hdr + SVAL(req->in.vwv, VWV(11));
1023 if (req->in.wct == 14) {
1024 uint32_t offset_high = IVAL(req->in.vwv, VWV(12));
1025 uint16_t count_high = SVAL(req->in.vwv, VWV(9));
1026 io->writex.in.offset |= (((uint64_t)offset_high) << 32);
1027 io->writex.in.count |= ((uint32_t)count_high) << 16;
1030 /* make sure the data is in bounds */
1031 if (req_data_oob(req, io->writex.in.data, io->writex.in.count)) {
1032 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1036 SMBSRV_CHECK_FILE_HANDLE(io->writex.in.file.ntvfs);
1037 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
1041 /****************************************************************************
1042 Reply to a lseek (async reply)
1043 ****************************************************************************/
1044 static void reply_lseek_send(struct ntvfs_request *ntvfs)
1046 struct smbsrv_request *req;
1049 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_seek);
1051 /* construct reply */
1052 smbsrv_setup_reply(req, 2, 0);
1054 SIVALS(req->out.vwv, VWV(0), io->lseek.out.offset);
1056 smbsrv_send_reply(req);
1059 /****************************************************************************
1061 ****************************************************************************/
1062 void smbsrv_reply_lseek(struct smbsrv_request *req)
1066 SMBSRV_CHECK_WCT(req, 4);
1067 SMBSRV_TALLOC_IO_PTR(io, union smb_seek);
1068 SMBSRV_SETUP_NTVFS_REQUEST(reply_lseek_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1070 io->lseek.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1071 io->lseek.in.mode = SVAL(req->in.vwv, VWV(1));
1072 io->lseek.in.offset = IVALS(req->in.vwv, VWV(2));
1074 SMBSRV_CHECK_FILE_HANDLE(io->lseek.in.file.ntvfs);
1075 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_seek(req->ntvfs, io));
1078 /****************************************************************************
1080 ****************************************************************************/
1081 void smbsrv_reply_flush(struct smbsrv_request *req)
1083 union smb_flush *io;
1087 SMBSRV_CHECK_WCT(req, 1);
1088 SMBSRV_TALLOC_IO_PTR(io, union smb_flush);
1089 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1091 fnum = SVAL(req->in.vwv, VWV(0));
1092 if (fnum == 0xFFFF) {
1093 io->flush_all.level = RAW_FLUSH_ALL;
1095 io->flush.level = RAW_FLUSH_FLUSH;
1096 io->flush.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1097 SMBSRV_CHECK_FILE_HANDLE(io->flush.in.file.ntvfs);
1100 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_flush(req->ntvfs, io));
1103 /****************************************************************************
1106 Note that this has to deal with closing a directory opened by NT SMB's.
1107 ****************************************************************************/
1108 void smbsrv_reply_close(struct smbsrv_request *req)
1110 union smb_close *io;
1113 SMBSRV_CHECK_WCT(req, 3);
1114 SMBSRV_TALLOC_IO_PTR(io, union smb_close);
1115 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1117 io->close.level = RAW_CLOSE_CLOSE;
1118 io->close.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1119 io->close.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(1));
1121 SMBSRV_CHECK_FILE_HANDLE(io->close.in.file.ntvfs);
1122 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_close(req->ntvfs, io));
1126 /****************************************************************************
1127 Reply to a writeclose (async reply)
1128 ****************************************************************************/
1129 static void reply_writeclose_send(struct ntvfs_request *ntvfs)
1131 struct smbsrv_request *req;
1132 union smb_write *io;
1134 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_write);
1136 /* construct reply */
1137 smbsrv_setup_reply(req, 1, 0);
1139 SSVAL(req->out.vwv, VWV(0), io->write.out.nwritten);
1141 smbsrv_send_reply(req);
1144 /****************************************************************************
1145 Reply to a writeclose (Core+ protocol).
1146 ****************************************************************************/
1147 void smbsrv_reply_writeclose(struct smbsrv_request *req)
1149 union smb_write *io;
1151 /* this one is pretty weird - the wct can be 6 or 12 */
1152 if (req->in.wct != 12) {
1153 SMBSRV_CHECK_WCT(req, 6);
1156 SMBSRV_TALLOC_IO_PTR(io, union smb_write);
1157 SMBSRV_SETUP_NTVFS_REQUEST(reply_writeclose_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1159 io->writeclose.level = RAW_WRITE_WRITECLOSE;
1160 io->writeclose.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1161 io->writeclose.in.count = SVAL(req->in.vwv, VWV(1));
1162 io->writeclose.in.offset = IVAL(req->in.vwv, VWV(2));
1163 io->writeclose.in.mtime = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(4));
1164 io->writeclose.in.data = req->in.data + 1;
1166 /* make sure they gave us the data they promised */
1167 if (req_data_oob(req, io->writeclose.in.data, io->writeclose.in.count)) {
1168 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1172 SMBSRV_CHECK_FILE_HANDLE(io->writeclose.in.file.ntvfs);
1173 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
1176 /****************************************************************************
1178 ****************************************************************************/
1179 void smbsrv_reply_lock(struct smbsrv_request *req)
1181 union smb_lock *lck;
1184 SMBSRV_CHECK_WCT(req, 5);
1185 SMBSRV_TALLOC_IO_PTR(lck, union smb_lock);
1186 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1188 lck->lock.level = RAW_LOCK_LOCK;
1189 lck->lock.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1190 lck->lock.in.count = IVAL(req->in.vwv, VWV(1));
1191 lck->lock.in.offset = IVAL(req->in.vwv, VWV(3));
1193 SMBSRV_CHECK_FILE_HANDLE(lck->lock.in.file.ntvfs);
1194 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_lock(req->ntvfs, lck));
1198 /****************************************************************************
1200 ****************************************************************************/
1201 void smbsrv_reply_unlock(struct smbsrv_request *req)
1203 union smb_lock *lck;
1206 SMBSRV_CHECK_WCT(req, 5);
1207 SMBSRV_TALLOC_IO_PTR(lck, union smb_lock);
1208 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1210 lck->unlock.level = RAW_LOCK_UNLOCK;
1211 lck->unlock.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1212 lck->unlock.in.count = IVAL(req->in.vwv, VWV(1));
1213 lck->unlock.in.offset = IVAL(req->in.vwv, VWV(3));
1215 SMBSRV_CHECK_FILE_HANDLE(lck->unlock.in.file.ntvfs);
1216 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_lock(req->ntvfs, lck));
1220 /****************************************************************************
1222 ****************************************************************************/
1223 void smbsrv_reply_tdis(struct smbsrv_request *req)
1225 struct smbsrv_handle *h, *nh;
1227 SMBSRV_CHECK_WCT(req, 0);
1230 * TODO: cancel all pending requests on this tcon
1234 * close all handles on this tcon
1236 for (h=req->tcon->handles.list; h; h=nh) {
1241 /* finally destroy the tcon */
1242 talloc_free(req->tcon);
1245 smbsrv_setup_reply(req, 0, 0);
1246 smbsrv_send_reply(req);
1250 /****************************************************************************
1251 Reply to a echo. This is one of the few calls that is handled directly (the
1252 backends don't see it at all)
1253 ****************************************************************************/
1254 void smbsrv_reply_echo(struct smbsrv_request *req)
1259 SMBSRV_CHECK_WCT(req, 1);
1261 count = SVAL(req->in.vwv, VWV(0));
1263 smbsrv_setup_reply(req, 1, req->in.data_size);
1265 memcpy(req->out.data, req->in.data, req->in.data_size);
1267 for (i=1; i <= count;i++) {
1268 struct smbsrv_request *this_req;
1271 this_req = smbsrv_setup_secondary_request(req);
1276 SSVAL(this_req->out.vwv, VWV(0), i);
1277 smbsrv_send_reply(this_req);
1283 /****************************************************************************
1284 Reply to a printopen (async reply)
1285 ****************************************************************************/
1286 static void reply_printopen_send(struct ntvfs_request *ntvfs)
1288 struct smbsrv_request *req;
1291 SMBSRV_CHECK_ASYNC_STATUS(oi, union smb_open);
1293 /* construct reply */
1294 smbsrv_setup_reply(req, 1, 0);
1296 smbsrv_push_fnum(req->out.vwv, VWV(0), oi->openold.out.file.ntvfs);
1298 smbsrv_send_reply(req);
1301 /****************************************************************************
1302 Reply to a printopen.
1303 ****************************************************************************/
1304 void smbsrv_reply_printopen(struct smbsrv_request *req)
1309 SMBSRV_CHECK_WCT(req, 2);
1310 SMBSRV_TALLOC_IO_PTR(oi, union smb_open);
1311 SMBSRV_SETUP_NTVFS_REQUEST(reply_printopen_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1313 oi->splopen.level = RAW_OPEN_SPLOPEN;
1314 oi->splopen.in.setup_length = SVAL(req->in.vwv, VWV(0));
1315 oi->splopen.in.mode = SVAL(req->in.vwv, VWV(1));
1317 req_pull_ascii4(req, &oi->splopen.in.ident, req->in.data, STR_TERMINATE);
1319 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, oi));
1322 /****************************************************************************
1323 Reply to a printclose.
1324 ****************************************************************************/
1325 void smbsrv_reply_printclose(struct smbsrv_request *req)
1327 union smb_close *io;
1330 SMBSRV_CHECK_WCT(req, 3);
1331 SMBSRV_TALLOC_IO_PTR(io, union smb_close);
1332 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1334 io->splclose.level = RAW_CLOSE_SPLCLOSE;
1335 io->splclose.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1337 SMBSRV_CHECK_FILE_HANDLE(io->splclose.in.file.ntvfs);
1338 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_close(req->ntvfs, io));
1341 /****************************************************************************
1342 Reply to a printqueue.
1343 ****************************************************************************/
1344 static void reply_printqueue_send(struct ntvfs_request *ntvfs)
1346 struct smbsrv_request *req;
1349 const uint_t el_size = 28;
1351 SMBSRV_CHECK_ASYNC_STATUS(lpq,union smb_lpq);
1353 /* construct reply */
1354 smbsrv_setup_reply(req, 2, 0);
1356 /* truncate the returned list to fit in the negotiated buffer size */
1357 maxcount = (req_max_data(req) - 3) / el_size;
1358 if (maxcount < lpq->retq.out.count) {
1359 lpq->retq.out.count = maxcount;
1362 /* setup enough space in the reply */
1363 req_grow_data(req, 3 + el_size*lpq->retq.out.count);
1365 /* and fill it in */
1366 SSVAL(req->out.vwv, VWV(0), lpq->retq.out.count);
1367 SSVAL(req->out.vwv, VWV(1), lpq->retq.out.restart_idx);
1369 SCVAL(req->out.data, 0, SMB_DATA_BLOCK);
1370 SSVAL(req->out.data, 1, el_size*lpq->retq.out.count);
1372 req->out.ptr = req->out.data + 3;
1374 for (i=0;i<lpq->retq.out.count;i++) {
1375 srv_push_dos_date2(req->smb_conn, req->out.ptr, 0 , lpq->retq.out.queue[i].time);
1376 SCVAL(req->out.ptr, 4, lpq->retq.out.queue[i].status);
1377 SSVAL(req->out.ptr, 5, lpq->retq.out.queue[i].job);
1378 SIVAL(req->out.ptr, 7, lpq->retq.out.queue[i].size);
1379 SCVAL(req->out.ptr, 11, 0); /* reserved */
1380 req_push_str(req, req->out.ptr+12, lpq->retq.out.queue[i].user, 16, STR_ASCII);
1381 req->out.ptr += el_size;
1384 smbsrv_send_reply(req);
1387 /****************************************************************************
1388 Reply to a printqueue.
1389 ****************************************************************************/
1390 void smbsrv_reply_printqueue(struct smbsrv_request *req)
1395 SMBSRV_CHECK_WCT(req, 2);
1396 SMBSRV_TALLOC_IO_PTR(lpq, union smb_lpq);
1397 SMBSRV_SETUP_NTVFS_REQUEST(reply_printqueue_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1399 lpq->retq.level = RAW_LPQ_RETQ;
1400 lpq->retq.in.maxcount = SVAL(req->in.vwv, VWV(0));
1401 lpq->retq.in.startidx = SVAL(req->in.vwv, VWV(1));
1403 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_lpq(req->ntvfs, lpq));
1407 /****************************************************************************
1408 Reply to a printwrite.
1409 ****************************************************************************/
1410 void smbsrv_reply_printwrite(struct smbsrv_request *req)
1412 union smb_write *io;
1415 SMBSRV_CHECK_WCT(req, 1);
1416 SMBSRV_TALLOC_IO_PTR(io, union smb_write);
1417 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1419 if (req->in.data_size < 3) {
1420 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1424 io->splwrite.level = RAW_WRITE_SPLWRITE;
1425 io->splwrite.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1426 io->splwrite.in.count = SVAL(req->in.data, 1);
1427 io->splwrite.in.data = req->in.data + 3;
1429 /* make sure they gave us the data they promised */
1430 if (req_data_oob(req, io->splwrite.in.data, io->splwrite.in.count)) {
1431 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1435 SMBSRV_CHECK_FILE_HANDLE(io->splwrite.in.file.ntvfs);
1436 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
1440 /****************************************************************************
1442 ****************************************************************************/
1443 void smbsrv_reply_mkdir(struct smbsrv_request *req)
1445 union smb_mkdir *io;
1447 /* parse the request */
1448 SMBSRV_CHECK_WCT(req, 0);
1449 SMBSRV_TALLOC_IO_PTR(io, union smb_mkdir);
1450 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1452 io->generic.level = RAW_MKDIR_MKDIR;
1453 req_pull_ascii4(req, &io->mkdir.in.path, req->in.data, STR_TERMINATE);
1455 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_mkdir(req->ntvfs, io));
1459 /****************************************************************************
1461 ****************************************************************************/
1462 void smbsrv_reply_rmdir(struct smbsrv_request *req)
1464 struct smb_rmdir *io;
1466 /* parse the request */
1467 SMBSRV_CHECK_WCT(req, 0);
1468 SMBSRV_TALLOC_IO_PTR(io, struct smb_rmdir);
1469 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1471 req_pull_ascii4(req, &io->in.path, req->in.data, STR_TERMINATE);
1473 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_rmdir(req->ntvfs, io));
1477 /****************************************************************************
1479 ****************************************************************************/
1480 void smbsrv_reply_mv(struct smbsrv_request *req)
1482 union smb_rename *io;
1485 /* parse the request */
1486 SMBSRV_CHECK_WCT(req, 1);
1487 SMBSRV_TALLOC_IO_PTR(io, union smb_rename);
1488 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1490 io->generic.level = RAW_RENAME_RENAME;
1491 io->rename.in.attrib = SVAL(req->in.vwv, VWV(0));
1494 p += req_pull_ascii4(req, &io->rename.in.pattern1, p, STR_TERMINATE);
1495 p += req_pull_ascii4(req, &io->rename.in.pattern2, p, STR_TERMINATE);
1497 if (!io->rename.in.pattern1 || !io->rename.in.pattern2) {
1498 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1502 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_rename(req->ntvfs, io));
1506 /****************************************************************************
1507 Reply to an NT rename.
1508 ****************************************************************************/
1509 void smbsrv_reply_ntrename(struct smbsrv_request *req)
1511 union smb_rename *io;
1514 /* parse the request */
1515 SMBSRV_CHECK_WCT(req, 4);
1516 SMBSRV_TALLOC_IO_PTR(io, union smb_rename);
1517 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1519 io->generic.level = RAW_RENAME_NTRENAME;
1520 io->ntrename.in.attrib = SVAL(req->in.vwv, VWV(0));
1521 io->ntrename.in.flags = SVAL(req->in.vwv, VWV(1));
1522 io->ntrename.in.cluster_size = IVAL(req->in.vwv, VWV(2));
1525 p += req_pull_ascii4(req, &io->ntrename.in.old_name, p, STR_TERMINATE);
1526 p += req_pull_ascii4(req, &io->ntrename.in.new_name, p, STR_TERMINATE);
1528 if (!io->ntrename.in.old_name || !io->ntrename.in.new_name) {
1529 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1533 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_rename(req->ntvfs, io));
1536 /****************************************************************************
1537 Reply to a file copy (async reply)
1538 ****************************************************************************/
1539 static void reply_copy_send(struct ntvfs_request *ntvfs)
1541 struct smbsrv_request *req;
1542 struct smb_copy *cp;
1544 SMBSRV_CHECK_ASYNC_STATUS(cp, struct smb_copy);
1546 /* build the reply */
1547 smbsrv_setup_reply(req, 1, 0);
1549 SSVAL(req->out.vwv, VWV(0), cp->out.count);
1551 smbsrv_send_reply(req);
1554 /****************************************************************************
1555 Reply to a file copy.
1556 ****************************************************************************/
1557 void smbsrv_reply_copy(struct smbsrv_request *req)
1559 struct smb_copy *cp;
1563 SMBSRV_CHECK_WCT(req, 3);
1564 SMBSRV_TALLOC_IO_PTR(cp, struct smb_copy);
1565 SMBSRV_SETUP_NTVFS_REQUEST(reply_copy_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1567 cp->in.tid2 = SVAL(req->in.vwv, VWV(0));
1568 cp->in.ofun = SVAL(req->in.vwv, VWV(1));
1569 cp->in.flags = SVAL(req->in.vwv, VWV(2));
1572 p += req_pull_ascii4(req, &cp->in.path1, p, STR_TERMINATE);
1573 p += req_pull_ascii4(req, &cp->in.path2, p, STR_TERMINATE);
1575 if (!cp->in.path1 || !cp->in.path2) {
1576 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1580 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_copy(req->ntvfs, cp));
1583 /****************************************************************************
1584 Reply to a lockingX request (async send)
1585 ****************************************************************************/
1586 static void reply_lockingX_send(struct ntvfs_request *ntvfs)
1588 struct smbsrv_request *req;
1589 union smb_lock *lck;
1591 SMBSRV_CHECK_ASYNC_STATUS(lck, union smb_lock);
1593 /* if it was an oplock break ack then we only send a reply if
1594 there was an error */
1595 if (lck->lockx.in.ulock_cnt + lck->lockx.in.lock_cnt == 0) {
1600 /* construct reply */
1601 smbsrv_setup_reply(req, 2, 0);
1603 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1604 SSVAL(req->out.vwv, VWV(1), 0);
1606 smbsrv_chain_reply(req);
1610 /****************************************************************************
1611 Reply to a lockingX request.
1612 ****************************************************************************/
1613 void smbsrv_reply_lockingX(struct smbsrv_request *req)
1615 union smb_lock *lck;
1616 uint_t total_locks, i;
1621 SMBSRV_CHECK_WCT(req, 8);
1622 SMBSRV_TALLOC_IO_PTR(lck, union smb_lock);
1623 SMBSRV_SETUP_NTVFS_REQUEST(reply_lockingX_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1625 lck->lockx.level = RAW_LOCK_LOCKX;
1626 lck->lockx.in.file.ntvfs= smbsrv_pull_fnum(req, req->in.vwv, VWV(2));
1627 lck->lockx.in.mode = SVAL(req->in.vwv, VWV(3));
1628 lck->lockx.in.timeout = IVAL(req->in.vwv, VWV(4));
1629 lck->lockx.in.ulock_cnt = SVAL(req->in.vwv, VWV(6));
1630 lck->lockx.in.lock_cnt = SVAL(req->in.vwv, VWV(7));
1632 total_locks = lck->lockx.in.ulock_cnt + lck->lockx.in.lock_cnt;
1634 /* there are two variants, one with 64 bit offsets and counts */
1635 if (lck->lockx.in.mode & LOCKING_ANDX_LARGE_FILES) {
1641 /* make sure we got the promised data */
1642 if (req_data_oob(req, req->in.data, total_locks * lck_size)) {
1643 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1647 /* allocate the locks array */
1649 lck->lockx.in.locks = talloc_array(req, struct smb_lock_entry,
1651 if (lck->lockx.in.locks == NULL) {
1652 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
1659 /* construct the locks array */
1660 for (i=0;i<total_locks;i++) {
1661 uint32_t ofs_high=0, count_high=0;
1663 lck->lockx.in.locks[i].pid = SVAL(p, 0);
1665 if (lck->lockx.in.mode & LOCKING_ANDX_LARGE_FILES) {
1666 ofs_high = IVAL(p, 4);
1667 lck->lockx.in.locks[i].offset = IVAL(p, 8);
1668 count_high = IVAL(p, 12);
1669 lck->lockx.in.locks[i].count = IVAL(p, 16);
1671 lck->lockx.in.locks[i].offset = IVAL(p, 2);
1672 lck->lockx.in.locks[i].count = IVAL(p, 6);
1674 if (ofs_high != 0 || count_high != 0) {
1675 lck->lockx.in.locks[i].count |= ((uint64_t)count_high) << 32;
1676 lck->lockx.in.locks[i].offset |= ((uint64_t)ofs_high) << 32;
1681 SMBSRV_CHECK_FILE_HANDLE(lck->lockx.in.file.ntvfs);
1682 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_lock(req->ntvfs, lck));
1685 /****************************************************************************
1686 Reply to a SMBreadbmpx (read block multiplex) request.
1687 ****************************************************************************/
1688 void smbsrv_reply_readbmpx(struct smbsrv_request *req)
1690 /* tell the client to not use a multiplexed read - its too broken to use */
1691 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRuseSTD));
1695 /****************************************************************************
1696 Reply to a SMBsetattrE.
1697 ****************************************************************************/
1698 void smbsrv_reply_setattrE(struct smbsrv_request *req)
1700 union smb_setfileinfo *info;
1703 SMBSRV_CHECK_WCT(req, 7);
1704 SMBSRV_TALLOC_IO_PTR(info, union smb_setfileinfo);
1705 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1707 info->setattre.level = RAW_SFILEINFO_SETATTRE;
1708 info->setattre.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1709 info->setattre.in.create_time = srv_pull_dos_date2(req->smb_conn, req->in.vwv + VWV(1));
1710 info->setattre.in.access_time = srv_pull_dos_date2(req->smb_conn, req->in.vwv + VWV(3));
1711 info->setattre.in.write_time = srv_pull_dos_date2(req->smb_conn, req->in.vwv + VWV(5));
1713 SMBSRV_CHECK_FILE_HANDLE(info->setattre.in.file.ntvfs);
1714 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_setfileinfo(req->ntvfs, info));
1718 /****************************************************************************
1719 Reply to a SMBwritebmpx (write block multiplex primary) request.
1720 ****************************************************************************/
1721 void smbsrv_reply_writebmpx(struct smbsrv_request *req)
1723 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRuseSTD));
1727 /****************************************************************************
1728 Reply to a SMBwritebs (write block multiplex secondary) request.
1729 ****************************************************************************/
1730 void smbsrv_reply_writebs(struct smbsrv_request *req)
1732 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRuseSTD));
1737 /****************************************************************************
1738 Reply to a SMBgetattrE (async reply)
1739 ****************************************************************************/
1740 static void reply_getattrE_send(struct ntvfs_request *ntvfs)
1742 struct smbsrv_request *req;
1743 union smb_fileinfo *info;
1745 SMBSRV_CHECK_ASYNC_STATUS(info, union smb_fileinfo);
1748 smbsrv_setup_reply(req, 11, 0);
1750 srv_push_dos_date2(req->smb_conn, req->out.vwv, VWV(0), info->getattre.out.create_time);
1751 srv_push_dos_date2(req->smb_conn, req->out.vwv, VWV(2), info->getattre.out.access_time);
1752 srv_push_dos_date2(req->smb_conn, req->out.vwv, VWV(4), info->getattre.out.write_time);
1753 SIVAL(req->out.vwv, VWV(6), info->getattre.out.size);
1754 SIVAL(req->out.vwv, VWV(8), info->getattre.out.alloc_size);
1755 SSVAL(req->out.vwv, VWV(10), info->getattre.out.attrib);
1757 smbsrv_send_reply(req);
1760 /****************************************************************************
1761 Reply to a SMBgetattrE.
1762 ****************************************************************************/
1763 void smbsrv_reply_getattrE(struct smbsrv_request *req)
1765 union smb_fileinfo *info;
1768 SMBSRV_CHECK_WCT(req, 1);
1769 SMBSRV_TALLOC_IO_PTR(info, union smb_fileinfo);
1770 SMBSRV_SETUP_NTVFS_REQUEST(reply_getattrE_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1772 info->getattr.level = RAW_FILEINFO_GETATTRE;
1773 info->getattr.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1775 SMBSRV_CHECK_FILE_HANDLE(info->getattr.in.file.ntvfs);
1776 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_qfileinfo(req->ntvfs, info));
1779 void smbsrv_reply_sesssetup_send(struct smbsrv_request *req,
1780 union smb_sesssetup *io,
1783 switch (io->old.level) {
1784 case RAW_SESSSETUP_OLD:
1785 if (!NT_STATUS_IS_OK(status)) {
1786 smbsrv_send_error(req, status);
1790 /* construct reply */
1791 smbsrv_setup_reply(req, 3, 0);
1793 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1794 SSVAL(req->out.vwv, VWV(1), 0);
1795 SSVAL(req->out.vwv, VWV(2), io->old.out.action);
1797 SSVAL(req->out.hdr, HDR_UID, io->old.out.vuid);
1799 smbsrv_chain_reply(req);
1802 case RAW_SESSSETUP_NT1:
1803 if (!NT_STATUS_IS_OK(status)) {
1804 smbsrv_send_error(req, status);
1808 /* construct reply */
1809 smbsrv_setup_reply(req, 3, 0);
1811 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1812 SSVAL(req->out.vwv, VWV(1), 0);
1813 SSVAL(req->out.vwv, VWV(2), io->nt1.out.action);
1815 SSVAL(req->out.hdr, HDR_UID, io->nt1.out.vuid);
1817 req_push_str(req, NULL, io->nt1.out.os, -1, STR_TERMINATE);
1818 req_push_str(req, NULL, io->nt1.out.lanman, -1, STR_TERMINATE);
1819 req_push_str(req, NULL, io->nt1.out.domain, -1, STR_TERMINATE);
1821 smbsrv_chain_reply(req);
1824 case RAW_SESSSETUP_SPNEGO:
1825 if (!NT_STATUS_IS_OK(status) &&
1826 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1827 smbsrv_send_error(req, status);
1831 /* construct reply */
1832 smbsrv_setup_reply(req, 4, io->spnego.out.secblob.length);
1834 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1835 smbsrv_setup_error(req, status);
1838 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1839 SSVAL(req->out.vwv, VWV(1), 0);
1840 SSVAL(req->out.vwv, VWV(2), io->spnego.out.action);
1841 SSVAL(req->out.vwv, VWV(3), io->spnego.out.secblob.length);
1843 SSVAL(req->out.hdr, HDR_UID, io->spnego.out.vuid);
1845 memcpy(req->out.data, io->spnego.out.secblob.data, io->spnego.out.secblob.length);
1846 req_push_str(req, NULL, io->spnego.out.os, -1, STR_TERMINATE);
1847 req_push_str(req, NULL, io->spnego.out.lanman, -1, STR_TERMINATE);
1848 req_push_str(req, NULL, io->spnego.out.workgroup, -1, STR_TERMINATE);
1850 smbsrv_chain_reply(req);
1853 case RAW_SESSSETUP_SMB2:
1857 smbsrv_send_error(req, NT_STATUS_INTERNAL_ERROR);
1860 /****************************************************************************
1861 reply to an old style session setup command
1862 ****************************************************************************/
1863 static void reply_sesssetup_old(struct smbsrv_request *req)
1867 union smb_sesssetup *io;
1869 SMBSRV_TALLOC_IO_PTR(io, union smb_sesssetup);
1871 io->old.level = RAW_SESSSETUP_OLD;
1874 io->old.in.bufsize = SVAL(req->in.vwv, VWV(2));
1875 io->old.in.mpx_max = SVAL(req->in.vwv, VWV(3));
1876 io->old.in.vc_num = SVAL(req->in.vwv, VWV(4));
1877 io->old.in.sesskey = IVAL(req->in.vwv, VWV(5));
1878 passlen = SVAL(req->in.vwv, VWV(7));
1880 /* check the request isn't malformed */
1881 if (req_data_oob(req, req->in.data, passlen)) {
1882 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1887 if (!req_pull_blob(req, p, passlen, &io->old.in.password)) {
1888 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1893 p += req_pull_string(req, &io->old.in.user, p, -1, STR_TERMINATE);
1894 p += req_pull_string(req, &io->old.in.domain, p, -1, STR_TERMINATE);
1895 p += req_pull_string(req, &io->old.in.os, p, -1, STR_TERMINATE);
1896 p += req_pull_string(req, &io->old.in.lanman, p, -1, STR_TERMINATE);
1898 /* call the generic handler */
1899 smbsrv_sesssetup_backend(req, io);
1902 /****************************************************************************
1903 reply to an NT1 style session setup command
1904 ****************************************************************************/
1905 static void reply_sesssetup_nt1(struct smbsrv_request *req)
1908 uint16_t passlen1, passlen2;
1909 union smb_sesssetup *io;
1911 SMBSRV_TALLOC_IO_PTR(io, union smb_sesssetup);
1913 io->nt1.level = RAW_SESSSETUP_NT1;
1916 io->nt1.in.bufsize = SVAL(req->in.vwv, VWV(2));
1917 io->nt1.in.mpx_max = SVAL(req->in.vwv, VWV(3));
1918 io->nt1.in.vc_num = SVAL(req->in.vwv, VWV(4));
1919 io->nt1.in.sesskey = IVAL(req->in.vwv, VWV(5));
1920 passlen1 = SVAL(req->in.vwv, VWV(7));
1921 passlen2 = SVAL(req->in.vwv, VWV(8));
1922 io->nt1.in.capabilities = IVAL(req->in.vwv, VWV(11));
1924 /* check the request isn't malformed */
1925 if (req_data_oob(req, req->in.data, passlen1) ||
1926 req_data_oob(req, req->in.data + passlen1, passlen2)) {
1927 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1932 if (!req_pull_blob(req, p, passlen1, &io->nt1.in.password1)) {
1933 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1937 if (!req_pull_blob(req, p, passlen2, &io->nt1.in.password2)) {
1938 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1943 p += req_pull_string(req, &io->nt1.in.user, p, -1, STR_TERMINATE);
1944 p += req_pull_string(req, &io->nt1.in.domain, p, -1, STR_TERMINATE);
1945 p += req_pull_string(req, &io->nt1.in.os, p, -1, STR_TERMINATE);
1946 p += req_pull_string(req, &io->nt1.in.lanman, p, -1, STR_TERMINATE);
1948 /* call the generic handler */
1949 smbsrv_sesssetup_backend(req, io);
1953 /****************************************************************************
1954 reply to an SPNEGO style session setup command
1955 ****************************************************************************/
1956 static void reply_sesssetup_spnego(struct smbsrv_request *req)
1960 union smb_sesssetup *io;
1962 SMBSRV_TALLOC_IO_PTR(io, union smb_sesssetup);
1964 io->spnego.level = RAW_SESSSETUP_SPNEGO;
1967 io->spnego.in.bufsize = SVAL(req->in.vwv, VWV(2));
1968 io->spnego.in.mpx_max = SVAL(req->in.vwv, VWV(3));
1969 io->spnego.in.vc_num = SVAL(req->in.vwv, VWV(4));
1970 io->spnego.in.sesskey = IVAL(req->in.vwv, VWV(5));
1971 blob_len = SVAL(req->in.vwv, VWV(7));
1972 io->spnego.in.capabilities = IVAL(req->in.vwv, VWV(10));
1975 if (!req_pull_blob(req, p, blob_len, &io->spnego.in.secblob)) {
1976 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1981 p += req_pull_string(req, &io->spnego.in.os, p, -1, STR_TERMINATE);
1982 p += req_pull_string(req, &io->spnego.in.lanman, p, -1, STR_TERMINATE);
1983 p += req_pull_string(req, &io->spnego.in.workgroup, p, -1, STR_TERMINATE);
1985 /* call the generic handler */
1986 smbsrv_sesssetup_backend(req, io);
1990 /****************************************************************************
1991 reply to a session setup command
1992 ****************************************************************************/
1993 void smbsrv_reply_sesssetup(struct smbsrv_request *req)
1995 switch (req->in.wct) {
1997 /* a pre-NT1 call */
1998 reply_sesssetup_old(req);
2002 reply_sesssetup_nt1(req);
2006 reply_sesssetup_spnego(req);
2010 /* unsupported variant */
2011 smbsrv_send_error(req, NT_STATUS_FOOBAR);
2014 /****************************************************************************
2015 Reply to a exit. This closes all files open by a smbpid
2016 ****************************************************************************/
2017 void smbsrv_reply_exit(struct smbsrv_request *req)
2019 struct smbsrv_handle_session_item *i, *ni;
2020 struct smbsrv_handle *h;
2021 struct smbsrv_tcon *tcon;
2024 SMBSRV_CHECK_WCT(req, 0);
2026 smbpid = SVAL(req->in.hdr,HDR_PID);
2028 /* first destroy all handles, which have the same PID as the request */
2029 for (i=req->session->handles; i; i=ni) {
2032 if (h->smbpid != smbpid) continue;
2038 * then let the ntvfs backends proxy the call if they want to,
2039 * but we didn't check the return value of the backends,
2040 * as for the SMB client the call succeed
2042 for (tcon=req->smb_conn->smb_tcons.list;tcon;tcon=tcon->next) {
2044 SMBSRV_SETUP_NTVFS_REQUEST(NULL,0);
2045 ntvfs_exit(req->ntvfs);
2046 talloc_free(req->ntvfs);
2051 smbsrv_setup_reply(req, 0, 0);
2052 smbsrv_send_reply(req);
2055 /****************************************************************************
2056 Reply to a SMBulogoffX.
2057 ****************************************************************************/
2058 void smbsrv_reply_ulogoffX(struct smbsrv_request *req)
2060 struct smbsrv_handle_session_item *i, *ni;
2061 struct smbsrv_handle *h;
2062 struct smbsrv_tcon *tcon;
2064 SMBSRV_CHECK_WCT(req, 2);
2067 * TODO: cancel all pending requests
2071 /* destroy all handles */
2072 for (i=req->session->handles; i; i=ni) {
2079 * then let the ntvfs backends proxy the call if they want to,
2080 * but we didn't check the return value of the backends,
2081 * as for the SMB client the call succeed
2083 for (tcon=req->smb_conn->smb_tcons.list;tcon;tcon=tcon->next) {
2085 SMBSRV_SETUP_NTVFS_REQUEST(NULL,0);
2086 ntvfs_logoff(req->ntvfs);
2087 talloc_free(req->ntvfs);
2092 talloc_free(req->session);
2093 req->session = NULL; /* it is now invalid, don't use on
2094 any chained packets */
2096 smbsrv_setup_reply(req, 2, 0);
2098 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
2099 SSVAL(req->out.vwv, VWV(1), 0);
2101 smbsrv_chain_reply(req);
2104 /****************************************************************************
2105 Reply to an SMBfindclose request
2106 ****************************************************************************/
2107 void smbsrv_reply_findclose(struct smbsrv_request *req)
2109 union smb_search_close *io;
2112 SMBSRV_CHECK_WCT(req, 1);
2113 SMBSRV_TALLOC_IO_PTR(io, union smb_search_close);
2114 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
2116 io->findclose.level = RAW_FINDCLOSE_FINDCLOSE;
2117 io->findclose.in.handle = SVAL(req->in.vwv, VWV(0));
2119 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_search_close(req->ntvfs, io));
2122 /****************************************************************************
2123 Reply to an SMBfindnclose request
2124 ****************************************************************************/
2125 void smbsrv_reply_findnclose(struct smbsrv_request *req)
2127 smbsrv_send_error(req, NT_STATUS_FOOBAR);
2131 /****************************************************************************
2132 Reply to an SMBntcreateX request (async send)
2133 ****************************************************************************/
2134 static void reply_ntcreate_and_X_send(struct ntvfs_request *ntvfs)
2136 struct smbsrv_request *req;
2139 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_open);
2141 /* construct reply */
2142 smbsrv_setup_reply(req, 34, 0);
2144 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
2145 SSVAL(req->out.vwv, VWV(1), 0);
2146 SCVAL(req->out.vwv, VWV(2), io->ntcreatex.out.oplock_level);
2148 /* the rest of the parameters are not aligned! */
2149 smbsrv_push_fnum(req->out.vwv, 5, io->ntcreatex.out.file.ntvfs);
2150 SIVAL(req->out.vwv, 7, io->ntcreatex.out.create_action);
2151 push_nttime(req->out.vwv, 11, io->ntcreatex.out.create_time);
2152 push_nttime(req->out.vwv, 19, io->ntcreatex.out.access_time);
2153 push_nttime(req->out.vwv, 27, io->ntcreatex.out.write_time);
2154 push_nttime(req->out.vwv, 35, io->ntcreatex.out.change_time);
2155 SIVAL(req->out.vwv, 43, io->ntcreatex.out.attrib);
2156 SBVAL(req->out.vwv, 47, io->ntcreatex.out.alloc_size);
2157 SBVAL(req->out.vwv, 55, io->ntcreatex.out.size);
2158 SSVAL(req->out.vwv, 63, io->ntcreatex.out.file_type);
2159 SSVAL(req->out.vwv, 65, io->ntcreatex.out.ipc_state);
2160 SCVAL(req->out.vwv, 67, io->ntcreatex.out.is_directory);
2162 req->chained_fnum = SVAL(req->out.vwv, 5);
2164 smbsrv_chain_reply(req);
2167 /****************************************************************************
2168 Reply to an SMBntcreateX request
2169 ****************************************************************************/
2170 void smbsrv_reply_ntcreate_and_X(struct smbsrv_request *req)
2175 /* parse the request */
2176 SMBSRV_CHECK_WCT(req, 24);
2177 SMBSRV_TALLOC_IO_PTR(io, union smb_open);
2178 SMBSRV_SETUP_NTVFS_REQUEST(reply_ntcreate_and_X_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
2180 io->ntcreatex.level = RAW_OPEN_NTCREATEX;
2182 /* notice that the word parameters are not word aligned, so we don't use VWV() */
2183 fname_len = SVAL(req->in.vwv, 5);
2184 io->ntcreatex.in.flags = IVAL(req->in.vwv, 7);
2185 io->ntcreatex.in.root_fid = IVAL(req->in.vwv, 11);
2186 io->ntcreatex.in.access_mask = IVAL(req->in.vwv, 15);
2187 io->ntcreatex.in.alloc_size = BVAL(req->in.vwv, 19);
2188 io->ntcreatex.in.file_attr = IVAL(req->in.vwv, 27);
2189 io->ntcreatex.in.share_access = IVAL(req->in.vwv, 31);
2190 io->ntcreatex.in.open_disposition = IVAL(req->in.vwv, 35);
2191 io->ntcreatex.in.create_options = IVAL(req->in.vwv, 39);
2192 io->ntcreatex.in.impersonation = IVAL(req->in.vwv, 43);
2193 io->ntcreatex.in.security_flags = CVAL(req->in.vwv, 47);
2194 io->ntcreatex.in.ea_list = NULL;
2195 io->ntcreatex.in.sec_desc = NULL;
2197 /* we need a neater way to handle this alignment */
2198 if ((req->flags2 & FLAGS2_UNICODE_STRINGS) &&
2199 ucs2_align(req->in.buffer, req->in.data, STR_TERMINATE|STR_UNICODE)) {
2203 req_pull_string(req, &io->ntcreatex.in.fname, req->in.data, fname_len, STR_TERMINATE);
2204 if (!io->ntcreatex.in.fname) {
2205 smbsrv_send_error(req, NT_STATUS_FOOBAR);
2209 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, io));
2213 /****************************************************************************
2214 Reply to an SMBntcancel request
2215 ****************************************************************************/
2216 void smbsrv_reply_ntcancel(struct smbsrv_request *req)
2218 struct smbsrv_request *r;
2219 uint16_t tid = SVAL(req->in.hdr,HDR_TID);
2220 uint16_t uid = SVAL(req->in.hdr,HDR_UID);
2221 uint16_t mid = SVAL(req->in.hdr,HDR_MID);
2222 uint16_t pid = SVAL(req->in.hdr,HDR_PID);
2224 for (r = req->smb_conn->requests; r; r = r->next) {
2225 if (tid != SVAL(r->in.hdr,HDR_TID)) continue;
2226 if (uid != SVAL(r->in.hdr,HDR_UID)) continue;
2227 if (mid != SVAL(r->in.hdr,HDR_MID)) continue;
2228 if (pid != SVAL(r->in.hdr,HDR_PID)) continue;
2230 SMBSRV_CHECK(ntvfs_cancel(r->ntvfs));
2232 /* NOTE: this request does not generate a reply */
2237 /* TODO: workout the correct error code,
2238 * until we know how the smb signing works
2239 * for ntcancel replies, don't send an error
2241 /*smbsrv_send_error(req, NT_STATUS_FOOBAR);*/
2246 parse the called/calling names from session request
2248 static NTSTATUS parse_session_request(struct smbsrv_request *req)
2253 blob.data = req->in.buffer + 4;
2254 blob.length = ascii_len_n((const char *)blob.data, req->in.size - PTR_DIFF(blob.data, req->in.buffer));
2255 if (blob.length == 0) return NT_STATUS_BAD_NETWORK_NAME;
2257 req->smb_conn->negotiate.called_name = talloc(req->smb_conn, struct nbt_name);
2258 req->smb_conn->negotiate.calling_name = talloc(req->smb_conn, struct nbt_name);
2259 if (req->smb_conn->negotiate.called_name == NULL ||
2260 req->smb_conn->negotiate.calling_name == NULL) {
2261 return NT_STATUS_NO_MEMORY;
2264 status = nbt_name_from_blob(req->smb_conn, &blob,
2265 req->smb_conn->negotiate.called_name);
2266 NT_STATUS_NOT_OK_RETURN(status);
2268 blob.data += blob.length;
2269 blob.length = ascii_len_n((const char *)blob.data, req->in.size - PTR_DIFF(blob.data, req->in.buffer));
2270 if (blob.length == 0) return NT_STATUS_BAD_NETWORK_NAME;
2272 status = nbt_name_from_blob(req->smb_conn, &blob,
2273 req->smb_conn->negotiate.calling_name);
2274 NT_STATUS_NOT_OK_RETURN(status);
2276 req->smb_conn->negotiate.done_nbt_session = True;
2278 return NT_STATUS_OK;
2283 /****************************************************************************
2284 Reply to a special message - a SMB packet with non zero NBT message type
2285 ****************************************************************************/
2286 void smbsrv_reply_special(struct smbsrv_request *req)
2289 uint8_t *buf = talloc_zero_array(req, uint8_t, 4);
2291 msg_type = CVAL(req->in.buffer,0);
2296 case 0x81: /* session request */
2297 if (req->smb_conn->negotiate.done_nbt_session) {
2298 DEBUG(0,("Warning: ignoring secondary session request\n"));
2305 /* we don't check the status - samba always accepts session
2306 requests for any name */
2307 parse_session_request(req);
2309 req->out.buffer = buf;
2311 smbsrv_send_reply_nosign(req);
2314 case 0x89: /* session keepalive request
2315 (some old clients produce this?) */
2316 SCVAL(buf, 0, SMBkeepalive);
2318 req->out.buffer = buf;
2320 smbsrv_send_reply_nosign(req);
2324 /* session keepalive - swallow it */
2329 DEBUG(0,("Unexpected NBT session packet (%d)\n", msg_type));