smbd: Fix a typo
[Samba/gbeck.git] / source4 / smb_server / smb / reply.c
blobbae6b2ca79e061858c322b76db0da49d2d08663e
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 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 This file handles most of the reply_ calls that the server
23 makes to handle specific SMB commands
26 #include "includes.h"
27 #include "smb_server/smb_server.h"
28 #include "ntvfs/ntvfs.h"
29 #include "librpc/gen_ndr/ndr_nbt.h"
30 #include "libcli/nbt/libnbt.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 (async reply)
49 ****************************************************************************/
50 static void reply_tcon_send(struct ntvfs_request *ntvfs)
52 struct smbsrv_request *req;
53 union smb_tcon *con;
55 SMBSRV_CHECK_ASYNC_STATUS(con, union smb_tcon);
57 /* construct reply */
58 smbsrv_setup_reply(req, 2, 0);
60 SSVAL(req->out.vwv, VWV(0), con->tcon.out.max_xmit);
61 SSVAL(req->out.vwv, VWV(1), con->tcon.out.tid);
62 SSVAL(req->out.hdr, HDR_TID, req->tcon->tid);
64 smbsrv_send_reply(req);
67 /****************************************************************************
68 Reply to a tcon.
69 ****************************************************************************/
70 void smbsrv_reply_tcon(struct smbsrv_request *req)
72 union smb_tcon *con;
73 NTSTATUS status;
74 uint8_t *p;
76 /* parse request */
77 SMBSRV_CHECK_WCT(req, 0);
79 SMBSRV_TALLOC_IO_PTR(con, union smb_tcon);
81 con->tcon.level = RAW_TCON_TCON;
83 p = req->in.data;
84 p += req_pull_ascii4(&req->in.bufinfo, &con->tcon.in.service, p, STR_TERMINATE);
85 p += req_pull_ascii4(&req->in.bufinfo, &con->tcon.in.password, p, STR_TERMINATE);
86 p += req_pull_ascii4(&req->in.bufinfo, &con->tcon.in.dev, p, STR_TERMINATE);
88 if (!con->tcon.in.service || !con->tcon.in.password || !con->tcon.in.dev) {
89 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
90 return;
93 /* Instantiate backend */
94 status = smbsrv_tcon_backend(req, con);
95 if (!NT_STATUS_IS_OK(status)) {
96 smbsrv_send_error(req, status);
97 return;
100 SMBSRV_SETUP_NTVFS_REQUEST(reply_tcon_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
102 /* Invoke NTVFS connection hook */
103 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_connect(req->ntvfs, con));
107 /****************************************************************************
108 Reply to a tcon and X (async reply)
109 ****************************************************************************/
110 static void reply_tcon_and_X_send(struct ntvfs_request *ntvfs)
112 struct smbsrv_request *req;
113 union smb_tcon *con;
115 SMBSRV_CHECK_ASYNC_STATUS(con, union smb_tcon);
117 /* construct reply - two variants */
118 if (req->smb_conn->negotiate.protocol < PROTOCOL_NT1) {
119 smbsrv_setup_reply(req, 2, 0);
121 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
122 SSVAL(req->out.vwv, VWV(1), 0);
124 req_push_str(req, NULL, con->tconx.out.dev_type, -1, STR_TERMINATE|STR_ASCII);
125 } else {
126 smbsrv_setup_reply(req, 3, 0);
128 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
129 SSVAL(req->out.vwv, VWV(1), 0);
130 SSVAL(req->out.vwv, VWV(2), con->tconx.out.options);
132 req_push_str(req, NULL, con->tconx.out.dev_type, -1, STR_TERMINATE|STR_ASCII);
133 req_push_str(req, NULL, con->tconx.out.fs_type, -1, STR_TERMINATE);
136 /* set the incoming and outgoing tid to the just created one */
137 SSVAL(req->in.hdr, HDR_TID, con->tconx.out.tid);
138 SSVAL(req->out.hdr,HDR_TID, con->tconx.out.tid);
140 smbsrv_chain_reply(req);
143 /****************************************************************************
144 Reply to a tcon and X.
145 ****************************************************************************/
146 void smbsrv_reply_tcon_and_X(struct smbsrv_request *req)
148 NTSTATUS status;
149 union smb_tcon *con;
150 uint8_t *p;
151 uint16_t passlen;
153 SMBSRV_TALLOC_IO_PTR(con, union smb_tcon);
155 con->tconx.level = RAW_TCON_TCONX;
157 /* parse request */
158 SMBSRV_CHECK_WCT(req, 4);
160 con->tconx.in.flags = SVAL(req->in.vwv, VWV(2));
161 passlen = SVAL(req->in.vwv, VWV(3));
163 p = req->in.data;
165 if (!req_pull_blob(&req->in.bufinfo, p, passlen, &con->tconx.in.password)) {
166 smbsrv_send_error(req, NT_STATUS_ILL_FORMED_PASSWORD);
167 return;
169 p += passlen;
171 p += req_pull_string(&req->in.bufinfo, &con->tconx.in.path, p, -1, STR_TERMINATE);
172 p += req_pull_string(&req->in.bufinfo, &con->tconx.in.device, p, -1, STR_ASCII);
174 if (!con->tconx.in.path || !con->tconx.in.device) {
175 smbsrv_send_error(req, NT_STATUS_BAD_DEVICE_TYPE);
176 return;
179 /* Instantiate backend */
180 status = smbsrv_tcon_backend(req, con);
181 if (!NT_STATUS_IS_OK(status)) {
182 smbsrv_send_error(req, status);
183 return;
186 SMBSRV_SETUP_NTVFS_REQUEST(reply_tcon_and_X_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
188 /* Invoke NTVFS connection hook */
189 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_connect(req->ntvfs, con));
193 /****************************************************************************
194 Reply to an unknown request
195 ****************************************************************************/
196 void smbsrv_reply_unknown(struct smbsrv_request *req)
198 int type;
200 type = CVAL(req->in.hdr, HDR_COM);
202 DEBUG(0,("unknown command type %d (0x%X)\n", type, type));
204 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRunknownsmb));
208 /****************************************************************************
209 Reply to an ioctl (async reply)
210 ****************************************************************************/
211 static void reply_ioctl_send(struct ntvfs_request *ntvfs)
213 struct smbsrv_request *req;
214 union smb_ioctl *io;
216 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_ioctl);
218 /* the +1 is for nicer alignment */
219 smbsrv_setup_reply(req, 8, io->ioctl.out.blob.length+1);
220 SSVAL(req->out.vwv, VWV(1), io->ioctl.out.blob.length);
221 SSVAL(req->out.vwv, VWV(5), io->ioctl.out.blob.length);
222 SSVAL(req->out.vwv, VWV(6), PTR_DIFF(req->out.data, req->out.hdr) + 1);
224 memcpy(req->out.data+1, io->ioctl.out.blob.data, io->ioctl.out.blob.length);
226 smbsrv_send_reply(req);
229 /****************************************************************************
230 Reply to an ioctl.
231 ****************************************************************************/
232 void smbsrv_reply_ioctl(struct smbsrv_request *req)
234 union smb_ioctl *io;
236 /* parse request */
237 SMBSRV_CHECK_WCT(req, 3);
238 SMBSRV_TALLOC_IO_PTR(io, union smb_ioctl);
239 SMBSRV_SETUP_NTVFS_REQUEST(reply_ioctl_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
241 io->ioctl.level = RAW_IOCTL_IOCTL;
242 io->ioctl.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
243 io->ioctl.in.request = IVAL(req->in.vwv, VWV(1));
245 SMBSRV_CHECK_FILE_HANDLE_ERROR(io->ioctl.in.file.ntvfs,
246 NT_STATUS_DOS(ERRSRV, ERRerror));
247 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_ioctl(req->ntvfs, io));
251 /****************************************************************************
252 Reply to a chkpth.
253 ****************************************************************************/
254 void smbsrv_reply_chkpth(struct smbsrv_request *req)
256 union smb_chkpath *io;
258 SMBSRV_TALLOC_IO_PTR(io, union smb_chkpath);
259 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
261 req_pull_ascii4(&req->in.bufinfo, &io->chkpath.in.path, req->in.data, STR_TERMINATE);
263 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_chkpath(req->ntvfs, io));
266 /****************************************************************************
267 Reply to a getatr (async reply)
268 ****************************************************************************/
269 static void reply_getatr_send(struct ntvfs_request *ntvfs)
271 struct smbsrv_request *req;
272 union smb_fileinfo *st;
274 SMBSRV_CHECK_ASYNC_STATUS(st, union smb_fileinfo);
276 /* construct reply */
277 smbsrv_setup_reply(req, 10, 0);
279 SSVAL(req->out.vwv, VWV(0), st->getattr.out.attrib);
280 srv_push_dos_date3(req->smb_conn, req->out.vwv, VWV(1), st->getattr.out.write_time);
281 SIVAL(req->out.vwv, VWV(3), st->getattr.out.size);
283 SMBSRV_VWV_RESERVED(5, 5);
285 smbsrv_send_reply(req);
289 /****************************************************************************
290 Reply to a getatr.
291 ****************************************************************************/
292 void smbsrv_reply_getatr(struct smbsrv_request *req)
294 union smb_fileinfo *st;
296 SMBSRV_TALLOC_IO_PTR(st, union smb_fileinfo);
297 SMBSRV_SETUP_NTVFS_REQUEST(reply_getatr_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
299 st->getattr.level = RAW_FILEINFO_GETATTR;
301 /* parse request */
302 req_pull_ascii4(&req->in.bufinfo, &st->getattr.in.file.path, req->in.data, STR_TERMINATE);
303 if (!st->getattr.in.file.path) {
304 smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
305 return;
308 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_qpathinfo(req->ntvfs, st));
312 /****************************************************************************
313 Reply to a setatr.
314 ****************************************************************************/
315 void smbsrv_reply_setatr(struct smbsrv_request *req)
317 union smb_setfileinfo *st;
319 /* parse request */
320 SMBSRV_CHECK_WCT(req, 8);
321 SMBSRV_TALLOC_IO_PTR(st, union smb_setfileinfo);
322 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
324 st->setattr.level = RAW_SFILEINFO_SETATTR;
325 st->setattr.in.attrib = SVAL(req->in.vwv, VWV(0));
326 st->setattr.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(1));
328 req_pull_ascii4(&req->in.bufinfo, &st->setattr.in.file.path, req->in.data, STR_TERMINATE);
330 if (!st->setattr.in.file.path) {
331 smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
332 return;
335 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_setpathinfo(req->ntvfs, st));
339 /****************************************************************************
340 Reply to a dskattr (async reply)
341 ****************************************************************************/
342 static void reply_dskattr_send(struct ntvfs_request *ntvfs)
344 struct smbsrv_request *req;
345 union smb_fsinfo *fs;
347 SMBSRV_CHECK_ASYNC_STATUS(fs, union smb_fsinfo);
349 /* construct reply */
350 smbsrv_setup_reply(req, 5, 0);
352 SSVAL(req->out.vwv, VWV(0), fs->dskattr.out.units_total);
353 SSVAL(req->out.vwv, VWV(1), fs->dskattr.out.blocks_per_unit);
354 SSVAL(req->out.vwv, VWV(2), fs->dskattr.out.block_size);
355 SSVAL(req->out.vwv, VWV(3), fs->dskattr.out.units_free);
357 SMBSRV_VWV_RESERVED(4, 1);
359 smbsrv_send_reply(req);
363 /****************************************************************************
364 Reply to a dskattr.
365 ****************************************************************************/
366 void smbsrv_reply_dskattr(struct smbsrv_request *req)
368 union smb_fsinfo *fs;
370 SMBSRV_TALLOC_IO_PTR(fs, union smb_fsinfo);
371 SMBSRV_SETUP_NTVFS_REQUEST(reply_dskattr_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
373 fs->dskattr.level = RAW_QFS_DSKATTR;
375 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_fsinfo(req->ntvfs, fs));
379 /****************************************************************************
380 Reply to an open (async reply)
381 ****************************************************************************/
382 static void reply_open_send(struct ntvfs_request *ntvfs)
384 struct smbsrv_request *req;
385 union smb_open *oi;
387 SMBSRV_CHECK_ASYNC_STATUS(oi, union smb_open);
389 /* construct reply */
390 smbsrv_setup_reply(req, 7, 0);
392 smbsrv_push_fnum(req->out.vwv, VWV(0), oi->openold.out.file.ntvfs);
393 SSVAL(req->out.vwv, VWV(1), oi->openold.out.attrib);
394 srv_push_dos_date3(req->smb_conn, req->out.vwv, VWV(2), oi->openold.out.write_time);
395 SIVAL(req->out.vwv, VWV(4), oi->openold.out.size);
396 SSVAL(req->out.vwv, VWV(6), oi->openold.out.rmode);
398 smbsrv_send_reply(req);
401 /****************************************************************************
402 Reply to an open.
403 ****************************************************************************/
404 void smbsrv_reply_open(struct smbsrv_request *req)
406 union smb_open *oi;
408 /* parse request */
409 SMBSRV_CHECK_WCT(req, 2);
410 SMBSRV_TALLOC_IO_PTR(oi, union smb_open);
411 SMBSRV_SETUP_NTVFS_REQUEST(reply_open_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
413 oi->openold.level = RAW_OPEN_OPEN;
414 oi->openold.in.open_mode = SVAL(req->in.vwv, VWV(0));
415 oi->openold.in.search_attrs = SVAL(req->in.vwv, VWV(1));
417 req_pull_ascii4(&req->in.bufinfo, &oi->openold.in.fname, req->in.data, STR_TERMINATE);
419 if (!oi->openold.in.fname) {
420 smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
421 return;
424 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, oi));
428 /****************************************************************************
429 Reply to an open and X (async reply)
430 ****************************************************************************/
431 static void reply_open_and_X_send(struct ntvfs_request *ntvfs)
433 struct smbsrv_request *req;
434 union smb_open *oi;
436 SMBSRV_CHECK_ASYNC_STATUS(oi, union smb_open);
438 /* build the reply */
439 if (oi->openx.in.flags & OPENX_FLAGS_EXTENDED_RETURN) {
440 smbsrv_setup_reply(req, 19, 0);
441 } else {
442 smbsrv_setup_reply(req, 15, 0);
445 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
446 SSVAL(req->out.vwv, VWV(1), 0);
447 smbsrv_push_fnum(req->out.vwv, VWV(2), oi->openx.out.file.ntvfs);
448 SSVAL(req->out.vwv, VWV(3), oi->openx.out.attrib);
449 srv_push_dos_date3(req->smb_conn, req->out.vwv, VWV(4), oi->openx.out.write_time);
450 SIVAL(req->out.vwv, VWV(6), oi->openx.out.size);
451 SSVAL(req->out.vwv, VWV(8), oi->openx.out.access);
452 SSVAL(req->out.vwv, VWV(9), oi->openx.out.ftype);
453 SSVAL(req->out.vwv, VWV(10),oi->openx.out.devstate);
454 SSVAL(req->out.vwv, VWV(11),oi->openx.out.action);
455 SIVAL(req->out.vwv, VWV(12),oi->openx.out.unique_fid);
456 SSVAL(req->out.vwv, VWV(14),0); /* reserved */
457 if (oi->openx.in.flags & OPENX_FLAGS_EXTENDED_RETURN) {
458 SIVAL(req->out.vwv, VWV(15),oi->openx.out.access_mask);
459 SMBSRV_VWV_RESERVED(17, 2);
462 req->chained_fnum = SVAL(req->out.vwv, VWV(2));
464 smbsrv_chain_reply(req);
468 /****************************************************************************
469 Reply to an open and X.
470 ****************************************************************************/
471 void smbsrv_reply_open_and_X(struct smbsrv_request *req)
473 union smb_open *oi;
475 /* parse the request */
476 SMBSRV_CHECK_WCT(req, 15);
477 SMBSRV_TALLOC_IO_PTR(oi, union smb_open);
478 SMBSRV_SETUP_NTVFS_REQUEST(reply_open_and_X_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
480 oi->openx.level = RAW_OPEN_OPENX;
481 oi->openx.in.flags = SVAL(req->in.vwv, VWV(2));
482 oi->openx.in.open_mode = SVAL(req->in.vwv, VWV(3));
483 oi->openx.in.search_attrs = SVAL(req->in.vwv, VWV(4));
484 oi->openx.in.file_attrs = SVAL(req->in.vwv, VWV(5));
485 oi->openx.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(6));
486 oi->openx.in.open_func = SVAL(req->in.vwv, VWV(8));
487 oi->openx.in.size = IVAL(req->in.vwv, VWV(9));
488 oi->openx.in.timeout = IVAL(req->in.vwv, VWV(11));
490 req_pull_ascii4(&req->in.bufinfo, &oi->openx.in.fname, req->in.data, STR_TERMINATE);
492 if (!oi->openx.in.fname) {
493 smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
494 return;
497 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, oi));
501 /****************************************************************************
502 Reply to a mknew or a create.
503 ****************************************************************************/
504 static void reply_mknew_send(struct ntvfs_request *ntvfs)
506 struct smbsrv_request *req;
507 union smb_open *oi;
509 SMBSRV_CHECK_ASYNC_STATUS(oi, union smb_open);
511 /* build the reply */
512 smbsrv_setup_reply(req, 1, 0);
514 smbsrv_push_fnum(req->out.vwv, VWV(0), oi->mknew.out.file.ntvfs);
516 smbsrv_send_reply(req);
520 /****************************************************************************
521 Reply to a mknew or a create.
522 ****************************************************************************/
523 void smbsrv_reply_mknew(struct smbsrv_request *req)
525 union smb_open *oi;
527 /* parse the request */
528 SMBSRV_CHECK_WCT(req, 3);
529 SMBSRV_TALLOC_IO_PTR(oi, union smb_open);
530 SMBSRV_SETUP_NTVFS_REQUEST(reply_mknew_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
532 if (CVAL(req->in.hdr, HDR_COM) == SMBmknew) {
533 oi->mknew.level = RAW_OPEN_MKNEW;
534 } else {
535 oi->mknew.level = RAW_OPEN_CREATE;
537 oi->mknew.in.attrib = SVAL(req->in.vwv, VWV(0));
538 oi->mknew.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(1));
540 req_pull_ascii4(&req->in.bufinfo, &oi->mknew.in.fname, req->in.data, STR_TERMINATE);
542 if (!oi->mknew.in.fname) {
543 smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
544 return;
547 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, oi));
550 /****************************************************************************
551 Reply to a create temporary file (async reply)
552 ****************************************************************************/
553 static void reply_ctemp_send(struct ntvfs_request *ntvfs)
555 struct smbsrv_request *req;
556 union smb_open *oi;
558 SMBSRV_CHECK_ASYNC_STATUS(oi, union smb_open);
560 /* build the reply */
561 smbsrv_setup_reply(req, 1, 0);
563 smbsrv_push_fnum(req->out.vwv, VWV(0), oi->ctemp.out.file.ntvfs);
565 /* the returned filename is relative to the directory */
566 req_push_str(req, NULL, oi->ctemp.out.name, -1, STR_TERMINATE | STR_ASCII);
568 smbsrv_send_reply(req);
571 /****************************************************************************
572 Reply to a create temporary file.
573 ****************************************************************************/
574 void smbsrv_reply_ctemp(struct smbsrv_request *req)
576 union smb_open *oi;
578 /* parse the request */
579 SMBSRV_CHECK_WCT(req, 3);
580 SMBSRV_TALLOC_IO_PTR(oi, union smb_open);
581 SMBSRV_SETUP_NTVFS_REQUEST(reply_ctemp_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
583 oi->ctemp.level = RAW_OPEN_CTEMP;
584 oi->ctemp.in.attrib = SVAL(req->in.vwv, VWV(0));
585 oi->ctemp.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(1));
587 /* the filename is actually a directory name, the server provides a filename
588 in that directory */
589 req_pull_ascii4(&req->in.bufinfo, &oi->ctemp.in.directory, req->in.data, STR_TERMINATE);
591 if (!oi->ctemp.in.directory) {
592 smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
593 return;
596 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, oi));
600 /****************************************************************************
601 Reply to a unlink
602 ****************************************************************************/
603 void smbsrv_reply_unlink(struct smbsrv_request *req)
605 union smb_unlink *unl;
607 /* parse the request */
608 SMBSRV_CHECK_WCT(req, 1);
609 SMBSRV_TALLOC_IO_PTR(unl, union smb_unlink);
610 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
612 unl->unlink.in.attrib = SVAL(req->in.vwv, VWV(0));
614 req_pull_ascii4(&req->in.bufinfo, &unl->unlink.in.pattern, req->in.data, STR_TERMINATE);
616 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_unlink(req->ntvfs, unl));
620 /****************************************************************************
621 Reply to a readbraw (core+ protocol).
622 this is a strange packet because it doesn't use a standard SMB header in the reply,
623 only the 4 byte NBT header
624 This command must be replied to synchronously
625 ****************************************************************************/
626 void smbsrv_reply_readbraw(struct smbsrv_request *req)
628 NTSTATUS status;
629 union smb_read io;
631 io.readbraw.level = RAW_READ_READBRAW;
633 /* there are two variants, one with 10 and one with 8 command words */
634 if (req->in.wct < 8) {
635 goto failed;
638 io.readbraw.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
639 io.readbraw.in.offset = IVAL(req->in.vwv, VWV(1));
640 io.readbraw.in.maxcnt = SVAL(req->in.vwv, VWV(3));
641 io.readbraw.in.mincnt = SVAL(req->in.vwv, VWV(4));
642 io.readbraw.in.timeout = IVAL(req->in.vwv, VWV(5));
644 if (!io.readbraw.in.file.ntvfs) {
645 goto failed;
648 /* the 64 bit variant */
649 if (req->in.wct == 10) {
650 uint32_t offset_high = IVAL(req->in.vwv, VWV(8));
651 io.readbraw.in.offset |= (((off_t)offset_high) << 32);
654 /* before calling the backend we setup the raw buffer. This
655 * saves a copy later */
656 req->out.size = io.readbraw.in.maxcnt + NBT_HDR_SIZE;
657 req->out.buffer = talloc_size(req, req->out.size);
658 if (req->out.buffer == NULL) {
659 goto failed;
661 SIVAL(req->out.buffer, 0, 0); /* init NBT header */
663 /* tell the backend where to put the data */
664 io.readbraw.out.data = req->out.buffer + NBT_HDR_SIZE;
666 /* prepare the ntvfs request */
667 req->ntvfs = ntvfs_request_create(req->tcon->ntvfs, req,
668 req->session->session_info,
669 SVAL(req->in.hdr,HDR_PID),
670 req->request_time,
671 req, NULL, 0);
672 if (!req->ntvfs) {
673 goto failed;
676 /* call the backend */
677 status = ntvfs_read(req->ntvfs, &io);
678 if (!NT_STATUS_IS_OK(status)) {
679 goto failed;
682 req->out.size = io.readbraw.out.nread + NBT_HDR_SIZE;
684 smbsrv_send_reply_nosign(req);
685 return;
687 failed:
688 /* any failure in readbraw is equivalent to reading zero bytes */
689 req->out.size = 4;
690 req->out.buffer = talloc_size(req, req->out.size);
691 SIVAL(req->out.buffer, 0, 0); /* init NBT header */
693 smbsrv_send_reply_nosign(req);
697 /****************************************************************************
698 Reply to a lockread (async reply)
699 ****************************************************************************/
700 static void reply_lockread_send(struct ntvfs_request *ntvfs)
702 struct smbsrv_request *req;
703 union smb_read *io;
705 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_read);
707 /* trim packet */
708 io->lockread.out.nread = MIN(io->lockread.out.nread,
709 req_max_data(req) - 3);
710 req_grow_data(req, 3 + io->lockread.out.nread);
712 /* construct reply */
713 SSVAL(req->out.vwv, VWV(0), io->lockread.out.nread);
714 SMBSRV_VWV_RESERVED(1, 4);
716 SCVAL(req->out.data, 0, SMB_DATA_BLOCK);
717 SSVAL(req->out.data, 1, io->lockread.out.nread);
719 smbsrv_send_reply(req);
723 /****************************************************************************
724 Reply to a lockread (core+ protocol).
725 note that the lock is a write lock, not a read lock!
726 ****************************************************************************/
727 void smbsrv_reply_lockread(struct smbsrv_request *req)
729 union smb_read *io;
731 /* parse request */
732 SMBSRV_CHECK_WCT(req, 5);
733 SMBSRV_TALLOC_IO_PTR(io, union smb_read);
734 SMBSRV_SETUP_NTVFS_REQUEST(reply_lockread_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
736 io->lockread.level = RAW_READ_LOCKREAD;
737 io->lockread.in.file.ntvfs= smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
738 io->lockread.in.count = SVAL(req->in.vwv, VWV(1));
739 io->lockread.in.offset = IVAL(req->in.vwv, VWV(2));
740 io->lockread.in.remaining = SVAL(req->in.vwv, VWV(4));
742 /* setup the reply packet assuming the maximum possible read */
743 smbsrv_setup_reply(req, 5, 3 + io->lockread.in.count);
745 /* tell the backend where to put the data */
746 io->lockread.out.data = req->out.data + 3;
748 SMBSRV_CHECK_FILE_HANDLE(io->lockread.in.file.ntvfs);
749 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_read(req->ntvfs, io));
754 /****************************************************************************
755 Reply to a read (async reply)
756 ****************************************************************************/
757 static void reply_read_send(struct ntvfs_request *ntvfs)
759 struct smbsrv_request *req;
760 union smb_read *io;
762 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_read);
764 /* trim packet */
765 io->read.out.nread = MIN(io->read.out.nread,
766 req_max_data(req) - 3);
767 req_grow_data(req, 3 + io->read.out.nread);
769 /* construct reply */
770 SSVAL(req->out.vwv, VWV(0), io->read.out.nread);
771 SMBSRV_VWV_RESERVED(1, 4);
773 SCVAL(req->out.data, 0, SMB_DATA_BLOCK);
774 SSVAL(req->out.data, 1, io->read.out.nread);
776 smbsrv_send_reply(req);
779 /****************************************************************************
780 Reply to a read.
781 ****************************************************************************/
782 void smbsrv_reply_read(struct smbsrv_request *req)
784 union smb_read *io;
786 /* parse request */
787 SMBSRV_CHECK_WCT(req, 5);
788 SMBSRV_TALLOC_IO_PTR(io, union smb_read);
789 SMBSRV_SETUP_NTVFS_REQUEST(reply_read_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
791 io->read.level = RAW_READ_READ;
792 io->read.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
793 io->read.in.count = SVAL(req->in.vwv, VWV(1));
794 io->read.in.offset = IVAL(req->in.vwv, VWV(2));
795 io->read.in.remaining = SVAL(req->in.vwv, VWV(4));
797 /* setup the reply packet assuming the maximum possible read */
798 smbsrv_setup_reply(req, 5, 3 + io->read.in.count);
800 /* tell the backend where to put the data */
801 io->read.out.data = req->out.data + 3;
803 SMBSRV_CHECK_FILE_HANDLE(io->read.in.file.ntvfs);
804 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_read(req->ntvfs, io));
807 /****************************************************************************
808 Reply to a read and X (async reply)
809 ****************************************************************************/
810 static void reply_read_and_X_send(struct ntvfs_request *ntvfs)
812 struct smbsrv_request *req;
813 union smb_read *io;
815 SMBSRV_CHECK_ASYNC_STATUS_ERR(io, union smb_read);
817 /* readx reply packets can be over-sized */
818 req->control_flags |= SMBSRV_REQ_CONTROL_LARGE;
819 if (io->readx.in.maxcnt != 0xFFFF &&
820 io->readx.in.mincnt != 0xFFFF) {
821 req_grow_data(req, 1 + io->readx.out.nread);
822 SCVAL(req->out.data, 0, 0); /* padding */
823 } else {
824 req_grow_data(req, io->readx.out.nread);
827 /* construct reply */
828 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
829 SSVAL(req->out.vwv, VWV(1), 0);
830 SSVAL(req->out.vwv, VWV(2), io->readx.out.remaining);
831 SSVAL(req->out.vwv, VWV(3), io->readx.out.compaction_mode);
832 SMBSRV_VWV_RESERVED(4, 1);
833 SSVAL(req->out.vwv, VWV(5), io->readx.out.nread);
834 SSVAL(req->out.vwv, VWV(6), PTR_DIFF(io->readx.out.data, req->out.hdr));
835 SSVAL(req->out.vwv, VWV(7), (io->readx.out.nread>>16));
836 SMBSRV_VWV_RESERVED(8, 4);
838 if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) {
839 smbsrv_setup_error(req, req->ntvfs->async_states->status);
842 smbsrv_chain_reply(req);
845 /****************************************************************************
846 Reply to a read and X.
847 ****************************************************************************/
848 void smbsrv_reply_read_and_X(struct smbsrv_request *req)
850 union smb_read *io;
852 /* parse request */
853 if (req->in.wct != 12) {
854 SMBSRV_CHECK_WCT(req, 10);
857 SMBSRV_TALLOC_IO_PTR(io, union smb_read);
858 SMBSRV_SETUP_NTVFS_REQUEST(reply_read_and_X_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
860 io->readx.level = RAW_READ_READX;
861 io->readx.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(2));
862 io->readx.in.offset = IVAL(req->in.vwv, VWV(3));
863 io->readx.in.maxcnt = SVAL(req->in.vwv, VWV(5));
864 io->readx.in.mincnt = SVAL(req->in.vwv, VWV(6));
865 io->readx.in.remaining = SVAL(req->in.vwv, VWV(9));
866 if (req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) {
867 io->readx.in.read_for_execute = true;
868 } else {
869 io->readx.in.read_for_execute = false;
872 if (req->smb_conn->negotiate.client_caps & CAP_LARGE_READX) {
873 uint32_t high_part = IVAL(req->in.vwv, VWV(7));
874 if (high_part == 1) {
875 io->readx.in.maxcnt |= high_part << 16;
879 /* the 64 bit variant */
880 if (req->in.wct == 12) {
881 uint32_t offset_high = IVAL(req->in.vwv, VWV(10));
882 io->readx.in.offset |= (((uint64_t)offset_high) << 32);
885 /* setup the reply packet assuming the maximum possible read */
886 smbsrv_setup_reply(req, 12, 1 + io->readx.in.maxcnt);
888 /* tell the backend where to put the data. Notice the pad byte. */
889 if (io->readx.in.maxcnt != 0xFFFF &&
890 io->readx.in.mincnt != 0xFFFF) {
891 io->readx.out.data = req->out.data + 1;
892 } else {
893 io->readx.out.data = req->out.data;
896 SMBSRV_CHECK_FILE_HANDLE(io->readx.in.file.ntvfs);
897 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_read(req->ntvfs, io));
901 /****************************************************************************
902 Reply to a writebraw (core+ or LANMAN1.0 protocol).
903 ****************************************************************************/
904 void smbsrv_reply_writebraw(struct smbsrv_request *req)
906 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRuseSTD));
910 /****************************************************************************
911 Reply to a writeunlock (async reply)
912 ****************************************************************************/
913 static void reply_writeunlock_send(struct ntvfs_request *ntvfs)
915 struct smbsrv_request *req;
916 union smb_write *io;
918 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_write);
920 /* construct reply */
921 smbsrv_setup_reply(req, 1, 0);
923 SSVAL(req->out.vwv, VWV(0), io->writeunlock.out.nwritten);
925 smbsrv_send_reply(req);
928 /****************************************************************************
929 Reply to a writeunlock (core+).
930 ****************************************************************************/
931 void smbsrv_reply_writeunlock(struct smbsrv_request *req)
933 union smb_write *io;
935 SMBSRV_CHECK_WCT(req, 5);
936 SMBSRV_TALLOC_IO_PTR(io, union smb_write);
937 SMBSRV_SETUP_NTVFS_REQUEST(reply_writeunlock_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
939 io->writeunlock.level = RAW_WRITE_WRITEUNLOCK;
940 io->writeunlock.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
941 io->writeunlock.in.count = SVAL(req->in.vwv, VWV(1));
942 io->writeunlock.in.offset = IVAL(req->in.vwv, VWV(2));
943 io->writeunlock.in.remaining = SVAL(req->in.vwv, VWV(4));
944 io->writeunlock.in.data = req->in.data + 3;
946 /* make sure they gave us the data they promised */
947 if (io->writeunlock.in.count+3 > req->in.data_size) {
948 smbsrv_send_error(req, NT_STATUS_FOOBAR);
949 return;
952 /* make sure the data block is big enough */
953 if (SVAL(req->in.data, 1) < io->writeunlock.in.count) {
954 smbsrv_send_error(req, NT_STATUS_FOOBAR);
955 return;
958 SMBSRV_CHECK_FILE_HANDLE(io->writeunlock.in.file.ntvfs);
959 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
964 /****************************************************************************
965 Reply to a write (async reply)
966 ****************************************************************************/
967 static void reply_write_send(struct ntvfs_request *ntvfs)
969 struct smbsrv_request *req;
970 union smb_write *io;
972 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_write);
974 /* construct reply */
975 smbsrv_setup_reply(req, 1, 0);
977 SSVAL(req->out.vwv, VWV(0), io->write.out.nwritten);
979 smbsrv_send_reply(req);
982 /****************************************************************************
983 Reply to a write
984 ****************************************************************************/
985 void smbsrv_reply_write(struct smbsrv_request *req)
987 union smb_write *io;
989 SMBSRV_CHECK_WCT(req, 5);
990 SMBSRV_TALLOC_IO_PTR(io, union smb_write);
991 SMBSRV_SETUP_NTVFS_REQUEST(reply_write_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
993 io->write.level = RAW_WRITE_WRITE;
994 io->write.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
995 io->write.in.count = SVAL(req->in.vwv, VWV(1));
996 io->write.in.offset = IVAL(req->in.vwv, VWV(2));
997 io->write.in.remaining = SVAL(req->in.vwv, VWV(4));
998 io->write.in.data = req->in.data + 3;
1000 /* make sure they gave us the data they promised */
1001 if (req_data_oob(&req->in.bufinfo, io->write.in.data, io->write.in.count)) {
1002 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1003 return;
1006 /* make sure the data block is big enough */
1007 if (SVAL(req->in.data, 1) < io->write.in.count) {
1008 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1009 return;
1012 SMBSRV_CHECK_FILE_HANDLE(io->write.in.file.ntvfs);
1013 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
1017 /****************************************************************************
1018 Reply to a write and X (async reply)
1019 ****************************************************************************/
1020 static void reply_write_and_X_send(struct ntvfs_request *ntvfs)
1022 struct smbsrv_request *req;
1023 union smb_write *io;
1025 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_write);
1027 /* construct reply */
1028 smbsrv_setup_reply(req, 6, 0);
1030 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1031 SSVAL(req->out.vwv, VWV(1), 0);
1032 SSVAL(req->out.vwv, VWV(2), io->writex.out.nwritten & 0xFFFF);
1033 SSVAL(req->out.vwv, VWV(3), io->writex.out.remaining);
1034 SSVAL(req->out.vwv, VWV(4), io->writex.out.nwritten >> 16);
1035 SMBSRV_VWV_RESERVED(5, 1);
1037 smbsrv_chain_reply(req);
1040 /****************************************************************************
1041 Reply to a write and X.
1042 ****************************************************************************/
1043 void smbsrv_reply_write_and_X(struct smbsrv_request *req)
1045 union smb_write *io;
1047 if (req->in.wct != 14) {
1048 SMBSRV_CHECK_WCT(req, 12);
1051 SMBSRV_TALLOC_IO_PTR(io, union smb_write);
1052 SMBSRV_SETUP_NTVFS_REQUEST(reply_write_and_X_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1054 io->writex.level = RAW_WRITE_WRITEX;
1055 io->writex.in.file.ntvfs= smbsrv_pull_fnum(req, req->in.vwv, VWV(2));
1056 io->writex.in.offset = IVAL(req->in.vwv, VWV(3));
1057 io->writex.in.wmode = SVAL(req->in.vwv, VWV(7));
1058 io->writex.in.remaining = SVAL(req->in.vwv, VWV(8));
1059 io->writex.in.count = SVAL(req->in.vwv, VWV(10));
1060 io->writex.in.data = req->in.hdr + SVAL(req->in.vwv, VWV(11));
1062 if (req->in.wct == 14) {
1063 uint32_t offset_high = IVAL(req->in.vwv, VWV(12));
1064 uint16_t count_high = SVAL(req->in.vwv, VWV(9));
1065 io->writex.in.offset |= (((uint64_t)offset_high) << 32);
1066 io->writex.in.count |= ((uint32_t)count_high) << 16;
1069 /* make sure the data is in bounds */
1070 if (req_data_oob(&req->in.bufinfo, io->writex.in.data, io->writex.in.count)) {
1071 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
1072 return;
1075 SMBSRV_CHECK_FILE_HANDLE(io->writex.in.file.ntvfs);
1076 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
1080 /****************************************************************************
1081 Reply to a lseek (async reply)
1082 ****************************************************************************/
1083 static void reply_lseek_send(struct ntvfs_request *ntvfs)
1085 struct smbsrv_request *req;
1086 union smb_seek *io;
1088 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_seek);
1090 /* construct reply */
1091 smbsrv_setup_reply(req, 2, 0);
1093 SIVALS(req->out.vwv, VWV(0), io->lseek.out.offset);
1095 smbsrv_send_reply(req);
1098 /****************************************************************************
1099 Reply to a lseek.
1100 ****************************************************************************/
1101 void smbsrv_reply_lseek(struct smbsrv_request *req)
1103 union smb_seek *io;
1105 SMBSRV_CHECK_WCT(req, 4);
1106 SMBSRV_TALLOC_IO_PTR(io, union smb_seek);
1107 SMBSRV_SETUP_NTVFS_REQUEST(reply_lseek_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1109 io->lseek.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1110 io->lseek.in.mode = SVAL(req->in.vwv, VWV(1));
1111 io->lseek.in.offset = IVALS(req->in.vwv, VWV(2));
1113 SMBSRV_CHECK_FILE_HANDLE(io->lseek.in.file.ntvfs);
1114 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_seek(req->ntvfs, io));
1117 /****************************************************************************
1118 Reply to a flush.
1119 ****************************************************************************/
1120 void smbsrv_reply_flush(struct smbsrv_request *req)
1122 union smb_flush *io;
1123 uint16_t fnum;
1125 /* parse request */
1126 SMBSRV_CHECK_WCT(req, 1);
1127 SMBSRV_TALLOC_IO_PTR(io, union smb_flush);
1128 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1130 fnum = SVAL(req->in.vwv, VWV(0));
1131 if (fnum == 0xFFFF) {
1132 io->flush_all.level = RAW_FLUSH_ALL;
1133 } else {
1134 io->flush.level = RAW_FLUSH_FLUSH;
1135 io->flush.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1136 SMBSRV_CHECK_FILE_HANDLE(io->flush.in.file.ntvfs);
1139 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_flush(req->ntvfs, io));
1142 /****************************************************************************
1143 Reply to a close
1145 Note that this has to deal with closing a directory opened by NT SMB's.
1146 ****************************************************************************/
1147 void smbsrv_reply_close(struct smbsrv_request *req)
1149 union smb_close *io;
1151 /* parse request */
1152 SMBSRV_CHECK_WCT(req, 3);
1153 SMBSRV_TALLOC_IO_PTR(io, union smb_close);
1154 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1156 io->close.level = RAW_CLOSE_CLOSE;
1157 io->close.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1158 io->close.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(1));
1160 SMBSRV_CHECK_FILE_HANDLE(io->close.in.file.ntvfs);
1161 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_close(req->ntvfs, io));
1165 /****************************************************************************
1166 Reply to a writeclose (async reply)
1167 ****************************************************************************/
1168 static void reply_writeclose_send(struct ntvfs_request *ntvfs)
1170 struct smbsrv_request *req;
1171 union smb_write *io;
1173 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_write);
1175 /* construct reply */
1176 smbsrv_setup_reply(req, 1, 0);
1178 SSVAL(req->out.vwv, VWV(0), io->write.out.nwritten);
1180 smbsrv_send_reply(req);
1183 /****************************************************************************
1184 Reply to a writeclose (Core+ protocol).
1185 ****************************************************************************/
1186 void smbsrv_reply_writeclose(struct smbsrv_request *req)
1188 union smb_write *io;
1190 /* this one is pretty weird - the wct can be 6 or 12 */
1191 if (req->in.wct != 12) {
1192 SMBSRV_CHECK_WCT(req, 6);
1195 SMBSRV_TALLOC_IO_PTR(io, union smb_write);
1196 SMBSRV_SETUP_NTVFS_REQUEST(reply_writeclose_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1198 io->writeclose.level = RAW_WRITE_WRITECLOSE;
1199 io->writeclose.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1200 io->writeclose.in.count = SVAL(req->in.vwv, VWV(1));
1201 io->writeclose.in.offset = IVAL(req->in.vwv, VWV(2));
1202 io->writeclose.in.mtime = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(4));
1203 io->writeclose.in.data = req->in.data + 1;
1205 /* make sure they gave us the data they promised */
1206 if (req_data_oob(&req->in.bufinfo, io->writeclose.in.data, io->writeclose.in.count)) {
1207 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1208 return;
1211 SMBSRV_CHECK_FILE_HANDLE(io->writeclose.in.file.ntvfs);
1212 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
1215 /****************************************************************************
1216 Reply to a lock.
1217 ****************************************************************************/
1218 void smbsrv_reply_lock(struct smbsrv_request *req)
1220 union smb_lock *lck;
1222 /* parse request */
1223 SMBSRV_CHECK_WCT(req, 5);
1224 SMBSRV_TALLOC_IO_PTR(lck, union smb_lock);
1225 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1227 lck->lock.level = RAW_LOCK_LOCK;
1228 lck->lock.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1229 lck->lock.in.count = IVAL(req->in.vwv, VWV(1));
1230 lck->lock.in.offset = IVAL(req->in.vwv, VWV(3));
1232 SMBSRV_CHECK_FILE_HANDLE(lck->lock.in.file.ntvfs);
1233 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_lock(req->ntvfs, lck));
1237 /****************************************************************************
1238 Reply to a unlock.
1239 ****************************************************************************/
1240 void smbsrv_reply_unlock(struct smbsrv_request *req)
1242 union smb_lock *lck;
1244 /* parse request */
1245 SMBSRV_CHECK_WCT(req, 5);
1246 SMBSRV_TALLOC_IO_PTR(lck, union smb_lock);
1247 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1249 lck->unlock.level = RAW_LOCK_UNLOCK;
1250 lck->unlock.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1251 lck->unlock.in.count = IVAL(req->in.vwv, VWV(1));
1252 lck->unlock.in.offset = IVAL(req->in.vwv, VWV(3));
1254 SMBSRV_CHECK_FILE_HANDLE(lck->unlock.in.file.ntvfs);
1255 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_lock(req->ntvfs, lck));
1259 /****************************************************************************
1260 Reply to a tdis.
1261 ****************************************************************************/
1262 void smbsrv_reply_tdis(struct smbsrv_request *req)
1264 struct smbsrv_handle *h, *nh;
1266 SMBSRV_CHECK_WCT(req, 0);
1269 * TODO: cancel all pending requests on this tcon
1273 * close all handles on this tcon
1275 for (h=req->tcon->handles.list; h; h=nh) {
1276 nh = h->next;
1277 talloc_free(h);
1280 /* finally destroy the tcon */
1281 talloc_free(req->tcon);
1282 req->tcon = NULL;
1284 smbsrv_setup_reply(req, 0, 0);
1285 smbsrv_send_reply(req);
1289 /****************************************************************************
1290 Reply to a echo. This is one of the few calls that is handled directly (the
1291 backends don't see it at all)
1292 ****************************************************************************/
1293 void smbsrv_reply_echo(struct smbsrv_request *req)
1295 uint16_t count;
1296 int i;
1298 SMBSRV_CHECK_WCT(req, 1);
1300 count = SVAL(req->in.vwv, VWV(0));
1302 smbsrv_setup_reply(req, 1, req->in.data_size);
1304 memcpy(req->out.data, req->in.data, req->in.data_size);
1306 for (i=1; i <= count;i++) {
1307 struct smbsrv_request *this_req;
1309 if (i != count) {
1310 this_req = smbsrv_setup_secondary_request(req);
1311 } else {
1312 this_req = req;
1315 SSVAL(this_req->out.vwv, VWV(0), i);
1316 smbsrv_send_reply(this_req);
1322 /****************************************************************************
1323 Reply to a printopen (async reply)
1324 ****************************************************************************/
1325 static void reply_printopen_send(struct ntvfs_request *ntvfs)
1327 struct smbsrv_request *req;
1328 union smb_open *oi;
1330 SMBSRV_CHECK_ASYNC_STATUS(oi, union smb_open);
1332 /* construct reply */
1333 smbsrv_setup_reply(req, 1, 0);
1335 smbsrv_push_fnum(req->out.vwv, VWV(0), oi->openold.out.file.ntvfs);
1337 smbsrv_send_reply(req);
1340 /****************************************************************************
1341 Reply to a printopen.
1342 ****************************************************************************/
1343 void smbsrv_reply_printopen(struct smbsrv_request *req)
1345 union smb_open *oi;
1347 /* parse request */
1348 SMBSRV_CHECK_WCT(req, 2);
1349 SMBSRV_TALLOC_IO_PTR(oi, union smb_open);
1350 SMBSRV_SETUP_NTVFS_REQUEST(reply_printopen_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1352 oi->splopen.level = RAW_OPEN_SPLOPEN;
1353 oi->splopen.in.setup_length = SVAL(req->in.vwv, VWV(0));
1354 oi->splopen.in.mode = SVAL(req->in.vwv, VWV(1));
1356 req_pull_ascii4(&req->in.bufinfo, &oi->splopen.in.ident, req->in.data, STR_TERMINATE);
1358 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, oi));
1361 /****************************************************************************
1362 Reply to a printclose.
1363 ****************************************************************************/
1364 void smbsrv_reply_printclose(struct smbsrv_request *req)
1366 union smb_close *io;
1368 /* parse request */
1369 SMBSRV_CHECK_WCT(req, 3);
1370 SMBSRV_TALLOC_IO_PTR(io, union smb_close);
1371 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1373 io->splclose.level = RAW_CLOSE_SPLCLOSE;
1374 io->splclose.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1376 SMBSRV_CHECK_FILE_HANDLE(io->splclose.in.file.ntvfs);
1377 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_close(req->ntvfs, io));
1380 /****************************************************************************
1381 Reply to a printqueue.
1382 ****************************************************************************/
1383 static void reply_printqueue_send(struct ntvfs_request *ntvfs)
1385 struct smbsrv_request *req;
1386 union smb_lpq *lpq;
1387 int i, maxcount;
1388 const unsigned int el_size = 28;
1390 SMBSRV_CHECK_ASYNC_STATUS(lpq,union smb_lpq);
1392 /* construct reply */
1393 smbsrv_setup_reply(req, 2, 0);
1395 /* truncate the returned list to fit in the negotiated buffer size */
1396 maxcount = (req_max_data(req) - 3) / el_size;
1397 if (maxcount < lpq->retq.out.count) {
1398 lpq->retq.out.count = maxcount;
1401 /* setup enough space in the reply */
1402 req_grow_data(req, 3 + el_size*lpq->retq.out.count);
1404 /* and fill it in */
1405 SSVAL(req->out.vwv, VWV(0), lpq->retq.out.count);
1406 SSVAL(req->out.vwv, VWV(1), lpq->retq.out.restart_idx);
1408 SCVAL(req->out.data, 0, SMB_DATA_BLOCK);
1409 SSVAL(req->out.data, 1, el_size*lpq->retq.out.count);
1411 req->out.ptr = req->out.data + 3;
1413 for (i=0;i<lpq->retq.out.count;i++) {
1414 srv_push_dos_date2(req->smb_conn, req->out.ptr, 0 , lpq->retq.out.queue[i].time);
1415 SCVAL(req->out.ptr, 4, lpq->retq.out.queue[i].status);
1416 SSVAL(req->out.ptr, 5, lpq->retq.out.queue[i].job);
1417 SIVAL(req->out.ptr, 7, lpq->retq.out.queue[i].size);
1418 SCVAL(req->out.ptr, 11, 0); /* reserved */
1419 req_push_str(req, req->out.ptr+12, lpq->retq.out.queue[i].user, 16, STR_ASCII);
1420 req->out.ptr += el_size;
1423 smbsrv_send_reply(req);
1426 /****************************************************************************
1427 Reply to a printqueue.
1428 ****************************************************************************/
1429 void smbsrv_reply_printqueue(struct smbsrv_request *req)
1431 union smb_lpq *lpq;
1433 /* parse request */
1434 SMBSRV_CHECK_WCT(req, 2);
1435 SMBSRV_TALLOC_IO_PTR(lpq, union smb_lpq);
1436 SMBSRV_SETUP_NTVFS_REQUEST(reply_printqueue_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1438 lpq->retq.level = RAW_LPQ_RETQ;
1439 lpq->retq.in.maxcount = SVAL(req->in.vwv, VWV(0));
1440 lpq->retq.in.startidx = SVAL(req->in.vwv, VWV(1));
1442 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_lpq(req->ntvfs, lpq));
1446 /****************************************************************************
1447 Reply to a printwrite.
1448 ****************************************************************************/
1449 void smbsrv_reply_printwrite(struct smbsrv_request *req)
1451 union smb_write *io;
1453 /* parse request */
1454 SMBSRV_CHECK_WCT(req, 1);
1455 SMBSRV_TALLOC_IO_PTR(io, union smb_write);
1456 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1458 if (req->in.data_size < 3) {
1459 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1460 return;
1463 io->splwrite.level = RAW_WRITE_SPLWRITE;
1464 io->splwrite.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1465 io->splwrite.in.count = SVAL(req->in.data, 1);
1466 io->splwrite.in.data = req->in.data + 3;
1468 /* make sure they gave us the data they promised */
1469 if (req_data_oob(&req->in.bufinfo, io->splwrite.in.data, io->splwrite.in.count)) {
1470 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1471 return;
1474 SMBSRV_CHECK_FILE_HANDLE(io->splwrite.in.file.ntvfs);
1475 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
1479 /****************************************************************************
1480 Reply to a mkdir.
1481 ****************************************************************************/
1482 void smbsrv_reply_mkdir(struct smbsrv_request *req)
1484 union smb_mkdir *io;
1486 /* parse the request */
1487 SMBSRV_CHECK_WCT(req, 0);
1488 SMBSRV_TALLOC_IO_PTR(io, union smb_mkdir);
1489 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1491 io->generic.level = RAW_MKDIR_MKDIR;
1492 req_pull_ascii4(&req->in.bufinfo, &io->mkdir.in.path, req->in.data, STR_TERMINATE);
1494 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_mkdir(req->ntvfs, io));
1498 /****************************************************************************
1499 Reply to a rmdir.
1500 ****************************************************************************/
1501 void smbsrv_reply_rmdir(struct smbsrv_request *req)
1503 struct smb_rmdir *io;
1505 /* parse the request */
1506 SMBSRV_CHECK_WCT(req, 0);
1507 SMBSRV_TALLOC_IO_PTR(io, struct smb_rmdir);
1508 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1510 req_pull_ascii4(&req->in.bufinfo, &io->in.path, req->in.data, STR_TERMINATE);
1512 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_rmdir(req->ntvfs, io));
1516 /****************************************************************************
1517 Reply to a mv.
1518 ****************************************************************************/
1519 void smbsrv_reply_mv(struct smbsrv_request *req)
1521 union smb_rename *io;
1522 uint8_t *p;
1524 /* parse the request */
1525 SMBSRV_CHECK_WCT(req, 1);
1526 SMBSRV_TALLOC_IO_PTR(io, union smb_rename);
1527 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1529 io->generic.level = RAW_RENAME_RENAME;
1530 io->rename.in.attrib = SVAL(req->in.vwv, VWV(0));
1532 p = req->in.data;
1533 p += req_pull_ascii4(&req->in.bufinfo, &io->rename.in.pattern1, p, STR_TERMINATE);
1534 p += req_pull_ascii4(&req->in.bufinfo, &io->rename.in.pattern2, p, STR_TERMINATE);
1536 if (!io->rename.in.pattern1 || !io->rename.in.pattern2) {
1537 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1538 return;
1541 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_rename(req->ntvfs, io));
1545 /****************************************************************************
1546 Reply to an NT rename.
1547 ****************************************************************************/
1548 void smbsrv_reply_ntrename(struct smbsrv_request *req)
1550 union smb_rename *io;
1551 uint8_t *p;
1553 /* parse the request */
1554 SMBSRV_CHECK_WCT(req, 4);
1555 SMBSRV_TALLOC_IO_PTR(io, union smb_rename);
1556 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1558 io->generic.level = RAW_RENAME_NTRENAME;
1559 io->ntrename.in.attrib = SVAL(req->in.vwv, VWV(0));
1560 io->ntrename.in.flags = SVAL(req->in.vwv, VWV(1));
1561 io->ntrename.in.cluster_size = IVAL(req->in.vwv, VWV(2));
1563 p = req->in.data;
1564 p += req_pull_ascii4(&req->in.bufinfo, &io->ntrename.in.old_name, p, STR_TERMINATE);
1565 p += req_pull_ascii4(&req->in.bufinfo, &io->ntrename.in.new_name, p, STR_TERMINATE);
1567 if (!io->ntrename.in.old_name || !io->ntrename.in.new_name) {
1568 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1569 return;
1572 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_rename(req->ntvfs, io));
1575 /****************************************************************************
1576 Reply to a file copy (async reply)
1577 ****************************************************************************/
1578 static void reply_copy_send(struct ntvfs_request *ntvfs)
1580 struct smbsrv_request *req;
1581 struct smb_copy *cp;
1583 SMBSRV_CHECK_ASYNC_STATUS(cp, struct smb_copy);
1585 /* build the reply */
1586 smbsrv_setup_reply(req, 1, 0);
1588 SSVAL(req->out.vwv, VWV(0), cp->out.count);
1590 smbsrv_send_reply(req);
1593 /****************************************************************************
1594 Reply to a file copy.
1595 ****************************************************************************/
1596 void smbsrv_reply_copy(struct smbsrv_request *req)
1598 struct smb_copy *cp;
1599 uint8_t *p;
1601 /* parse request */
1602 SMBSRV_CHECK_WCT(req, 3);
1603 SMBSRV_TALLOC_IO_PTR(cp, struct smb_copy);
1604 SMBSRV_SETUP_NTVFS_REQUEST(reply_copy_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1606 cp->in.tid2 = SVAL(req->in.vwv, VWV(0));
1607 cp->in.ofun = SVAL(req->in.vwv, VWV(1));
1608 cp->in.flags = SVAL(req->in.vwv, VWV(2));
1610 p = req->in.data;
1611 p += req_pull_ascii4(&req->in.bufinfo, &cp->in.path1, p, STR_TERMINATE);
1612 p += req_pull_ascii4(&req->in.bufinfo, &cp->in.path2, p, STR_TERMINATE);
1614 if (!cp->in.path1 || !cp->in.path2) {
1615 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1616 return;
1619 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_copy(req->ntvfs, cp));
1622 /****************************************************************************
1623 Reply to a lockingX request (async send)
1624 ****************************************************************************/
1625 static void reply_lockingX_send(struct ntvfs_request *ntvfs)
1627 struct smbsrv_request *req;
1628 union smb_lock *lck;
1630 SMBSRV_CHECK_ASYNC_STATUS(lck, union smb_lock);
1632 /* if it was an oplock break ack then we only send a reply if
1633 there was an error */
1634 if (lck->lockx.in.ulock_cnt + lck->lockx.in.lock_cnt == 0) {
1635 talloc_free(req);
1636 return;
1639 /* construct reply */
1640 smbsrv_setup_reply(req, 2, 0);
1642 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1643 SSVAL(req->out.vwv, VWV(1), 0);
1645 smbsrv_chain_reply(req);
1649 /****************************************************************************
1650 Reply to a lockingX request.
1651 ****************************************************************************/
1652 void smbsrv_reply_lockingX(struct smbsrv_request *req)
1654 union smb_lock *lck;
1655 unsigned int total_locks, i;
1656 unsigned int lck_size;
1657 uint8_t *p;
1659 /* parse request */
1660 SMBSRV_CHECK_WCT(req, 8);
1661 SMBSRV_TALLOC_IO_PTR(lck, union smb_lock);
1662 SMBSRV_SETUP_NTVFS_REQUEST(reply_lockingX_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1664 lck->lockx.level = RAW_LOCK_LOCKX;
1665 lck->lockx.in.file.ntvfs= smbsrv_pull_fnum(req, req->in.vwv, VWV(2));
1666 lck->lockx.in.mode = SVAL(req->in.vwv, VWV(3));
1667 lck->lockx.in.timeout = IVAL(req->in.vwv, VWV(4));
1668 lck->lockx.in.ulock_cnt = SVAL(req->in.vwv, VWV(6));
1669 lck->lockx.in.lock_cnt = SVAL(req->in.vwv, VWV(7));
1671 total_locks = lck->lockx.in.ulock_cnt + lck->lockx.in.lock_cnt;
1673 /* there are two variants, one with 64 bit offsets and counts */
1674 if (lck->lockx.in.mode & LOCKING_ANDX_LARGE_FILES) {
1675 lck_size = 20;
1676 } else {
1677 lck_size = 10;
1680 /* make sure we got the promised data */
1681 if (req_data_oob(&req->in.bufinfo, req->in.data, total_locks * lck_size)) {
1682 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1683 return;
1686 /* allocate the locks array */
1687 if (total_locks) {
1688 lck->lockx.in.locks = talloc_array(req, struct smb_lock_entry,
1689 total_locks);
1690 if (lck->lockx.in.locks == NULL) {
1691 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
1692 return;
1696 p = req->in.data;
1698 /* construct the locks array */
1699 for (i=0;i<total_locks;i++) {
1700 uint32_t ofs_high=0, count_high=0;
1702 lck->lockx.in.locks[i].pid = SVAL(p, 0);
1704 if (lck->lockx.in.mode & LOCKING_ANDX_LARGE_FILES) {
1705 ofs_high = IVAL(p, 4);
1706 lck->lockx.in.locks[i].offset = IVAL(p, 8);
1707 count_high = IVAL(p, 12);
1708 lck->lockx.in.locks[i].count = IVAL(p, 16);
1709 } else {
1710 lck->lockx.in.locks[i].offset = IVAL(p, 2);
1711 lck->lockx.in.locks[i].count = IVAL(p, 6);
1713 if (ofs_high != 0 || count_high != 0) {
1714 lck->lockx.in.locks[i].count |= ((uint64_t)count_high) << 32;
1715 lck->lockx.in.locks[i].offset |= ((uint64_t)ofs_high) << 32;
1717 p += lck_size;
1720 SMBSRV_CHECK_FILE_HANDLE(lck->lockx.in.file.ntvfs);
1721 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_lock(req->ntvfs, lck));
1724 /****************************************************************************
1725 Reply to a SMBreadbmpx (read block multiplex) request.
1726 ****************************************************************************/
1727 void smbsrv_reply_readbmpx(struct smbsrv_request *req)
1729 /* tell the client to not use a multiplexed read - its too broken to use */
1730 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRuseSTD));
1734 /****************************************************************************
1735 Reply to a SMBsetattrE.
1736 ****************************************************************************/
1737 void smbsrv_reply_setattrE(struct smbsrv_request *req)
1739 union smb_setfileinfo *info;
1741 /* parse request */
1742 SMBSRV_CHECK_WCT(req, 7);
1743 SMBSRV_TALLOC_IO_PTR(info, union smb_setfileinfo);
1744 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1746 info->setattre.level = RAW_SFILEINFO_SETATTRE;
1747 info->setattre.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1748 info->setattre.in.create_time = srv_pull_dos_date2(req->smb_conn, req->in.vwv + VWV(1));
1749 info->setattre.in.access_time = srv_pull_dos_date2(req->smb_conn, req->in.vwv + VWV(3));
1750 info->setattre.in.write_time = srv_pull_dos_date2(req->smb_conn, req->in.vwv + VWV(5));
1752 SMBSRV_CHECK_FILE_HANDLE(info->setattre.in.file.ntvfs);
1753 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_setfileinfo(req->ntvfs, info));
1757 /****************************************************************************
1758 Reply to a SMBwritebmpx (write block multiplex primary) request.
1759 ****************************************************************************/
1760 void smbsrv_reply_writebmpx(struct smbsrv_request *req)
1762 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRuseSTD));
1766 /****************************************************************************
1767 Reply to a SMBwritebs (write block multiplex secondary) request.
1768 ****************************************************************************/
1769 void smbsrv_reply_writebs(struct smbsrv_request *req)
1771 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRuseSTD));
1776 /****************************************************************************
1777 Reply to a SMBgetattrE (async reply)
1778 ****************************************************************************/
1779 static void reply_getattrE_send(struct ntvfs_request *ntvfs)
1781 struct smbsrv_request *req;
1782 union smb_fileinfo *info;
1784 SMBSRV_CHECK_ASYNC_STATUS(info, union smb_fileinfo);
1786 /* setup reply */
1787 smbsrv_setup_reply(req, 11, 0);
1789 srv_push_dos_date2(req->smb_conn, req->out.vwv, VWV(0), info->getattre.out.create_time);
1790 srv_push_dos_date2(req->smb_conn, req->out.vwv, VWV(2), info->getattre.out.access_time);
1791 srv_push_dos_date2(req->smb_conn, req->out.vwv, VWV(4), info->getattre.out.write_time);
1792 SIVAL(req->out.vwv, VWV(6), info->getattre.out.size);
1793 SIVAL(req->out.vwv, VWV(8), info->getattre.out.alloc_size);
1794 SSVAL(req->out.vwv, VWV(10), info->getattre.out.attrib);
1796 smbsrv_send_reply(req);
1799 /****************************************************************************
1800 Reply to a SMBgetattrE.
1801 ****************************************************************************/
1802 void smbsrv_reply_getattrE(struct smbsrv_request *req)
1804 union smb_fileinfo *info;
1806 /* parse request */
1807 SMBSRV_CHECK_WCT(req, 1);
1808 SMBSRV_TALLOC_IO_PTR(info, union smb_fileinfo);
1809 SMBSRV_SETUP_NTVFS_REQUEST(reply_getattrE_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1811 info->getattr.level = RAW_FILEINFO_GETATTRE;
1812 info->getattr.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1814 SMBSRV_CHECK_FILE_HANDLE(info->getattr.in.file.ntvfs);
1815 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_qfileinfo(req->ntvfs, info));
1818 void smbsrv_reply_sesssetup_send(struct smbsrv_request *req,
1819 union smb_sesssetup *io,
1820 NTSTATUS status)
1822 switch (io->old.level) {
1823 case RAW_SESSSETUP_OLD:
1824 if (!NT_STATUS_IS_OK(status)) {
1825 smbsrv_send_error(req, status);
1826 return;
1829 /* construct reply */
1830 smbsrv_setup_reply(req, 3, 0);
1832 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1833 SSVAL(req->out.vwv, VWV(1), 0);
1834 SSVAL(req->out.vwv, VWV(2), io->old.out.action);
1836 SSVAL(req->out.hdr, HDR_UID, io->old.out.vuid);
1838 smbsrv_chain_reply(req);
1839 return;
1841 case RAW_SESSSETUP_NT1:
1842 if (!NT_STATUS_IS_OK(status)) {
1843 smbsrv_send_error(req, status);
1844 return;
1847 /* construct reply */
1848 smbsrv_setup_reply(req, 3, 0);
1850 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1851 SSVAL(req->out.vwv, VWV(1), 0);
1852 SSVAL(req->out.vwv, VWV(2), io->nt1.out.action);
1854 SSVAL(req->out.hdr, HDR_UID, io->nt1.out.vuid);
1856 req_push_str(req, NULL, io->nt1.out.os, -1, STR_TERMINATE);
1857 req_push_str(req, NULL, io->nt1.out.lanman, -1, STR_TERMINATE);
1858 req_push_str(req, NULL, io->nt1.out.domain, -1, STR_TERMINATE);
1860 smbsrv_chain_reply(req);
1861 return;
1863 case RAW_SESSSETUP_SPNEGO:
1864 if (!NT_STATUS_IS_OK(status) &&
1865 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1866 smbsrv_send_error(req, status);
1867 return;
1870 /* construct reply */
1871 smbsrv_setup_reply(req, 4, io->spnego.out.secblob.length);
1873 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1874 smbsrv_setup_error(req, status);
1877 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1878 SSVAL(req->out.vwv, VWV(1), 0);
1879 SSVAL(req->out.vwv, VWV(2), io->spnego.out.action);
1880 SSVAL(req->out.vwv, VWV(3), io->spnego.out.secblob.length);
1882 SSVAL(req->out.hdr, HDR_UID, io->spnego.out.vuid);
1884 memcpy(req->out.data, io->spnego.out.secblob.data, io->spnego.out.secblob.length);
1885 req_push_str(req, NULL, io->spnego.out.os, -1, STR_TERMINATE);
1886 req_push_str(req, NULL, io->spnego.out.lanman, -1, STR_TERMINATE);
1887 req_push_str(req, NULL, io->spnego.out.workgroup, -1, STR_TERMINATE);
1889 smbsrv_chain_reply(req);
1890 return;
1892 case RAW_SESSSETUP_SMB2:
1893 break;
1896 smbsrv_send_error(req, NT_STATUS_INTERNAL_ERROR);
1899 /****************************************************************************
1900 reply to an old style session setup command
1901 ****************************************************************************/
1902 static void reply_sesssetup_old(struct smbsrv_request *req)
1904 uint8_t *p;
1905 uint16_t passlen;
1906 union smb_sesssetup *io;
1908 SMBSRV_TALLOC_IO_PTR(io, union smb_sesssetup);
1910 io->old.level = RAW_SESSSETUP_OLD;
1912 /* parse request */
1913 io->old.in.bufsize = SVAL(req->in.vwv, VWV(2));
1914 io->old.in.mpx_max = SVAL(req->in.vwv, VWV(3));
1915 io->old.in.vc_num = SVAL(req->in.vwv, VWV(4));
1916 io->old.in.sesskey = IVAL(req->in.vwv, VWV(5));
1917 passlen = SVAL(req->in.vwv, VWV(7));
1919 /* check the request isn't malformed */
1920 if (req_data_oob(&req->in.bufinfo, req->in.data, passlen)) {
1921 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1922 return;
1925 p = req->in.data;
1926 if (!req_pull_blob(&req->in.bufinfo, p, passlen, &io->old.in.password)) {
1927 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1928 return;
1930 p += passlen;
1932 p += req_pull_string(&req->in.bufinfo, &io->old.in.user, p, -1, STR_TERMINATE);
1933 p += req_pull_string(&req->in.bufinfo, &io->old.in.domain, p, -1, STR_TERMINATE);
1934 p += req_pull_string(&req->in.bufinfo, &io->old.in.os, p, -1, STR_TERMINATE);
1935 p += req_pull_string(&req->in.bufinfo, &io->old.in.lanman, p, -1, STR_TERMINATE);
1937 /* call the generic handler */
1938 smbsrv_sesssetup_backend(req, io);
1941 /****************************************************************************
1942 reply to an NT1 style session setup command
1943 ****************************************************************************/
1944 static void reply_sesssetup_nt1(struct smbsrv_request *req)
1946 uint8_t *p;
1947 uint16_t passlen1, passlen2;
1948 union smb_sesssetup *io;
1950 SMBSRV_TALLOC_IO_PTR(io, union smb_sesssetup);
1952 io->nt1.level = RAW_SESSSETUP_NT1;
1954 /* parse request */
1955 io->nt1.in.bufsize = SVAL(req->in.vwv, VWV(2));
1956 io->nt1.in.mpx_max = SVAL(req->in.vwv, VWV(3));
1957 io->nt1.in.vc_num = SVAL(req->in.vwv, VWV(4));
1958 io->nt1.in.sesskey = IVAL(req->in.vwv, VWV(5));
1959 passlen1 = SVAL(req->in.vwv, VWV(7));
1960 passlen2 = SVAL(req->in.vwv, VWV(8));
1961 io->nt1.in.capabilities = IVAL(req->in.vwv, VWV(11));
1963 /* check the request isn't malformed */
1964 if (req_data_oob(&req->in.bufinfo, req->in.data, passlen1) ||
1965 req_data_oob(&req->in.bufinfo, req->in.data + passlen1, passlen2)) {
1966 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1967 return;
1970 p = req->in.data;
1971 if (!req_pull_blob(&req->in.bufinfo, p, passlen1, &io->nt1.in.password1)) {
1972 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1973 return;
1975 p += passlen1;
1976 if (!req_pull_blob(&req->in.bufinfo, p, passlen2, &io->nt1.in.password2)) {
1977 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1978 return;
1980 p += passlen2;
1982 p += req_pull_string(&req->in.bufinfo, &io->nt1.in.user, p, -1, STR_TERMINATE);
1983 p += req_pull_string(&req->in.bufinfo, &io->nt1.in.domain, p, -1, STR_TERMINATE);
1984 p += req_pull_string(&req->in.bufinfo, &io->nt1.in.os, p, -1, STR_TERMINATE);
1985 p += req_pull_string(&req->in.bufinfo, &io->nt1.in.lanman, p, -1, STR_TERMINATE);
1987 /* call the generic handler */
1988 smbsrv_sesssetup_backend(req, io);
1992 /****************************************************************************
1993 reply to an SPNEGO style session setup command
1994 ****************************************************************************/
1995 static void reply_sesssetup_spnego(struct smbsrv_request *req)
1997 uint8_t *p;
1998 uint16_t blob_len;
1999 union smb_sesssetup *io;
2001 SMBSRV_TALLOC_IO_PTR(io, union smb_sesssetup);
2003 io->spnego.level = RAW_SESSSETUP_SPNEGO;
2005 /* parse request */
2006 io->spnego.in.bufsize = SVAL(req->in.vwv, VWV(2));
2007 io->spnego.in.mpx_max = SVAL(req->in.vwv, VWV(3));
2008 io->spnego.in.vc_num = SVAL(req->in.vwv, VWV(4));
2009 io->spnego.in.sesskey = IVAL(req->in.vwv, VWV(5));
2010 blob_len = SVAL(req->in.vwv, VWV(7));
2011 io->spnego.in.capabilities = IVAL(req->in.vwv, VWV(10));
2013 p = req->in.data;
2014 if (!req_pull_blob(&req->in.bufinfo, p, blob_len, &io->spnego.in.secblob)) {
2015 smbsrv_send_error(req, NT_STATUS_FOOBAR);
2016 return;
2018 p += blob_len;
2020 p += req_pull_string(&req->in.bufinfo, &io->spnego.in.os, p, -1, STR_TERMINATE);
2021 p += req_pull_string(&req->in.bufinfo, &io->spnego.in.lanman, p, -1, STR_TERMINATE);
2022 p += req_pull_string(&req->in.bufinfo, &io->spnego.in.workgroup, p, -1, STR_TERMINATE);
2024 /* call the generic handler */
2025 smbsrv_sesssetup_backend(req, io);
2029 /****************************************************************************
2030 reply to a session setup command
2031 ****************************************************************************/
2032 void smbsrv_reply_sesssetup(struct smbsrv_request *req)
2034 switch (req->in.wct) {
2035 case 10:
2036 /* a pre-NT1 call */
2037 reply_sesssetup_old(req);
2038 return;
2039 case 13:
2040 /* a NT1 call */
2041 reply_sesssetup_nt1(req);
2042 return;
2043 case 12:
2044 /* a SPNEGO call */
2045 reply_sesssetup_spnego(req);
2046 return;
2049 /* unsupported variant */
2050 smbsrv_send_error(req, NT_STATUS_FOOBAR);
2053 /****************************************************************************
2054 Reply to a exit. This closes all files open by a smbpid
2055 ****************************************************************************/
2056 void smbsrv_reply_exit(struct smbsrv_request *req)
2058 struct smbsrv_handle_session_item *i, *ni;
2059 struct smbsrv_handle *h;
2060 struct smbsrv_tcon *tcon;
2061 uint16_t smbpid;
2063 SMBSRV_CHECK_WCT(req, 0);
2065 smbpid = SVAL(req->in.hdr,HDR_PID);
2067 /* first destroy all handles, which have the same PID as the request */
2068 for (i=req->session->handles; i; i=ni) {
2069 ni = i->next;
2070 h = i->handle;
2071 if (h->smbpid != smbpid) continue;
2073 talloc_free(h);
2077 * then let the ntvfs backends proxy the call if they want to,
2078 * but we didn't check the return value of the backends,
2079 * as for the SMB client the call succeed
2081 for (tcon=req->smb_conn->smb_tcons.list;tcon;tcon=tcon->next) {
2082 req->tcon = tcon;
2083 SMBSRV_SETUP_NTVFS_REQUEST(NULL,0);
2084 ntvfs_exit(req->ntvfs);
2085 talloc_free(req->ntvfs);
2086 req->ntvfs = NULL;
2087 req->tcon = NULL;
2090 smbsrv_setup_reply(req, 0, 0);
2091 smbsrv_send_reply(req);
2094 /****************************************************************************
2095 Reply to a SMBulogoffX.
2096 ****************************************************************************/
2097 void smbsrv_reply_ulogoffX(struct smbsrv_request *req)
2099 struct smbsrv_handle_session_item *i, *ni;
2100 struct smbsrv_handle *h;
2101 struct smbsrv_tcon *tcon;
2103 SMBSRV_CHECK_WCT(req, 2);
2106 * TODO: cancel all pending requests
2110 /* destroy all handles */
2111 for (i=req->session->handles; i; i=ni) {
2112 ni = i->next;
2113 h = i->handle;
2114 talloc_free(h);
2118 * then let the ntvfs backends proxy the call if they want to,
2119 * but we didn't check the return value of the backends,
2120 * as for the SMB client the call succeed
2122 for (tcon=req->smb_conn->smb_tcons.list;tcon;tcon=tcon->next) {
2123 req->tcon = tcon;
2124 SMBSRV_SETUP_NTVFS_REQUEST(NULL,0);
2125 ntvfs_logoff(req->ntvfs);
2126 talloc_free(req->ntvfs);
2127 req->ntvfs = NULL;
2128 req->tcon = NULL;
2131 talloc_free(req->session);
2132 req->session = NULL; /* it is now invalid, don't use on
2133 any chained packets */
2135 smbsrv_setup_reply(req, 2, 0);
2137 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
2138 SSVAL(req->out.vwv, VWV(1), 0);
2140 smbsrv_chain_reply(req);
2143 /****************************************************************************
2144 Reply to an SMBfindclose request
2145 ****************************************************************************/
2146 void smbsrv_reply_findclose(struct smbsrv_request *req)
2148 union smb_search_close *io;
2150 /* parse request */
2151 SMBSRV_CHECK_WCT(req, 1);
2152 SMBSRV_TALLOC_IO_PTR(io, union smb_search_close);
2153 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
2155 io->findclose.level = RAW_FINDCLOSE_FINDCLOSE;
2156 io->findclose.in.handle = SVAL(req->in.vwv, VWV(0));
2158 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_search_close(req->ntvfs, io));
2161 /****************************************************************************
2162 Reply to an SMBfindnclose request
2163 ****************************************************************************/
2164 void smbsrv_reply_findnclose(struct smbsrv_request *req)
2166 smbsrv_send_error(req, NT_STATUS_FOOBAR);
2170 /****************************************************************************
2171 Reply to an SMBntcreateX request (async send)
2172 ****************************************************************************/
2173 static void reply_ntcreate_and_X_send(struct ntvfs_request *ntvfs)
2175 struct smbsrv_request *req;
2176 union smb_open *io;
2178 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_open);
2180 /* construct reply */
2181 smbsrv_setup_reply(req, 34, 0);
2183 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
2184 SSVAL(req->out.vwv, VWV(1), 0);
2185 SCVAL(req->out.vwv, VWV(2), io->ntcreatex.out.oplock_level);
2187 /* the rest of the parameters are not aligned! */
2188 smbsrv_push_fnum(req->out.vwv, 5, io->ntcreatex.out.file.ntvfs);
2189 SIVAL(req->out.vwv, 7, io->ntcreatex.out.create_action);
2190 push_nttime(req->out.vwv, 11, io->ntcreatex.out.create_time);
2191 push_nttime(req->out.vwv, 19, io->ntcreatex.out.access_time);
2192 push_nttime(req->out.vwv, 27, io->ntcreatex.out.write_time);
2193 push_nttime(req->out.vwv, 35, io->ntcreatex.out.change_time);
2194 SIVAL(req->out.vwv, 43, io->ntcreatex.out.attrib);
2195 SBVAL(req->out.vwv, 47, io->ntcreatex.out.alloc_size);
2196 SBVAL(req->out.vwv, 55, io->ntcreatex.out.size);
2197 SSVAL(req->out.vwv, 63, io->ntcreatex.out.file_type);
2198 SSVAL(req->out.vwv, 65, io->ntcreatex.out.ipc_state);
2199 SCVAL(req->out.vwv, 67, io->ntcreatex.out.is_directory);
2201 req->chained_fnum = SVAL(req->out.vwv, 5);
2203 smbsrv_chain_reply(req);
2206 /****************************************************************************
2207 Reply to an SMBntcreateX request
2208 ****************************************************************************/
2209 void smbsrv_reply_ntcreate_and_X(struct smbsrv_request *req)
2211 union smb_open *io;
2212 uint16_t fname_len;
2214 /* parse the request */
2215 SMBSRV_CHECK_WCT(req, 24);
2216 SMBSRV_TALLOC_IO_PTR(io, union smb_open);
2217 SMBSRV_SETUP_NTVFS_REQUEST(reply_ntcreate_and_X_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
2219 io->ntcreatex.level = RAW_OPEN_NTCREATEX;
2221 /* notice that the word parameters are not word aligned, so we don't use VWV() */
2222 fname_len = SVAL(req->in.vwv, 5);
2223 io->ntcreatex.in.flags = IVAL(req->in.vwv, 7);
2224 io->ntcreatex.in.root_fid.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, 11);
2225 io->ntcreatex.in.access_mask = IVAL(req->in.vwv, 15);
2226 io->ntcreatex.in.alloc_size = BVAL(req->in.vwv, 19);
2227 io->ntcreatex.in.file_attr = IVAL(req->in.vwv, 27);
2228 io->ntcreatex.in.share_access = IVAL(req->in.vwv, 31);
2229 io->ntcreatex.in.open_disposition = IVAL(req->in.vwv, 35);
2230 io->ntcreatex.in.create_options = IVAL(req->in.vwv, 39);
2231 io->ntcreatex.in.impersonation = IVAL(req->in.vwv, 43);
2232 io->ntcreatex.in.security_flags = CVAL(req->in.vwv, 47);
2233 io->ntcreatex.in.ea_list = NULL;
2234 io->ntcreatex.in.sec_desc = NULL;
2235 io->ntcreatex.in.query_maximal_access = false;
2236 io->ntcreatex.in.private_flags = 0;
2238 /* we need a neater way to handle this alignment */
2239 if ((req->flags2 & FLAGS2_UNICODE_STRINGS) &&
2240 ucs2_align(req->in.buffer, req->in.data, STR_TERMINATE|STR_UNICODE)) {
2241 fname_len++;
2244 req_pull_string(&req->in.bufinfo, &io->ntcreatex.in.fname, req->in.data, fname_len, STR_TERMINATE);
2245 if (!io->ntcreatex.in.fname) {
2246 smbsrv_send_error(req, NT_STATUS_FOOBAR);
2247 return;
2250 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, io));
2254 /****************************************************************************
2255 Reply to an SMBntcancel request
2256 ****************************************************************************/
2257 void smbsrv_reply_ntcancel(struct smbsrv_request *req)
2259 struct smbsrv_request *r;
2260 uint16_t tid = SVAL(req->in.hdr,HDR_TID);
2261 uint16_t uid = SVAL(req->in.hdr,HDR_UID);
2262 uint16_t mid = SVAL(req->in.hdr,HDR_MID);
2263 uint16_t pid = SVAL(req->in.hdr,HDR_PID);
2265 for (r = req->smb_conn->requests; r; r = r->next) {
2266 if (tid != SVAL(r->in.hdr,HDR_TID)) continue;
2267 if (uid != SVAL(r->in.hdr,HDR_UID)) continue;
2268 if (mid != SVAL(r->in.hdr,HDR_MID)) continue;
2269 if (pid != SVAL(r->in.hdr,HDR_PID)) continue;
2271 SMBSRV_CHECK(ntvfs_cancel(r->ntvfs));
2273 /* NOTE: this request does not generate a reply */
2274 talloc_free(req);
2275 return;
2278 /* TODO: workout the correct error code,
2279 * until we know how the smb signing works
2280 * for ntcancel replies, don't send an error
2282 /*smbsrv_send_error(req, NT_STATUS_FOOBAR);*/
2283 talloc_free(req);
2287 parse the called/calling names from session request
2289 static NTSTATUS parse_session_request(struct smbsrv_request *req)
2291 DATA_BLOB blob;
2292 NTSTATUS status;
2294 blob.data = req->in.buffer + 4;
2295 blob.length = ascii_len_n((const char *)blob.data, req->in.size - PTR_DIFF(blob.data, req->in.buffer));
2296 if (blob.length == 0) return NT_STATUS_BAD_NETWORK_NAME;
2298 req->smb_conn->negotiate.called_name = talloc(req->smb_conn, struct nbt_name);
2299 req->smb_conn->negotiate.calling_name = talloc(req->smb_conn, struct nbt_name);
2300 if (req->smb_conn->negotiate.called_name == NULL ||
2301 req->smb_conn->negotiate.calling_name == NULL) {
2302 return NT_STATUS_NO_MEMORY;
2305 status = nbt_name_from_blob(req->smb_conn, &blob,
2306 req->smb_conn->negotiate.called_name);
2307 NT_STATUS_NOT_OK_RETURN(status);
2309 blob.data += blob.length;
2310 blob.length = ascii_len_n((const char *)blob.data, req->in.size - PTR_DIFF(blob.data, req->in.buffer));
2311 if (blob.length == 0) return NT_STATUS_BAD_NETWORK_NAME;
2313 status = nbt_name_from_blob(req->smb_conn, &blob,
2314 req->smb_conn->negotiate.calling_name);
2315 NT_STATUS_NOT_OK_RETURN(status);
2317 req->smb_conn->negotiate.done_nbt_session = true;
2319 return NT_STATUS_OK;
2324 /****************************************************************************
2325 Reply to a special message - a SMB packet with non zero NBT message type
2326 ****************************************************************************/
2327 void smbsrv_reply_special(struct smbsrv_request *req)
2329 uint8_t msg_type;
2330 uint8_t *buf = talloc_zero_array(req, uint8_t, 4);
2332 msg_type = CVAL(req->in.buffer,0);
2334 SIVAL(buf, 0, 0);
2336 switch (msg_type) {
2337 case NBSSrequest: /* session request */
2338 if (req->smb_conn->negotiate.done_nbt_session) {
2339 DEBUG(0,("Warning: ignoring secondary session request\n"));
2340 return;
2343 SCVAL(buf,0,0x82);
2344 SCVAL(buf,3,0);
2346 /* we don't check the status - samba always accepts session
2347 requests for any name */
2348 parse_session_request(req);
2350 req->out.buffer = buf;
2351 req->out.size = 4;
2352 smbsrv_send_reply_nosign(req);
2353 return;
2355 case 0x89: /* session keepalive request
2356 (some old clients produce this?) */
2357 SCVAL(buf, 0, NBSSkeepalive);
2358 SCVAL(buf, 3, 0);
2359 req->out.buffer = buf;
2360 req->out.size = 4;
2361 smbsrv_send_reply_nosign(req);
2362 return;
2364 case NBSSkeepalive:
2365 /* session keepalive - swallow it */
2366 talloc_free(req);
2367 return;
2370 DEBUG(0,("Unexpected NBT session packet (%d)\n", msg_type));
2371 talloc_free(req);