r16950: remove the smb mid from the ntvfs layer and keep a list of pending
[Samba.git] / source / smb_server / smb / reply.c
blobc79ad15ea8c1eb5a73a2c0c66f4acd4d69e0fddd
1 /*
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
27 #include "includes.h"
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 /****************************************************************************
48 Reply to a tcon.
49 ****************************************************************************/
50 void smbsrv_reply_tcon(struct smbsrv_request *req)
52 union smb_tcon con;
53 NTSTATUS status;
54 uint8_t *p;
56 /* parse request */
57 SMBSRV_CHECK_WCT(req, 0);
59 con.tcon.level = RAW_TCON_TCON;
61 p = req->in.data;
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);
68 return;
71 /* call backend */
72 status = smbsrv_tcon_backend(req, &con);
74 if (!NT_STATUS_IS_OK(status)) {
75 smbsrv_send_error(req, status);
76 return;
79 /* construct reply */
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)
95 NTSTATUS status;
96 union smb_tcon con;
97 uint8_t *p;
98 uint16_t passlen;
100 con.tconx.level = RAW_TCON_TCONX;
102 /* parse request */
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));
108 p = req->in.data;
110 if (!req_pull_blob(req, p, passlen, &con.tconx.in.password)) {
111 smbsrv_send_error(req, NT_STATUS_ILL_FORMED_PASSWORD);
112 return;
114 p += passlen;
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);
121 return;
124 /* call backend */
125 status = smbsrv_tcon_backend(req, &con);
127 if (!NT_STATUS_IS_OK(status)) {
128 smbsrv_send_error(req, status);
129 return;
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);
140 } else {
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)
164 int type;
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;
180 union smb_ioctl *io;
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 /****************************************************************************
196 Reply to an ioctl.
197 ****************************************************************************/
198 void smbsrv_reply_ioctl(struct smbsrv_request *req)
200 union smb_ioctl *io;
202 /* parse request */
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 /****************************************************************************
218 Reply to a chkpth.
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 /****************************************************************************
256 Reply to a getatr.
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;
267 /* parse request */
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);
271 return;
274 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_qpathinfo(req->ntvfs, st));
278 /****************************************************************************
279 Reply to a setatr.
280 ****************************************************************************/
281 void smbsrv_reply_setatr(struct smbsrv_request *req)
283 union smb_setfileinfo *st;
285 /* parse request */
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);
298 return;
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 /****************************************************************************
330 Reply to a dskattr.
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;
351 union smb_open *oi;
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 /****************************************************************************
368 Reply to an open.
369 ****************************************************************************/
370 void smbsrv_reply_open(struct smbsrv_request *req)
372 union smb_open *oi;
374 /* parse request */
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);
387 return;
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;
400 union smb_open *oi;
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);
407 } else {
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)
439 union smb_open *oi;
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);
460 return;
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;
473 union smb_open *oi;
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)
491 union smb_open *oi;
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;
500 } else {
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);
510 return;
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;
522 union smb_open *oi;
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)
542 union smb_open *oi;
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
554 in that directory */
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);
559 return;
562 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, oi));
566 /****************************************************************************
567 Reply to a unlink
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)
594 NTSTATUS status;
595 union smb_read io;
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) {
601 goto failed;
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) {
611 goto failed;
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) {
625 goto failed;
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),
636 req->request_time,
637 req, NULL, 0);
638 if (!req->ntvfs) {
639 goto failed;
642 /* call the backend */
643 status = ntvfs_read(req->ntvfs, &io);
644 if (!NT_STATUS_IS_OK(status)) {
645 goto failed;
648 req->out.size = io.readbraw.out.nread + NBT_HDR_SIZE;
650 smbsrv_send_reply_nosign(req);
651 return;
653 failed:
654 /* any failure in readbraw is equivalent to reading zero bytes */
655 req->out.size = 4;
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;
669 union smb_read *io;
671 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_read);
673 /* trim packet */
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)
695 union smb_read *io;
697 /* parse request */
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;
726 union smb_read *io;
728 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_read);
730 /* trim packet */
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 /****************************************************************************
746 Reply to a read.
747 ****************************************************************************/
748 void smbsrv_reply_read(struct smbsrv_request *req)
750 union smb_read *io;
752 /* parse request */
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;
779 union smb_read *io;
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 */
789 } else {
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)
811 union smb_read *io;
813 /* parse request */
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;
829 } else {
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;
853 } else {
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;
877 union smb_write *io;
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)
894 union smb_write *io;
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);
910 return;
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);
916 return;
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;
931 union smb_write *io;
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 /****************************************************************************
944 Reply to a write
945 ****************************************************************************/
946 void smbsrv_reply_write(struct smbsrv_request *req)
948 union smb_write *io;
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);
964 return;
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);
970 return;
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;
984 union smb_write *io;
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);
1033 return;
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;
1047 union smb_seek *io;
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 /****************************************************************************
1060 Reply to a lseek.
1061 ****************************************************************************/
1062 void smbsrv_reply_lseek(struct smbsrv_request *req)
1064 union smb_seek *io;
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 /****************************************************************************
1079 Reply to a flush.
1080 ****************************************************************************/
1081 void smbsrv_reply_flush(struct smbsrv_request *req)
1083 union smb_flush *io;
1084 uint16_t fnum;
1086 /* parse request */
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;
1094 } else {
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 /****************************************************************************
1104 Reply to a close
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;
1112 /* parse request */
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);
1169 return;
1172 SMBSRV_CHECK_FILE_HANDLE(io->writeclose.in.file.ntvfs);
1173 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
1176 /****************************************************************************
1177 Reply to a lock.
1178 ****************************************************************************/
1179 void smbsrv_reply_lock(struct smbsrv_request *req)
1181 union smb_lock *lck;
1183 /* parse request */
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 /****************************************************************************
1199 Reply to a unlock.
1200 ****************************************************************************/
1201 void smbsrv_reply_unlock(struct smbsrv_request *req)
1203 union smb_lock *lck;
1205 /* parse request */
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 /****************************************************************************
1221 Reply to a tdis.
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) {
1237 nh = h->next;
1238 talloc_free(h);
1241 /* finally destroy the tcon */
1242 talloc_free(req->tcon);
1243 req->tcon = NULL;
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)
1256 uint16_t count;
1257 int i;
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;
1270 if (i != count) {
1271 this_req = smbsrv_setup_secondary_request(req);
1272 } else {
1273 this_req = 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;
1289 union smb_open *oi;
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)
1306 union smb_open *oi;
1308 /* parse request */
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;
1329 /* parse request */
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;
1347 union smb_lpq *lpq;
1348 int i, maxcount;
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)
1392 union smb_lpq *lpq;
1394 /* parse request */
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;
1414 /* parse request */
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);
1421 return;
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);
1432 return;
1435 SMBSRV_CHECK_FILE_HANDLE(io->splwrite.in.file.ntvfs);
1436 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
1440 /****************************************************************************
1441 Reply to a mkdir.
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 /****************************************************************************
1460 Reply to a rmdir.
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 /****************************************************************************
1478 Reply to a mv.
1479 ****************************************************************************/
1480 void smbsrv_reply_mv(struct smbsrv_request *req)
1482 union smb_rename *io;
1483 uint8_t *p;
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));
1493 p = req->in.data;
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);
1499 return;
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;
1512 uint8_t *p;
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));
1524 p = req->in.data;
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);
1530 return;
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;
1560 uint8_t *p;
1562 /* parse request */
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));
1571 p = req->in.data;
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);
1577 return;
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) {
1596 talloc_free(req);
1597 return;
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;
1617 uint_t lck_size;
1618 uint8_t *p;
1620 /* parse request */
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) {
1636 lck_size = 20;
1637 } else {
1638 lck_size = 10;
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);
1644 return;
1647 /* allocate the locks array */
1648 if (total_locks) {
1649 lck->lockx.in.locks = talloc_array(req, struct smb_lock_entry,
1650 total_locks);
1651 if (lck->lockx.in.locks == NULL) {
1652 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
1653 return;
1657 p = req->in.data;
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);
1670 } else {
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;
1678 p += lck_size;
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;
1702 /* parse request */
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);
1747 /* setup reply */
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;
1767 /* parse request */
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));
1780 /****************************************************************************
1781 reply to an old style session setup command
1782 ****************************************************************************/
1783 static void reply_sesssetup_old(struct smbsrv_request *req)
1785 NTSTATUS status;
1786 union smb_sesssetup sess;
1787 uint8_t *p;
1788 uint16_t passlen;
1790 sess.old.level = RAW_SESSSETUP_OLD;
1792 /* parse request */
1793 sess.old.in.bufsize = SVAL(req->in.vwv, VWV(2));
1794 sess.old.in.mpx_max = SVAL(req->in.vwv, VWV(3));
1795 sess.old.in.vc_num = SVAL(req->in.vwv, VWV(4));
1796 sess.old.in.sesskey = IVAL(req->in.vwv, VWV(5));
1797 passlen = SVAL(req->in.vwv, VWV(7));
1799 /* check the request isn't malformed */
1800 if (req_data_oob(req, req->in.data, passlen)) {
1801 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1802 return;
1805 p = req->in.data;
1806 if (!req_pull_blob(req, p, passlen, &sess.old.in.password)) {
1807 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1808 return;
1810 p += passlen;
1812 p += req_pull_string(req, &sess.old.in.user, p, -1, STR_TERMINATE);
1813 p += req_pull_string(req, &sess.old.in.domain, p, -1, STR_TERMINATE);
1814 p += req_pull_string(req, &sess.old.in.os, p, -1, STR_TERMINATE);
1815 p += req_pull_string(req, &sess.old.in.lanman, p, -1, STR_TERMINATE);
1817 /* call the generic handler */
1818 status = smbsrv_sesssetup_backend(req, &sess);
1820 if (!NT_STATUS_IS_OK(status)) {
1821 smbsrv_send_error(req, status);
1822 return;
1825 /* construct reply */
1826 smbsrv_setup_reply(req, 3, 0);
1828 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1829 SSVAL(req->out.vwv, VWV(1), 0);
1830 SSVAL(req->out.vwv, VWV(2), sess.old.out.action);
1832 SSVAL(req->out.hdr, HDR_UID, sess.old.out.vuid);
1834 smbsrv_chain_reply(req);
1838 /****************************************************************************
1839 reply to an NT1 style session setup command
1840 ****************************************************************************/
1841 static void reply_sesssetup_nt1(struct smbsrv_request *req)
1843 NTSTATUS status;
1844 union smb_sesssetup sess;
1845 uint8_t *p;
1846 uint16_t passlen1, passlen2;
1848 sess.nt1.level = RAW_SESSSETUP_NT1;
1850 /* parse request */
1851 sess.nt1.in.bufsize = SVAL(req->in.vwv, VWV(2));
1852 sess.nt1.in.mpx_max = SVAL(req->in.vwv, VWV(3));
1853 sess.nt1.in.vc_num = SVAL(req->in.vwv, VWV(4));
1854 sess.nt1.in.sesskey = IVAL(req->in.vwv, VWV(5));
1855 passlen1 = SVAL(req->in.vwv, VWV(7));
1856 passlen2 = SVAL(req->in.vwv, VWV(8));
1857 sess.nt1.in.capabilities = IVAL(req->in.vwv, VWV(11));
1859 /* check the request isn't malformed */
1860 if (req_data_oob(req, req->in.data, passlen1) ||
1861 req_data_oob(req, req->in.data + passlen1, passlen2)) {
1862 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1863 return;
1866 p = req->in.data;
1867 if (!req_pull_blob(req, p, passlen1, &sess.nt1.in.password1)) {
1868 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1869 return;
1871 p += passlen1;
1872 if (!req_pull_blob(req, p, passlen2, &sess.nt1.in.password2)) {
1873 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1874 return;
1876 p += passlen2;
1878 p += req_pull_string(req, &sess.nt1.in.user, p, -1, STR_TERMINATE);
1879 p += req_pull_string(req, &sess.nt1.in.domain, p, -1, STR_TERMINATE);
1880 p += req_pull_string(req, &sess.nt1.in.os, p, -1, STR_TERMINATE);
1881 p += req_pull_string(req, &sess.nt1.in.lanman, p, -1, STR_TERMINATE);
1883 /* call the generic handler */
1884 status = smbsrv_sesssetup_backend(req, &sess);
1886 if (!NT_STATUS_IS_OK(status)) {
1887 smbsrv_send_error(req, status);
1888 return;
1891 /* construct reply */
1892 smbsrv_setup_reply(req, 3, 0);
1894 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1895 SSVAL(req->out.vwv, VWV(1), 0);
1896 SSVAL(req->out.vwv, VWV(2), sess.nt1.out.action);
1898 SSVAL(req->out.hdr, HDR_UID, sess.nt1.out.vuid);
1900 req_push_str(req, NULL, sess.nt1.out.os, -1, STR_TERMINATE);
1901 req_push_str(req, NULL, sess.nt1.out.lanman, -1, STR_TERMINATE);
1902 req_push_str(req, NULL, sess.nt1.out.domain, -1, STR_TERMINATE);
1904 smbsrv_chain_reply(req);
1908 /****************************************************************************
1909 reply to an SPNEGO style session setup command
1910 ****************************************************************************/
1911 static void reply_sesssetup_spnego(struct smbsrv_request *req)
1913 NTSTATUS status;
1914 union smb_sesssetup sess;
1915 uint8_t *p;
1916 uint16_t blob_len;
1918 sess.spnego.level = RAW_SESSSETUP_SPNEGO;
1920 /* parse request */
1921 sess.spnego.in.bufsize = SVAL(req->in.vwv, VWV(2));
1922 sess.spnego.in.mpx_max = SVAL(req->in.vwv, VWV(3));
1923 sess.spnego.in.vc_num = SVAL(req->in.vwv, VWV(4));
1924 sess.spnego.in.sesskey = IVAL(req->in.vwv, VWV(5));
1925 blob_len = SVAL(req->in.vwv, VWV(7));
1926 sess.spnego.in.capabilities = IVAL(req->in.vwv, VWV(10));
1928 p = req->in.data;
1929 if (!req_pull_blob(req, p, blob_len, &sess.spnego.in.secblob)) {
1930 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1931 return;
1933 p += blob_len;
1935 p += req_pull_string(req, &sess.spnego.in.os, p, -1, STR_TERMINATE);
1936 p += req_pull_string(req, &sess.spnego.in.lanman, p, -1, STR_TERMINATE);
1937 p += req_pull_string(req, &sess.spnego.in.workgroup, p, -1, STR_TERMINATE);
1939 /* call the generic handler */
1940 status = smbsrv_sesssetup_backend(req, &sess);
1942 if (!NT_STATUS_IS_OK(status) &&
1943 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1944 smbsrv_send_error(req, status);
1945 return;
1948 /* construct reply */
1949 smbsrv_setup_reply(req, 4, sess.spnego.out.secblob.length);
1951 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1952 smbsrv_setup_error(req, status);
1955 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1956 SSVAL(req->out.vwv, VWV(1), 0);
1957 SSVAL(req->out.vwv, VWV(2), sess.spnego.out.action);
1958 SSVAL(req->out.vwv, VWV(3), sess.spnego.out.secblob.length);
1960 SSVAL(req->out.hdr, HDR_UID, sess.spnego.out.vuid);
1962 memcpy(req->out.data, sess.spnego.out.secblob.data, sess.spnego.out.secblob.length);
1963 req_push_str(req, NULL, sess.spnego.out.os, -1, STR_TERMINATE);
1964 req_push_str(req, NULL, sess.spnego.out.lanman, -1, STR_TERMINATE);
1965 req_push_str(req, NULL, sess.spnego.out.workgroup, -1, STR_TERMINATE);
1967 smbsrv_chain_reply(req);
1971 /****************************************************************************
1972 reply to a session setup command
1973 ****************************************************************************/
1974 void smbsrv_reply_sesssetup(struct smbsrv_request *req)
1976 switch (req->in.wct) {
1977 case 10:
1978 /* a pre-NT1 call */
1979 reply_sesssetup_old(req);
1980 return;
1981 case 13:
1982 /* a NT1 call */
1983 reply_sesssetup_nt1(req);
1984 return;
1985 case 12:
1986 /* a SPNEGO call */
1987 reply_sesssetup_spnego(req);
1988 return;
1991 /* unsupported variant */
1992 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1995 /****************************************************************************
1996 Reply to a exit. This closes all files open by a smbpid
1997 ****************************************************************************/
1998 void smbsrv_reply_exit(struct smbsrv_request *req)
2000 struct smbsrv_handle_session_item *i, *ni;
2001 struct smbsrv_handle *h;
2002 struct smbsrv_tcon *tcon;
2003 uint16_t smbpid;
2005 SMBSRV_CHECK_WCT(req, 0);
2007 smbpid = SVAL(req->in.hdr,HDR_PID);
2009 /* first destroy all handles, which have the same PID as the request */
2010 for (i=req->session->handles; i; i=ni) {
2011 ni = i->next;
2012 h = i->handle;
2013 if (h->smbpid != smbpid) continue;
2015 talloc_free(h);
2019 * then let the ntvfs backends proxy the call if they want to,
2020 * but we didn't check the return value of the backends,
2021 * as for the SMB client the call succeed
2023 for (tcon=req->smb_conn->smb_tcons.list;tcon;tcon=tcon->next) {
2024 req->tcon = tcon;
2025 SMBSRV_SETUP_NTVFS_REQUEST(NULL,0);
2026 ntvfs_exit(req->ntvfs);
2027 talloc_free(req->ntvfs);
2028 req->ntvfs = NULL;
2029 req->tcon = NULL;
2032 smbsrv_setup_reply(req, 0, 0);
2033 smbsrv_send_reply(req);
2036 /****************************************************************************
2037 Reply to a SMBulogoffX.
2038 ****************************************************************************/
2039 void smbsrv_reply_ulogoffX(struct smbsrv_request *req)
2041 struct smbsrv_handle_session_item *i, *ni;
2042 struct smbsrv_handle *h;
2043 struct smbsrv_tcon *tcon;
2045 SMBSRV_CHECK_WCT(req, 2);
2048 * TODO: cancel all pending requests
2052 /* destroy all handles */
2053 for (i=req->session->handles; i; i=ni) {
2054 ni = i->next;
2055 h = i->handle;
2056 talloc_free(h);
2060 * then let the ntvfs backends proxy the call if they want to,
2061 * but we didn't check the return value of the backends,
2062 * as for the SMB client the call succeed
2064 for (tcon=req->smb_conn->smb_tcons.list;tcon;tcon=tcon->next) {
2065 req->tcon = tcon;
2066 SMBSRV_SETUP_NTVFS_REQUEST(NULL,0);
2067 ntvfs_logoff(req->ntvfs);
2068 talloc_free(req->ntvfs);
2069 req->ntvfs = NULL;
2070 req->tcon = NULL;
2073 talloc_free(req->session);
2074 req->session = NULL; /* it is now invalid, don't use on
2075 any chained packets */
2077 smbsrv_setup_reply(req, 2, 0);
2079 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
2080 SSVAL(req->out.vwv, VWV(1), 0);
2082 smbsrv_chain_reply(req);
2085 /****************************************************************************
2086 Reply to an SMBfindclose request
2087 ****************************************************************************/
2088 void smbsrv_reply_findclose(struct smbsrv_request *req)
2090 union smb_search_close *io;
2092 /* parse request */
2093 SMBSRV_CHECK_WCT(req, 1);
2094 SMBSRV_TALLOC_IO_PTR(io, union smb_search_close);
2095 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
2097 io->findclose.level = RAW_FINDCLOSE_FINDCLOSE;
2098 io->findclose.in.handle = SVAL(req->in.vwv, VWV(0));
2100 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_search_close(req->ntvfs, io));
2103 /****************************************************************************
2104 Reply to an SMBfindnclose request
2105 ****************************************************************************/
2106 void smbsrv_reply_findnclose(struct smbsrv_request *req)
2108 smbsrv_send_error(req, NT_STATUS_FOOBAR);
2112 /****************************************************************************
2113 Reply to an SMBntcreateX request (async send)
2114 ****************************************************************************/
2115 static void reply_ntcreate_and_X_send(struct ntvfs_request *ntvfs)
2117 struct smbsrv_request *req;
2118 union smb_open *io;
2120 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_open);
2122 /* construct reply */
2123 smbsrv_setup_reply(req, 34, 0);
2125 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
2126 SSVAL(req->out.vwv, VWV(1), 0);
2127 SCVAL(req->out.vwv, VWV(2), io->ntcreatex.out.oplock_level);
2129 /* the rest of the parameters are not aligned! */
2130 smbsrv_push_fnum(req->out.vwv, 5, io->ntcreatex.out.file.ntvfs);
2131 SIVAL(req->out.vwv, 7, io->ntcreatex.out.create_action);
2132 push_nttime(req->out.vwv, 11, io->ntcreatex.out.create_time);
2133 push_nttime(req->out.vwv, 19, io->ntcreatex.out.access_time);
2134 push_nttime(req->out.vwv, 27, io->ntcreatex.out.write_time);
2135 push_nttime(req->out.vwv, 35, io->ntcreatex.out.change_time);
2136 SIVAL(req->out.vwv, 43, io->ntcreatex.out.attrib);
2137 SBVAL(req->out.vwv, 47, io->ntcreatex.out.alloc_size);
2138 SBVAL(req->out.vwv, 55, io->ntcreatex.out.size);
2139 SSVAL(req->out.vwv, 63, io->ntcreatex.out.file_type);
2140 SSVAL(req->out.vwv, 65, io->ntcreatex.out.ipc_state);
2141 SCVAL(req->out.vwv, 67, io->ntcreatex.out.is_directory);
2143 req->chained_fnum = SVAL(req->out.vwv, 5);
2145 smbsrv_chain_reply(req);
2148 /****************************************************************************
2149 Reply to an SMBntcreateX request
2150 ****************************************************************************/
2151 void smbsrv_reply_ntcreate_and_X(struct smbsrv_request *req)
2153 union smb_open *io;
2154 uint16_t fname_len;
2156 /* parse the request */
2157 SMBSRV_CHECK_WCT(req, 24);
2158 SMBSRV_TALLOC_IO_PTR(io, union smb_open);
2159 SMBSRV_SETUP_NTVFS_REQUEST(reply_ntcreate_and_X_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
2161 io->ntcreatex.level = RAW_OPEN_NTCREATEX;
2163 /* notice that the word parameters are not word aligned, so we don't use VWV() */
2164 fname_len = SVAL(req->in.vwv, 5);
2165 io->ntcreatex.in.flags = IVAL(req->in.vwv, 7);
2166 io->ntcreatex.in.root_fid = IVAL(req->in.vwv, 11);
2167 io->ntcreatex.in.access_mask = IVAL(req->in.vwv, 15);
2168 io->ntcreatex.in.alloc_size = BVAL(req->in.vwv, 19);
2169 io->ntcreatex.in.file_attr = IVAL(req->in.vwv, 27);
2170 io->ntcreatex.in.share_access = IVAL(req->in.vwv, 31);
2171 io->ntcreatex.in.open_disposition = IVAL(req->in.vwv, 35);
2172 io->ntcreatex.in.create_options = IVAL(req->in.vwv, 39);
2173 io->ntcreatex.in.impersonation = IVAL(req->in.vwv, 43);
2174 io->ntcreatex.in.security_flags = CVAL(req->in.vwv, 47);
2175 io->ntcreatex.in.ea_list = NULL;
2176 io->ntcreatex.in.sec_desc = NULL;
2178 /* we need a neater way to handle this alignment */
2179 if ((req->flags2 & FLAGS2_UNICODE_STRINGS) &&
2180 ucs2_align(req->in.buffer, req->in.data, STR_TERMINATE|STR_UNICODE)) {
2181 fname_len++;
2184 req_pull_string(req, &io->ntcreatex.in.fname, req->in.data, fname_len, STR_TERMINATE);
2185 if (!io->ntcreatex.in.fname) {
2186 smbsrv_send_error(req, NT_STATUS_FOOBAR);
2187 return;
2190 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, io));
2194 /****************************************************************************
2195 Reply to an SMBntcancel request
2196 ****************************************************************************/
2197 void smbsrv_reply_ntcancel(struct smbsrv_request *req)
2199 struct smbsrv_request *r;
2200 uint16_t mid = SVAL(req->in.hdr,HDR_MID);
2201 uint16_t pid = SVAL(req->in.hdr,HDR_PID);
2203 for (r = req->smb_conn->requests; r; r = r->next) {
2204 if (mid != SVAL(r->in.hdr,HDR_MID)) continue;
2205 /* do we really need to check the PID? */
2206 if (pid != SVAL(r->in.hdr,HDR_PID)) continue;
2208 SMBSRV_CHECK(ntvfs_cancel(r->ntvfs));
2210 /* NOTE: this request does not generate a reply */
2211 talloc_free(req);
2212 return;
2215 /* TODO: workout the correct error code */
2216 smbsrv_send_error(req, NT_STATUS_FOOBAR);
2220 parse the called/calling names from session request
2222 static NTSTATUS parse_session_request(struct smbsrv_request *req)
2224 DATA_BLOB blob;
2225 NTSTATUS status;
2227 blob.data = req->in.buffer + 4;
2228 blob.length = ascii_len_n((const char *)blob.data, req->in.size - PTR_DIFF(blob.data, req->in.buffer));
2229 if (blob.length == 0) return NT_STATUS_BAD_NETWORK_NAME;
2231 req->smb_conn->negotiate.called_name = talloc(req->smb_conn, struct nbt_name);
2232 req->smb_conn->negotiate.calling_name = talloc(req->smb_conn, struct nbt_name);
2233 if (req->smb_conn->negotiate.called_name == NULL ||
2234 req->smb_conn->negotiate.calling_name == NULL) {
2235 return NT_STATUS_NO_MEMORY;
2238 status = nbt_name_from_blob(req->smb_conn, &blob,
2239 req->smb_conn->negotiate.called_name);
2240 NT_STATUS_NOT_OK_RETURN(status);
2242 blob.data += blob.length;
2243 blob.length = ascii_len_n((const char *)blob.data, req->in.size - PTR_DIFF(blob.data, req->in.buffer));
2244 if (blob.length == 0) return NT_STATUS_BAD_NETWORK_NAME;
2246 status = nbt_name_from_blob(req->smb_conn, &blob,
2247 req->smb_conn->negotiate.calling_name);
2248 NT_STATUS_NOT_OK_RETURN(status);
2250 req->smb_conn->negotiate.done_nbt_session = True;
2252 return NT_STATUS_OK;
2257 /****************************************************************************
2258 Reply to a special message - a SMB packet with non zero NBT message type
2259 ****************************************************************************/
2260 void smbsrv_reply_special(struct smbsrv_request *req)
2262 uint8_t msg_type;
2263 uint8_t *buf = talloc_zero_array(req, uint8_t, 4);
2265 msg_type = CVAL(req->in.buffer,0);
2267 SIVAL(buf, 0, 0);
2269 switch (msg_type) {
2270 case 0x81: /* session request */
2271 if (req->smb_conn->negotiate.done_nbt_session) {
2272 DEBUG(0,("Warning: ignoring secondary session request\n"));
2273 return;
2276 SCVAL(buf,0,0x82);
2277 SCVAL(buf,3,0);
2279 /* we don't check the status - samba always accepts session
2280 requests for any name */
2281 parse_session_request(req);
2283 req->out.buffer = buf;
2284 req->out.size = 4;
2285 smbsrv_send_reply_nosign(req);
2286 return;
2288 case 0x89: /* session keepalive request
2289 (some old clients produce this?) */
2290 SCVAL(buf, 0, SMBkeepalive);
2291 SCVAL(buf, 3, 0);
2292 req->out.buffer = buf;
2293 req->out.size = 4;
2294 smbsrv_send_reply_nosign(req);
2295 return;
2297 case SMBkeepalive:
2298 /* session keepalive - swallow it */
2299 talloc_free(req);
2300 return;
2303 DEBUG(0,("Unexpected NBT session packet (%d)\n", msg_type));
2304 talloc_free(req);