librpc: Shorten dcerpc_binding_handle_call a bit
[Samba/vl.git] / source4 / smb_server / smb / reply.c
blob7ce5f5dbaa51f83bc0f6f15764409220573aa7ea
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;
851 uint16_t high_part = 0;
853 /* parse request */
854 if (req->in.wct != 12) {
855 SMBSRV_CHECK_WCT(req, 10);
858 SMBSRV_TALLOC_IO_PTR(io, union smb_read);
859 SMBSRV_SETUP_NTVFS_REQUEST(reply_read_and_X_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
861 io->readx.level = RAW_READ_READX;
862 io->readx.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(2));
863 io->readx.in.offset = IVAL(req->in.vwv, VWV(3));
864 io->readx.in.maxcnt = SVAL(req->in.vwv, VWV(5));
865 io->readx.in.mincnt = SVAL(req->in.vwv, VWV(6));
866 io->readx.in.remaining = SVAL(req->in.vwv, VWV(9));
867 if (req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) {
868 io->readx.in.read_for_execute = true;
869 } else {
870 io->readx.in.read_for_execute = false;
873 if (req->smb_conn->negotiate.protocol == PROTOCOL_NT1) {
874 high_part = SVAL(req->in.vwv, VWV(7));
876 if (high_part != UINT16_MAX) {
877 io->readx.in.maxcnt |= high_part << 16;
881 * Windows truncates the length to 0x10000
883 io->readx.in.maxcnt = MIN(io->readx.in.maxcnt, 0x10000);
885 /* the 64 bit variant */
886 if (req->in.wct == 12) {
887 uint32_t offset_high = IVAL(req->in.vwv, VWV(10));
888 io->readx.in.offset |= (((uint64_t)offset_high) << 32);
891 /* setup the reply packet assuming the maximum possible read */
892 smbsrv_setup_reply(req, 12, 1 + io->readx.in.maxcnt);
894 /* tell the backend where to put the data. Notice the pad byte. */
895 if (io->readx.in.maxcnt != 0xFFFF &&
896 io->readx.in.mincnt != 0xFFFF) {
897 io->readx.out.data = req->out.data + 1;
898 } else {
899 io->readx.out.data = req->out.data;
902 SMBSRV_CHECK_FILE_HANDLE(io->readx.in.file.ntvfs);
903 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_read(req->ntvfs, io));
907 /****************************************************************************
908 Reply to a writebraw (core+ or LANMAN1.0 protocol).
909 ****************************************************************************/
910 void smbsrv_reply_writebraw(struct smbsrv_request *req)
912 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRuseSTD));
916 /****************************************************************************
917 Reply to a writeunlock (async reply)
918 ****************************************************************************/
919 static void reply_writeunlock_send(struct ntvfs_request *ntvfs)
921 struct smbsrv_request *req;
922 union smb_write *io;
924 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_write);
926 /* construct reply */
927 smbsrv_setup_reply(req, 1, 0);
929 SSVAL(req->out.vwv, VWV(0), io->writeunlock.out.nwritten);
931 smbsrv_send_reply(req);
934 /****************************************************************************
935 Reply to a writeunlock (core+).
936 ****************************************************************************/
937 void smbsrv_reply_writeunlock(struct smbsrv_request *req)
939 union smb_write *io;
941 SMBSRV_CHECK_WCT(req, 5);
942 SMBSRV_TALLOC_IO_PTR(io, union smb_write);
943 SMBSRV_SETUP_NTVFS_REQUEST(reply_writeunlock_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
945 io->writeunlock.level = RAW_WRITE_WRITEUNLOCK;
946 io->writeunlock.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
947 io->writeunlock.in.count = SVAL(req->in.vwv, VWV(1));
948 io->writeunlock.in.offset = IVAL(req->in.vwv, VWV(2));
949 io->writeunlock.in.remaining = SVAL(req->in.vwv, VWV(4));
950 io->writeunlock.in.data = req->in.data + 3;
952 /* make sure they gave us the data they promised */
953 if (io->writeunlock.in.count+3 > req->in.data_size) {
954 smbsrv_send_error(req, NT_STATUS_FOOBAR);
955 return;
958 /* make sure the data block is big enough */
959 if (SVAL(req->in.data, 1) < io->writeunlock.in.count) {
960 smbsrv_send_error(req, NT_STATUS_FOOBAR);
961 return;
964 SMBSRV_CHECK_FILE_HANDLE(io->writeunlock.in.file.ntvfs);
965 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
970 /****************************************************************************
971 Reply to a write (async reply)
972 ****************************************************************************/
973 static void reply_write_send(struct ntvfs_request *ntvfs)
975 struct smbsrv_request *req;
976 union smb_write *io;
978 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_write);
980 /* construct reply */
981 smbsrv_setup_reply(req, 1, 0);
983 SSVAL(req->out.vwv, VWV(0), io->write.out.nwritten);
985 smbsrv_send_reply(req);
988 /****************************************************************************
989 Reply to a write
990 ****************************************************************************/
991 void smbsrv_reply_write(struct smbsrv_request *req)
993 union smb_write *io;
995 SMBSRV_CHECK_WCT(req, 5);
996 SMBSRV_TALLOC_IO_PTR(io, union smb_write);
997 SMBSRV_SETUP_NTVFS_REQUEST(reply_write_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
999 io->write.level = RAW_WRITE_WRITE;
1000 io->write.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1001 io->write.in.count = SVAL(req->in.vwv, VWV(1));
1002 io->write.in.offset = IVAL(req->in.vwv, VWV(2));
1003 io->write.in.remaining = SVAL(req->in.vwv, VWV(4));
1004 io->write.in.data = req->in.data + 3;
1006 /* make sure they gave us the data they promised */
1007 if (req_data_oob(&req->in.bufinfo, io->write.in.data, io->write.in.count)) {
1008 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1009 return;
1012 /* make sure the data block is big enough */
1013 if (SVAL(req->in.data, 1) < io->write.in.count) {
1014 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1015 return;
1018 SMBSRV_CHECK_FILE_HANDLE(io->write.in.file.ntvfs);
1019 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
1023 /****************************************************************************
1024 Reply to a write and X (async reply)
1025 ****************************************************************************/
1026 static void reply_write_and_X_send(struct ntvfs_request *ntvfs)
1028 struct smbsrv_request *req;
1029 union smb_write *io;
1031 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_write);
1033 /* construct reply */
1034 smbsrv_setup_reply(req, 6, 0);
1036 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1037 SSVAL(req->out.vwv, VWV(1), 0);
1038 SSVAL(req->out.vwv, VWV(2), io->writex.out.nwritten & 0xFFFF);
1039 SSVAL(req->out.vwv, VWV(3), io->writex.out.remaining);
1040 SSVAL(req->out.vwv, VWV(4), io->writex.out.nwritten >> 16);
1041 SMBSRV_VWV_RESERVED(5, 1);
1043 smbsrv_chain_reply(req);
1046 /****************************************************************************
1047 Reply to a write and X.
1048 ****************************************************************************/
1049 void smbsrv_reply_write_and_X(struct smbsrv_request *req)
1051 union smb_write *io;
1053 if (req->in.wct != 14) {
1054 SMBSRV_CHECK_WCT(req, 12);
1057 SMBSRV_TALLOC_IO_PTR(io, union smb_write);
1058 SMBSRV_SETUP_NTVFS_REQUEST(reply_write_and_X_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1060 io->writex.level = RAW_WRITE_WRITEX;
1061 io->writex.in.file.ntvfs= smbsrv_pull_fnum(req, req->in.vwv, VWV(2));
1062 io->writex.in.offset = IVAL(req->in.vwv, VWV(3));
1063 io->writex.in.wmode = SVAL(req->in.vwv, VWV(7));
1064 io->writex.in.remaining = SVAL(req->in.vwv, VWV(8));
1065 io->writex.in.count = SVAL(req->in.vwv, VWV(10));
1066 io->writex.in.data = req->in.hdr + SVAL(req->in.vwv, VWV(11));
1068 if (req->in.wct == 14) {
1069 uint32_t offset_high = IVAL(req->in.vwv, VWV(12));
1070 uint16_t count_high = SVAL(req->in.vwv, VWV(9));
1071 io->writex.in.offset |= (((uint64_t)offset_high) << 32);
1072 io->writex.in.count |= ((uint32_t)count_high) << 16;
1075 /* make sure the data is in bounds */
1076 if (req_data_oob(&req->in.bufinfo, io->writex.in.data, io->writex.in.count)) {
1077 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
1078 return;
1081 SMBSRV_CHECK_FILE_HANDLE(io->writex.in.file.ntvfs);
1082 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
1086 /****************************************************************************
1087 Reply to a lseek (async reply)
1088 ****************************************************************************/
1089 static void reply_lseek_send(struct ntvfs_request *ntvfs)
1091 struct smbsrv_request *req;
1092 union smb_seek *io;
1094 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_seek);
1096 /* construct reply */
1097 smbsrv_setup_reply(req, 2, 0);
1099 SIVALS(req->out.vwv, VWV(0), io->lseek.out.offset);
1101 smbsrv_send_reply(req);
1104 /****************************************************************************
1105 Reply to a lseek.
1106 ****************************************************************************/
1107 void smbsrv_reply_lseek(struct smbsrv_request *req)
1109 union smb_seek *io;
1111 SMBSRV_CHECK_WCT(req, 4);
1112 SMBSRV_TALLOC_IO_PTR(io, union smb_seek);
1113 SMBSRV_SETUP_NTVFS_REQUEST(reply_lseek_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1115 io->lseek.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1116 io->lseek.in.mode = SVAL(req->in.vwv, VWV(1));
1117 io->lseek.in.offset = IVALS(req->in.vwv, VWV(2));
1119 SMBSRV_CHECK_FILE_HANDLE(io->lseek.in.file.ntvfs);
1120 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_seek(req->ntvfs, io));
1123 /****************************************************************************
1124 Reply to a flush.
1125 ****************************************************************************/
1126 void smbsrv_reply_flush(struct smbsrv_request *req)
1128 union smb_flush *io;
1129 uint16_t fnum;
1131 /* parse request */
1132 SMBSRV_CHECK_WCT(req, 1);
1133 SMBSRV_TALLOC_IO_PTR(io, union smb_flush);
1134 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1136 fnum = SVAL(req->in.vwv, VWV(0));
1137 if (fnum == 0xFFFF) {
1138 io->flush_all.level = RAW_FLUSH_ALL;
1139 } else {
1140 io->flush.level = RAW_FLUSH_FLUSH;
1141 io->flush.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1142 SMBSRV_CHECK_FILE_HANDLE(io->flush.in.file.ntvfs);
1145 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_flush(req->ntvfs, io));
1148 /****************************************************************************
1149 Reply to a close
1151 Note that this has to deal with closing a directory opened by NT SMB's.
1152 ****************************************************************************/
1153 void smbsrv_reply_close(struct smbsrv_request *req)
1155 union smb_close *io;
1157 /* parse request */
1158 SMBSRV_CHECK_WCT(req, 3);
1159 SMBSRV_TALLOC_IO_PTR(io, union smb_close);
1160 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1162 io->close.level = RAW_CLOSE_CLOSE;
1163 io->close.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1164 io->close.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(1));
1166 SMBSRV_CHECK_FILE_HANDLE(io->close.in.file.ntvfs);
1167 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_close(req->ntvfs, io));
1171 /****************************************************************************
1172 Reply to a writeclose (async reply)
1173 ****************************************************************************/
1174 static void reply_writeclose_send(struct ntvfs_request *ntvfs)
1176 struct smbsrv_request *req;
1177 union smb_write *io;
1179 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_write);
1181 /* construct reply */
1182 smbsrv_setup_reply(req, 1, 0);
1184 SSVAL(req->out.vwv, VWV(0), io->write.out.nwritten);
1186 smbsrv_send_reply(req);
1189 /****************************************************************************
1190 Reply to a writeclose (Core+ protocol).
1191 ****************************************************************************/
1192 void smbsrv_reply_writeclose(struct smbsrv_request *req)
1194 union smb_write *io;
1196 /* this one is pretty weird - the wct can be 6 or 12 */
1197 if (req->in.wct != 12) {
1198 SMBSRV_CHECK_WCT(req, 6);
1201 SMBSRV_TALLOC_IO_PTR(io, union smb_write);
1202 SMBSRV_SETUP_NTVFS_REQUEST(reply_writeclose_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1204 io->writeclose.level = RAW_WRITE_WRITECLOSE;
1205 io->writeclose.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1206 io->writeclose.in.count = SVAL(req->in.vwv, VWV(1));
1207 io->writeclose.in.offset = IVAL(req->in.vwv, VWV(2));
1208 io->writeclose.in.mtime = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(4));
1209 io->writeclose.in.data = req->in.data + 1;
1211 /* make sure they gave us the data they promised */
1212 if (req_data_oob(&req->in.bufinfo, io->writeclose.in.data, io->writeclose.in.count)) {
1213 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1214 return;
1217 SMBSRV_CHECK_FILE_HANDLE(io->writeclose.in.file.ntvfs);
1218 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
1221 /****************************************************************************
1222 Reply to a lock.
1223 ****************************************************************************/
1224 void smbsrv_reply_lock(struct smbsrv_request *req)
1226 union smb_lock *lck;
1228 /* parse request */
1229 SMBSRV_CHECK_WCT(req, 5);
1230 SMBSRV_TALLOC_IO_PTR(lck, union smb_lock);
1231 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1233 lck->lock.level = RAW_LOCK_LOCK;
1234 lck->lock.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1235 lck->lock.in.count = IVAL(req->in.vwv, VWV(1));
1236 lck->lock.in.offset = IVAL(req->in.vwv, VWV(3));
1238 SMBSRV_CHECK_FILE_HANDLE(lck->lock.in.file.ntvfs);
1239 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_lock(req->ntvfs, lck));
1243 /****************************************************************************
1244 Reply to a unlock.
1245 ****************************************************************************/
1246 void smbsrv_reply_unlock(struct smbsrv_request *req)
1248 union smb_lock *lck;
1250 /* parse request */
1251 SMBSRV_CHECK_WCT(req, 5);
1252 SMBSRV_TALLOC_IO_PTR(lck, union smb_lock);
1253 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1255 lck->unlock.level = RAW_LOCK_UNLOCK;
1256 lck->unlock.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1257 lck->unlock.in.count = IVAL(req->in.vwv, VWV(1));
1258 lck->unlock.in.offset = IVAL(req->in.vwv, VWV(3));
1260 SMBSRV_CHECK_FILE_HANDLE(lck->unlock.in.file.ntvfs);
1261 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_lock(req->ntvfs, lck));
1265 /****************************************************************************
1266 Reply to a tdis.
1267 ****************************************************************************/
1268 void smbsrv_reply_tdis(struct smbsrv_request *req)
1270 struct smbsrv_handle *h, *nh;
1272 SMBSRV_CHECK_WCT(req, 0);
1275 * TODO: cancel all pending requests on this tcon
1279 * close all handles on this tcon
1281 for (h=req->tcon->handles.list; h; h=nh) {
1282 nh = h->next;
1283 talloc_free(h);
1286 /* finally destroy the tcon */
1287 talloc_free(req->tcon);
1288 req->tcon = NULL;
1290 smbsrv_setup_reply(req, 0, 0);
1291 smbsrv_send_reply(req);
1295 /****************************************************************************
1296 Reply to a echo. This is one of the few calls that is handled directly (the
1297 backends don't see it at all)
1298 ****************************************************************************/
1299 void smbsrv_reply_echo(struct smbsrv_request *req)
1301 uint16_t count;
1302 int i;
1304 SMBSRV_CHECK_WCT(req, 1);
1306 count = SVAL(req->in.vwv, VWV(0));
1308 smbsrv_setup_reply(req, 1, req->in.data_size);
1310 memcpy(req->out.data, req->in.data, req->in.data_size);
1312 for (i=1; i <= count;i++) {
1313 struct smbsrv_request *this_req;
1315 if (i != count) {
1316 this_req = smbsrv_setup_secondary_request(req);
1317 } else {
1318 this_req = req;
1321 SSVAL(this_req->out.vwv, VWV(0), i);
1322 smbsrv_send_reply(this_req);
1328 /****************************************************************************
1329 Reply to a printopen (async reply)
1330 ****************************************************************************/
1331 static void reply_printopen_send(struct ntvfs_request *ntvfs)
1333 struct smbsrv_request *req;
1334 union smb_open *oi;
1336 SMBSRV_CHECK_ASYNC_STATUS(oi, union smb_open);
1338 /* construct reply */
1339 smbsrv_setup_reply(req, 1, 0);
1341 smbsrv_push_fnum(req->out.vwv, VWV(0), oi->openold.out.file.ntvfs);
1343 smbsrv_send_reply(req);
1346 /****************************************************************************
1347 Reply to a printopen.
1348 ****************************************************************************/
1349 void smbsrv_reply_printopen(struct smbsrv_request *req)
1351 union smb_open *oi;
1353 /* parse request */
1354 SMBSRV_CHECK_WCT(req, 2);
1355 SMBSRV_TALLOC_IO_PTR(oi, union smb_open);
1356 SMBSRV_SETUP_NTVFS_REQUEST(reply_printopen_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1358 oi->splopen.level = RAW_OPEN_SPLOPEN;
1359 oi->splopen.in.setup_length = SVAL(req->in.vwv, VWV(0));
1360 oi->splopen.in.mode = SVAL(req->in.vwv, VWV(1));
1362 req_pull_ascii4(&req->in.bufinfo, &oi->splopen.in.ident, req->in.data, STR_TERMINATE);
1364 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, oi));
1367 /****************************************************************************
1368 Reply to a printclose.
1369 ****************************************************************************/
1370 void smbsrv_reply_printclose(struct smbsrv_request *req)
1372 union smb_close *io;
1374 /* parse request */
1375 SMBSRV_CHECK_WCT(req, 3);
1376 SMBSRV_TALLOC_IO_PTR(io, union smb_close);
1377 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1379 io->splclose.level = RAW_CLOSE_SPLCLOSE;
1380 io->splclose.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1382 SMBSRV_CHECK_FILE_HANDLE(io->splclose.in.file.ntvfs);
1383 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_close(req->ntvfs, io));
1386 /****************************************************************************
1387 Reply to a printqueue.
1388 ****************************************************************************/
1389 static void reply_printqueue_send(struct ntvfs_request *ntvfs)
1391 struct smbsrv_request *req;
1392 union smb_lpq *lpq;
1393 int i, maxcount;
1394 const unsigned int el_size = 28;
1396 SMBSRV_CHECK_ASYNC_STATUS(lpq,union smb_lpq);
1398 /* construct reply */
1399 smbsrv_setup_reply(req, 2, 0);
1401 /* truncate the returned list to fit in the negotiated buffer size */
1402 maxcount = (req_max_data(req) - 3) / el_size;
1403 if (maxcount < lpq->retq.out.count) {
1404 lpq->retq.out.count = maxcount;
1407 /* setup enough space in the reply */
1408 req_grow_data(req, 3 + el_size*lpq->retq.out.count);
1410 /* and fill it in */
1411 SSVAL(req->out.vwv, VWV(0), lpq->retq.out.count);
1412 SSVAL(req->out.vwv, VWV(1), lpq->retq.out.restart_idx);
1414 SCVAL(req->out.data, 0, SMB_DATA_BLOCK);
1415 SSVAL(req->out.data, 1, el_size*lpq->retq.out.count);
1417 req->out.ptr = req->out.data + 3;
1419 for (i=0;i<lpq->retq.out.count;i++) {
1420 srv_push_dos_date2(req->smb_conn, req->out.ptr, 0 , lpq->retq.out.queue[i].time);
1421 SCVAL(req->out.ptr, 4, lpq->retq.out.queue[i].status);
1422 SSVAL(req->out.ptr, 5, lpq->retq.out.queue[i].job);
1423 SIVAL(req->out.ptr, 7, lpq->retq.out.queue[i].size);
1424 SCVAL(req->out.ptr, 11, 0); /* reserved */
1425 req_push_str(req, req->out.ptr+12, lpq->retq.out.queue[i].user, 16, STR_ASCII);
1426 req->out.ptr += el_size;
1429 smbsrv_send_reply(req);
1432 /****************************************************************************
1433 Reply to a printqueue.
1434 ****************************************************************************/
1435 void smbsrv_reply_printqueue(struct smbsrv_request *req)
1437 union smb_lpq *lpq;
1439 /* parse request */
1440 SMBSRV_CHECK_WCT(req, 2);
1441 SMBSRV_TALLOC_IO_PTR(lpq, union smb_lpq);
1442 SMBSRV_SETUP_NTVFS_REQUEST(reply_printqueue_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1444 lpq->retq.level = RAW_LPQ_RETQ;
1445 lpq->retq.in.maxcount = SVAL(req->in.vwv, VWV(0));
1446 lpq->retq.in.startidx = SVAL(req->in.vwv, VWV(1));
1448 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_lpq(req->ntvfs, lpq));
1452 /****************************************************************************
1453 Reply to a printwrite.
1454 ****************************************************************************/
1455 void smbsrv_reply_printwrite(struct smbsrv_request *req)
1457 union smb_write *io;
1459 /* parse request */
1460 SMBSRV_CHECK_WCT(req, 1);
1461 SMBSRV_TALLOC_IO_PTR(io, union smb_write);
1462 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1464 if (req->in.data_size < 3) {
1465 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1466 return;
1469 io->splwrite.level = RAW_WRITE_SPLWRITE;
1470 io->splwrite.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1471 io->splwrite.in.count = SVAL(req->in.data, 1);
1472 io->splwrite.in.data = req->in.data + 3;
1474 /* make sure they gave us the data they promised */
1475 if (req_data_oob(&req->in.bufinfo, io->splwrite.in.data, io->splwrite.in.count)) {
1476 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1477 return;
1480 SMBSRV_CHECK_FILE_HANDLE(io->splwrite.in.file.ntvfs);
1481 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
1485 /****************************************************************************
1486 Reply to a mkdir.
1487 ****************************************************************************/
1488 void smbsrv_reply_mkdir(struct smbsrv_request *req)
1490 union smb_mkdir *io;
1492 /* parse the request */
1493 SMBSRV_CHECK_WCT(req, 0);
1494 SMBSRV_TALLOC_IO_PTR(io, union smb_mkdir);
1495 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1497 io->generic.level = RAW_MKDIR_MKDIR;
1498 req_pull_ascii4(&req->in.bufinfo, &io->mkdir.in.path, req->in.data, STR_TERMINATE);
1500 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_mkdir(req->ntvfs, io));
1504 /****************************************************************************
1505 Reply to a rmdir.
1506 ****************************************************************************/
1507 void smbsrv_reply_rmdir(struct smbsrv_request *req)
1509 struct smb_rmdir *io;
1511 /* parse the request */
1512 SMBSRV_CHECK_WCT(req, 0);
1513 SMBSRV_TALLOC_IO_PTR(io, struct smb_rmdir);
1514 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1516 req_pull_ascii4(&req->in.bufinfo, &io->in.path, req->in.data, STR_TERMINATE);
1518 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_rmdir(req->ntvfs, io));
1522 /****************************************************************************
1523 Reply to a mv.
1524 ****************************************************************************/
1525 void smbsrv_reply_mv(struct smbsrv_request *req)
1527 union smb_rename *io;
1528 uint8_t *p;
1530 /* parse the request */
1531 SMBSRV_CHECK_WCT(req, 1);
1532 SMBSRV_TALLOC_IO_PTR(io, union smb_rename);
1533 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1535 io->generic.level = RAW_RENAME_RENAME;
1536 io->rename.in.attrib = SVAL(req->in.vwv, VWV(0));
1538 p = req->in.data;
1539 p += req_pull_ascii4(&req->in.bufinfo, &io->rename.in.pattern1, p, STR_TERMINATE);
1540 p += req_pull_ascii4(&req->in.bufinfo, &io->rename.in.pattern2, p, STR_TERMINATE);
1542 if (!io->rename.in.pattern1 || !io->rename.in.pattern2) {
1543 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1544 return;
1547 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_rename(req->ntvfs, io));
1551 /****************************************************************************
1552 Reply to an NT rename.
1553 ****************************************************************************/
1554 void smbsrv_reply_ntrename(struct smbsrv_request *req)
1556 union smb_rename *io;
1557 uint8_t *p;
1559 /* parse the request */
1560 SMBSRV_CHECK_WCT(req, 4);
1561 SMBSRV_TALLOC_IO_PTR(io, union smb_rename);
1562 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1564 io->generic.level = RAW_RENAME_NTRENAME;
1565 io->ntrename.in.attrib = SVAL(req->in.vwv, VWV(0));
1566 io->ntrename.in.flags = SVAL(req->in.vwv, VWV(1));
1567 io->ntrename.in.cluster_size = IVAL(req->in.vwv, VWV(2));
1569 p = req->in.data;
1570 p += req_pull_ascii4(&req->in.bufinfo, &io->ntrename.in.old_name, p, STR_TERMINATE);
1571 p += req_pull_ascii4(&req->in.bufinfo, &io->ntrename.in.new_name, p, STR_TERMINATE);
1573 if (!io->ntrename.in.old_name || !io->ntrename.in.new_name) {
1574 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1575 return;
1578 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_rename(req->ntvfs, io));
1581 /****************************************************************************
1582 Reply to a file copy (async reply)
1583 ****************************************************************************/
1584 static void reply_copy_send(struct ntvfs_request *ntvfs)
1586 struct smbsrv_request *req;
1587 struct smb_copy *cp;
1589 SMBSRV_CHECK_ASYNC_STATUS(cp, struct smb_copy);
1591 /* build the reply */
1592 smbsrv_setup_reply(req, 1, 0);
1594 SSVAL(req->out.vwv, VWV(0), cp->out.count);
1596 smbsrv_send_reply(req);
1599 /****************************************************************************
1600 Reply to a file copy.
1601 ****************************************************************************/
1602 void smbsrv_reply_copy(struct smbsrv_request *req)
1604 struct smb_copy *cp;
1605 uint8_t *p;
1607 /* parse request */
1608 SMBSRV_CHECK_WCT(req, 3);
1609 SMBSRV_TALLOC_IO_PTR(cp, struct smb_copy);
1610 SMBSRV_SETUP_NTVFS_REQUEST(reply_copy_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1612 cp->in.tid2 = SVAL(req->in.vwv, VWV(0));
1613 cp->in.ofun = SVAL(req->in.vwv, VWV(1));
1614 cp->in.flags = SVAL(req->in.vwv, VWV(2));
1616 p = req->in.data;
1617 p += req_pull_ascii4(&req->in.bufinfo, &cp->in.path1, p, STR_TERMINATE);
1618 p += req_pull_ascii4(&req->in.bufinfo, &cp->in.path2, p, STR_TERMINATE);
1620 if (!cp->in.path1 || !cp->in.path2) {
1621 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1622 return;
1625 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_copy(req->ntvfs, cp));
1628 /****************************************************************************
1629 Reply to a lockingX request (async send)
1630 ****************************************************************************/
1631 static void reply_lockingX_send(struct ntvfs_request *ntvfs)
1633 struct smbsrv_request *req;
1634 union smb_lock *lck;
1636 SMBSRV_CHECK_ASYNC_STATUS(lck, union smb_lock);
1638 /* if it was an oplock break ack then we only send a reply if
1639 there was an error */
1640 if (lck->lockx.in.ulock_cnt + lck->lockx.in.lock_cnt == 0) {
1641 talloc_free(req);
1642 return;
1645 /* construct reply */
1646 smbsrv_setup_reply(req, 2, 0);
1648 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1649 SSVAL(req->out.vwv, VWV(1), 0);
1651 smbsrv_chain_reply(req);
1655 /****************************************************************************
1656 Reply to a lockingX request.
1657 ****************************************************************************/
1658 void smbsrv_reply_lockingX(struct smbsrv_request *req)
1660 union smb_lock *lck;
1661 unsigned int total_locks, i;
1662 unsigned int lck_size;
1663 uint8_t *p;
1665 /* parse request */
1666 SMBSRV_CHECK_WCT(req, 8);
1667 SMBSRV_TALLOC_IO_PTR(lck, union smb_lock);
1668 SMBSRV_SETUP_NTVFS_REQUEST(reply_lockingX_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1670 lck->lockx.level = RAW_LOCK_LOCKX;
1671 lck->lockx.in.file.ntvfs= smbsrv_pull_fnum(req, req->in.vwv, VWV(2));
1672 lck->lockx.in.mode = SVAL(req->in.vwv, VWV(3));
1673 lck->lockx.in.timeout = IVAL(req->in.vwv, VWV(4));
1674 lck->lockx.in.ulock_cnt = SVAL(req->in.vwv, VWV(6));
1675 lck->lockx.in.lock_cnt = SVAL(req->in.vwv, VWV(7));
1677 total_locks = lck->lockx.in.ulock_cnt + lck->lockx.in.lock_cnt;
1679 /* there are two variants, one with 64 bit offsets and counts */
1680 if (lck->lockx.in.mode & LOCKING_ANDX_LARGE_FILES) {
1681 lck_size = 20;
1682 } else {
1683 lck_size = 10;
1686 /* make sure we got the promised data */
1687 if (req_data_oob(&req->in.bufinfo, req->in.data, total_locks * lck_size)) {
1688 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1689 return;
1692 /* allocate the locks array */
1693 if (total_locks) {
1694 lck->lockx.in.locks = talloc_array(req, struct smb_lock_entry,
1695 total_locks);
1696 if (lck->lockx.in.locks == NULL) {
1697 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
1698 return;
1702 p = req->in.data;
1704 /* construct the locks array */
1705 for (i=0;i<total_locks;i++) {
1706 uint32_t ofs_high=0, count_high=0;
1708 lck->lockx.in.locks[i].pid = SVAL(p, 0);
1710 if (lck->lockx.in.mode & LOCKING_ANDX_LARGE_FILES) {
1711 ofs_high = IVAL(p, 4);
1712 lck->lockx.in.locks[i].offset = IVAL(p, 8);
1713 count_high = IVAL(p, 12);
1714 lck->lockx.in.locks[i].count = IVAL(p, 16);
1715 } else {
1716 lck->lockx.in.locks[i].offset = IVAL(p, 2);
1717 lck->lockx.in.locks[i].count = IVAL(p, 6);
1719 if (ofs_high != 0 || count_high != 0) {
1720 lck->lockx.in.locks[i].count |= ((uint64_t)count_high) << 32;
1721 lck->lockx.in.locks[i].offset |= ((uint64_t)ofs_high) << 32;
1723 p += lck_size;
1726 SMBSRV_CHECK_FILE_HANDLE(lck->lockx.in.file.ntvfs);
1727 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_lock(req->ntvfs, lck));
1730 /****************************************************************************
1731 Reply to a SMBreadbmpx (read block multiplex) request.
1732 ****************************************************************************/
1733 void smbsrv_reply_readbmpx(struct smbsrv_request *req)
1735 /* tell the client to not use a multiplexed read - its too broken to use */
1736 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRuseSTD));
1740 /****************************************************************************
1741 Reply to a SMBsetattrE.
1742 ****************************************************************************/
1743 void smbsrv_reply_setattrE(struct smbsrv_request *req)
1745 union smb_setfileinfo *info;
1747 /* parse request */
1748 SMBSRV_CHECK_WCT(req, 7);
1749 SMBSRV_TALLOC_IO_PTR(info, union smb_setfileinfo);
1750 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1752 info->setattre.level = RAW_SFILEINFO_SETATTRE;
1753 info->setattre.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1754 info->setattre.in.create_time = srv_pull_dos_date2(req->smb_conn, req->in.vwv + VWV(1));
1755 info->setattre.in.access_time = srv_pull_dos_date2(req->smb_conn, req->in.vwv + VWV(3));
1756 info->setattre.in.write_time = srv_pull_dos_date2(req->smb_conn, req->in.vwv + VWV(5));
1758 SMBSRV_CHECK_FILE_HANDLE(info->setattre.in.file.ntvfs);
1759 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_setfileinfo(req->ntvfs, info));
1763 /****************************************************************************
1764 Reply to a SMBwritebmpx (write block multiplex primary) request.
1765 ****************************************************************************/
1766 void smbsrv_reply_writebmpx(struct smbsrv_request *req)
1768 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRuseSTD));
1772 /****************************************************************************
1773 Reply to a SMBwritebs (write block multiplex secondary) request.
1774 ****************************************************************************/
1775 void smbsrv_reply_writebs(struct smbsrv_request *req)
1777 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRuseSTD));
1782 /****************************************************************************
1783 Reply to a SMBgetattrE (async reply)
1784 ****************************************************************************/
1785 static void reply_getattrE_send(struct ntvfs_request *ntvfs)
1787 struct smbsrv_request *req;
1788 union smb_fileinfo *info;
1790 SMBSRV_CHECK_ASYNC_STATUS(info, union smb_fileinfo);
1792 /* setup reply */
1793 smbsrv_setup_reply(req, 11, 0);
1795 srv_push_dos_date2(req->smb_conn, req->out.vwv, VWV(0), info->getattre.out.create_time);
1796 srv_push_dos_date2(req->smb_conn, req->out.vwv, VWV(2), info->getattre.out.access_time);
1797 srv_push_dos_date2(req->smb_conn, req->out.vwv, VWV(4), info->getattre.out.write_time);
1798 SIVAL(req->out.vwv, VWV(6), info->getattre.out.size);
1799 SIVAL(req->out.vwv, VWV(8), info->getattre.out.alloc_size);
1800 SSVAL(req->out.vwv, VWV(10), info->getattre.out.attrib);
1802 smbsrv_send_reply(req);
1805 /****************************************************************************
1806 Reply to a SMBgetattrE.
1807 ****************************************************************************/
1808 void smbsrv_reply_getattrE(struct smbsrv_request *req)
1810 union smb_fileinfo *info;
1812 /* parse request */
1813 SMBSRV_CHECK_WCT(req, 1);
1814 SMBSRV_TALLOC_IO_PTR(info, union smb_fileinfo);
1815 SMBSRV_SETUP_NTVFS_REQUEST(reply_getattrE_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1817 info->getattr.level = RAW_FILEINFO_GETATTRE;
1818 info->getattr.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1820 SMBSRV_CHECK_FILE_HANDLE(info->getattr.in.file.ntvfs);
1821 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_qfileinfo(req->ntvfs, info));
1824 void smbsrv_reply_sesssetup_send(struct smbsrv_request *req,
1825 union smb_sesssetup *io,
1826 NTSTATUS status)
1828 switch (io->old.level) {
1829 case RAW_SESSSETUP_OLD:
1830 if (!NT_STATUS_IS_OK(status)) {
1831 smbsrv_send_error(req, status);
1832 return;
1835 /* construct reply */
1836 smbsrv_setup_reply(req, 3, 0);
1838 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1839 SSVAL(req->out.vwv, VWV(1), 0);
1840 SSVAL(req->out.vwv, VWV(2), io->old.out.action);
1842 SSVAL(req->out.hdr, HDR_UID, io->old.out.vuid);
1844 smbsrv_chain_reply(req);
1845 return;
1847 case RAW_SESSSETUP_NT1:
1848 if (!NT_STATUS_IS_OK(status)) {
1849 smbsrv_send_error(req, status);
1850 return;
1853 /* construct reply */
1854 smbsrv_setup_reply(req, 3, 0);
1856 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1857 SSVAL(req->out.vwv, VWV(1), 0);
1858 SSVAL(req->out.vwv, VWV(2), io->nt1.out.action);
1860 SSVAL(req->out.hdr, HDR_UID, io->nt1.out.vuid);
1862 req_push_str(req, NULL, io->nt1.out.os, -1, STR_TERMINATE);
1863 req_push_str(req, NULL, io->nt1.out.lanman, -1, STR_TERMINATE);
1864 req_push_str(req, NULL, io->nt1.out.domain, -1, STR_TERMINATE);
1866 smbsrv_chain_reply(req);
1867 return;
1869 case RAW_SESSSETUP_SPNEGO:
1870 if (!NT_STATUS_IS_OK(status) &&
1871 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1872 smbsrv_send_error(req, status);
1873 return;
1876 /* construct reply */
1877 smbsrv_setup_reply(req, 4, io->spnego.out.secblob.length);
1879 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1880 smbsrv_setup_error(req, status);
1883 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1884 SSVAL(req->out.vwv, VWV(1), 0);
1885 SSVAL(req->out.vwv, VWV(2), io->spnego.out.action);
1886 SSVAL(req->out.vwv, VWV(3), io->spnego.out.secblob.length);
1888 SSVAL(req->out.hdr, HDR_UID, io->spnego.out.vuid);
1890 memcpy(req->out.data, io->spnego.out.secblob.data, io->spnego.out.secblob.length);
1891 req_push_str(req, NULL, io->spnego.out.os, -1, STR_TERMINATE);
1892 req_push_str(req, NULL, io->spnego.out.lanman, -1, STR_TERMINATE);
1893 req_push_str(req, NULL, io->spnego.out.workgroup, -1, STR_TERMINATE);
1895 smbsrv_chain_reply(req);
1896 return;
1898 case RAW_SESSSETUP_SMB2:
1899 break;
1902 smbsrv_send_error(req, NT_STATUS_INTERNAL_ERROR);
1905 /****************************************************************************
1906 reply to an old style session setup command
1907 ****************************************************************************/
1908 static void reply_sesssetup_old(struct smbsrv_request *req)
1910 uint8_t *p;
1911 uint16_t passlen;
1912 union smb_sesssetup *io;
1914 SMBSRV_TALLOC_IO_PTR(io, union smb_sesssetup);
1916 io->old.level = RAW_SESSSETUP_OLD;
1918 /* parse request */
1919 io->old.in.bufsize = SVAL(req->in.vwv, VWV(2));
1920 io->old.in.mpx_max = SVAL(req->in.vwv, VWV(3));
1921 io->old.in.vc_num = SVAL(req->in.vwv, VWV(4));
1922 io->old.in.sesskey = IVAL(req->in.vwv, VWV(5));
1923 passlen = SVAL(req->in.vwv, VWV(7));
1925 /* check the request isn't malformed */
1926 if (req_data_oob(&req->in.bufinfo, req->in.data, passlen)) {
1927 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1928 return;
1931 p = req->in.data;
1932 if (!req_pull_blob(&req->in.bufinfo, p, passlen, &io->old.in.password)) {
1933 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1934 return;
1936 p += passlen;
1938 p += req_pull_string(&req->in.bufinfo, &io->old.in.user, p, -1, STR_TERMINATE);
1939 p += req_pull_string(&req->in.bufinfo, &io->old.in.domain, p, -1, STR_TERMINATE);
1940 p += req_pull_string(&req->in.bufinfo, &io->old.in.os, p, -1, STR_TERMINATE);
1941 p += req_pull_string(&req->in.bufinfo, &io->old.in.lanman, p, -1, STR_TERMINATE);
1943 /* call the generic handler */
1944 smbsrv_sesssetup_backend(req, io);
1947 /****************************************************************************
1948 reply to an NT1 style session setup command
1949 ****************************************************************************/
1950 static void reply_sesssetup_nt1(struct smbsrv_request *req)
1952 uint8_t *p;
1953 uint16_t passlen1, passlen2;
1954 union smb_sesssetup *io;
1956 SMBSRV_TALLOC_IO_PTR(io, union smb_sesssetup);
1958 io->nt1.level = RAW_SESSSETUP_NT1;
1960 /* parse request */
1961 io->nt1.in.bufsize = SVAL(req->in.vwv, VWV(2));
1962 io->nt1.in.mpx_max = SVAL(req->in.vwv, VWV(3));
1963 io->nt1.in.vc_num = SVAL(req->in.vwv, VWV(4));
1964 io->nt1.in.sesskey = IVAL(req->in.vwv, VWV(5));
1965 passlen1 = SVAL(req->in.vwv, VWV(7));
1966 passlen2 = SVAL(req->in.vwv, VWV(8));
1967 io->nt1.in.capabilities = IVAL(req->in.vwv, VWV(11));
1969 /* check the request isn't malformed */
1970 if (req_data_oob(&req->in.bufinfo, req->in.data, passlen1) ||
1971 req_data_oob(&req->in.bufinfo, req->in.data + passlen1, passlen2)) {
1972 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1973 return;
1976 p = req->in.data;
1977 if (!req_pull_blob(&req->in.bufinfo, p, passlen1, &io->nt1.in.password1)) {
1978 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1979 return;
1981 p += passlen1;
1982 if (!req_pull_blob(&req->in.bufinfo, p, passlen2, &io->nt1.in.password2)) {
1983 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1984 return;
1986 p += passlen2;
1988 p += req_pull_string(&req->in.bufinfo, &io->nt1.in.user, p, -1, STR_TERMINATE);
1989 p += req_pull_string(&req->in.bufinfo, &io->nt1.in.domain, p, -1, STR_TERMINATE);
1990 p += req_pull_string(&req->in.bufinfo, &io->nt1.in.os, p, -1, STR_TERMINATE);
1991 p += req_pull_string(&req->in.bufinfo, &io->nt1.in.lanman, p, -1, STR_TERMINATE);
1993 /* call the generic handler */
1994 smbsrv_sesssetup_backend(req, io);
1998 /****************************************************************************
1999 reply to an SPNEGO style session setup command
2000 ****************************************************************************/
2001 static void reply_sesssetup_spnego(struct smbsrv_request *req)
2003 uint8_t *p;
2004 uint16_t blob_len;
2005 union smb_sesssetup *io;
2007 SMBSRV_TALLOC_IO_PTR(io, union smb_sesssetup);
2009 io->spnego.level = RAW_SESSSETUP_SPNEGO;
2011 /* parse request */
2012 io->spnego.in.bufsize = SVAL(req->in.vwv, VWV(2));
2013 io->spnego.in.mpx_max = SVAL(req->in.vwv, VWV(3));
2014 io->spnego.in.vc_num = SVAL(req->in.vwv, VWV(4));
2015 io->spnego.in.sesskey = IVAL(req->in.vwv, VWV(5));
2016 blob_len = SVAL(req->in.vwv, VWV(7));
2017 io->spnego.in.capabilities = IVAL(req->in.vwv, VWV(10));
2019 p = req->in.data;
2020 if (!req_pull_blob(&req->in.bufinfo, p, blob_len, &io->spnego.in.secblob)) {
2021 smbsrv_send_error(req, NT_STATUS_FOOBAR);
2022 return;
2024 p += blob_len;
2026 p += req_pull_string(&req->in.bufinfo, &io->spnego.in.os, p, -1, STR_TERMINATE);
2027 p += req_pull_string(&req->in.bufinfo, &io->spnego.in.lanman, p, -1, STR_TERMINATE);
2028 p += req_pull_string(&req->in.bufinfo, &io->spnego.in.workgroup, p, -1, STR_TERMINATE);
2030 /* call the generic handler */
2031 smbsrv_sesssetup_backend(req, io);
2035 /****************************************************************************
2036 reply to a session setup command
2037 ****************************************************************************/
2038 void smbsrv_reply_sesssetup(struct smbsrv_request *req)
2040 switch (req->in.wct) {
2041 case 10:
2042 /* a pre-NT1 call */
2043 reply_sesssetup_old(req);
2044 return;
2045 case 13:
2046 /* a NT1 call */
2047 reply_sesssetup_nt1(req);
2048 return;
2049 case 12:
2050 /* a SPNEGO call */
2051 reply_sesssetup_spnego(req);
2052 return;
2055 /* unsupported variant */
2056 smbsrv_send_error(req, NT_STATUS_FOOBAR);
2059 /****************************************************************************
2060 Reply to a exit. This closes all files open by a smbpid
2061 ****************************************************************************/
2062 void smbsrv_reply_exit(struct smbsrv_request *req)
2064 struct smbsrv_handle_session_item *i, *ni;
2065 struct smbsrv_handle *h;
2066 struct smbsrv_tcon *tcon;
2067 uint16_t smbpid;
2069 SMBSRV_CHECK_WCT(req, 0);
2071 smbpid = SVAL(req->in.hdr,HDR_PID);
2073 /* first destroy all handles, which have the same PID as the request */
2074 for (i=req->session->handles; i; i=ni) {
2075 ni = i->next;
2076 h = i->handle;
2077 if (h->smbpid != smbpid) continue;
2079 talloc_free(h);
2083 * then let the ntvfs backends proxy the call if they want to,
2084 * but we didn't check the return value of the backends,
2085 * as for the SMB client the call succeed
2087 for (tcon=req->smb_conn->smb_tcons.list;tcon;tcon=tcon->next) {
2088 req->tcon = tcon;
2089 SMBSRV_SETUP_NTVFS_REQUEST(NULL,0);
2090 ntvfs_exit(req->ntvfs);
2091 talloc_free(req->ntvfs);
2092 req->ntvfs = NULL;
2093 req->tcon = NULL;
2096 smbsrv_setup_reply(req, 0, 0);
2097 smbsrv_send_reply(req);
2100 /****************************************************************************
2101 Reply to a SMBulogoffX.
2102 ****************************************************************************/
2103 void smbsrv_reply_ulogoffX(struct smbsrv_request *req)
2105 struct smbsrv_handle_session_item *i, *ni;
2106 struct smbsrv_handle *h;
2107 struct smbsrv_tcon *tcon;
2109 SMBSRV_CHECK_WCT(req, 2);
2112 * TODO: cancel all pending requests
2116 /* destroy all handles */
2117 for (i=req->session->handles; i; i=ni) {
2118 ni = i->next;
2119 h = i->handle;
2120 talloc_free(h);
2124 * then let the ntvfs backends proxy the call if they want to,
2125 * but we didn't check the return value of the backends,
2126 * as for the SMB client the call succeed
2128 for (tcon=req->smb_conn->smb_tcons.list;tcon;tcon=tcon->next) {
2129 req->tcon = tcon;
2130 SMBSRV_SETUP_NTVFS_REQUEST(NULL,0);
2131 ntvfs_logoff(req->ntvfs);
2132 talloc_free(req->ntvfs);
2133 req->ntvfs = NULL;
2134 req->tcon = NULL;
2137 talloc_free(req->session);
2138 req->session = NULL; /* it is now invalid, don't use on
2139 any chained packets */
2141 smbsrv_setup_reply(req, 2, 0);
2143 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
2144 SSVAL(req->out.vwv, VWV(1), 0);
2146 smbsrv_chain_reply(req);
2149 /****************************************************************************
2150 Reply to an SMBfindclose request
2151 ****************************************************************************/
2152 void smbsrv_reply_findclose(struct smbsrv_request *req)
2154 union smb_search_close *io;
2156 /* parse request */
2157 SMBSRV_CHECK_WCT(req, 1);
2158 SMBSRV_TALLOC_IO_PTR(io, union smb_search_close);
2159 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
2161 io->findclose.level = RAW_FINDCLOSE_FINDCLOSE;
2162 io->findclose.in.handle = SVAL(req->in.vwv, VWV(0));
2164 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_search_close(req->ntvfs, io));
2167 /****************************************************************************
2168 Reply to an SMBfindnclose request
2169 ****************************************************************************/
2170 void smbsrv_reply_findnclose(struct smbsrv_request *req)
2172 smbsrv_send_error(req, NT_STATUS_FOOBAR);
2176 /****************************************************************************
2177 Reply to an SMBntcreateX request (async send)
2178 ****************************************************************************/
2179 static void reply_ntcreate_and_X_send(struct ntvfs_request *ntvfs)
2181 struct smbsrv_request *req;
2182 union smb_open *io;
2184 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_open);
2186 /* construct reply */
2187 smbsrv_setup_reply(req, 34, 0);
2189 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
2190 SSVAL(req->out.vwv, VWV(1), 0);
2191 SCVAL(req->out.vwv, VWV(2), io->ntcreatex.out.oplock_level);
2193 /* the rest of the parameters are not aligned! */
2194 smbsrv_push_fnum(req->out.vwv, 5, io->ntcreatex.out.file.ntvfs);
2195 SIVAL(req->out.vwv, 7, io->ntcreatex.out.create_action);
2196 push_nttime(req->out.vwv, 11, io->ntcreatex.out.create_time);
2197 push_nttime(req->out.vwv, 19, io->ntcreatex.out.access_time);
2198 push_nttime(req->out.vwv, 27, io->ntcreatex.out.write_time);
2199 push_nttime(req->out.vwv, 35, io->ntcreatex.out.change_time);
2200 SIVAL(req->out.vwv, 43, io->ntcreatex.out.attrib);
2201 SBVAL(req->out.vwv, 47, io->ntcreatex.out.alloc_size);
2202 SBVAL(req->out.vwv, 55, io->ntcreatex.out.size);
2203 SSVAL(req->out.vwv, 63, io->ntcreatex.out.file_type);
2204 SSVAL(req->out.vwv, 65, io->ntcreatex.out.ipc_state);
2205 SCVAL(req->out.vwv, 67, io->ntcreatex.out.is_directory);
2207 req->chained_fnum = SVAL(req->out.vwv, 5);
2209 smbsrv_chain_reply(req);
2212 /****************************************************************************
2213 Reply to an SMBntcreateX request
2214 ****************************************************************************/
2215 void smbsrv_reply_ntcreate_and_X(struct smbsrv_request *req)
2217 union smb_open *io;
2218 uint16_t fname_len;
2220 /* parse the request */
2221 SMBSRV_CHECK_WCT(req, 24);
2222 SMBSRV_TALLOC_IO_PTR(io, union smb_open);
2223 SMBSRV_SETUP_NTVFS_REQUEST(reply_ntcreate_and_X_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
2225 io->ntcreatex.level = RAW_OPEN_NTCREATEX;
2227 /* notice that the word parameters are not word aligned, so we don't use VWV() */
2228 fname_len = SVAL(req->in.vwv, 5);
2229 io->ntcreatex.in.flags = IVAL(req->in.vwv, 7);
2230 io->ntcreatex.in.root_fid.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, 11);
2231 io->ntcreatex.in.access_mask = IVAL(req->in.vwv, 15);
2232 io->ntcreatex.in.alloc_size = BVAL(req->in.vwv, 19);
2233 io->ntcreatex.in.file_attr = IVAL(req->in.vwv, 27);
2234 io->ntcreatex.in.share_access = IVAL(req->in.vwv, 31);
2235 io->ntcreatex.in.open_disposition = IVAL(req->in.vwv, 35);
2236 io->ntcreatex.in.create_options = IVAL(req->in.vwv, 39);
2237 io->ntcreatex.in.impersonation = IVAL(req->in.vwv, 43);
2238 io->ntcreatex.in.security_flags = CVAL(req->in.vwv, 47);
2239 io->ntcreatex.in.ea_list = NULL;
2240 io->ntcreatex.in.sec_desc = NULL;
2241 io->ntcreatex.in.query_maximal_access = false;
2242 io->ntcreatex.in.private_flags = 0;
2244 /* we need a neater way to handle this alignment */
2245 if ((req->flags2 & FLAGS2_UNICODE_STRINGS) &&
2246 ucs2_align(req->in.buffer, req->in.data, STR_TERMINATE|STR_UNICODE)) {
2247 fname_len++;
2250 req_pull_string(&req->in.bufinfo, &io->ntcreatex.in.fname, req->in.data, fname_len, STR_TERMINATE);
2251 if (!io->ntcreatex.in.fname) {
2252 smbsrv_send_error(req, NT_STATUS_FOOBAR);
2253 return;
2256 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, io));
2260 /****************************************************************************
2261 Reply to an SMBntcancel request
2262 ****************************************************************************/
2263 void smbsrv_reply_ntcancel(struct smbsrv_request *req)
2265 struct smbsrv_request *r;
2266 uint16_t tid = SVAL(req->in.hdr,HDR_TID);
2267 uint16_t uid = SVAL(req->in.hdr,HDR_UID);
2268 uint16_t mid = SVAL(req->in.hdr,HDR_MID);
2269 uint16_t pid = SVAL(req->in.hdr,HDR_PID);
2271 for (r = req->smb_conn->requests; r; r = r->next) {
2272 if (tid != SVAL(r->in.hdr,HDR_TID)) continue;
2273 if (uid != SVAL(r->in.hdr,HDR_UID)) continue;
2274 if (mid != SVAL(r->in.hdr,HDR_MID)) continue;
2275 if (pid != SVAL(r->in.hdr,HDR_PID)) continue;
2277 SMBSRV_CHECK(ntvfs_cancel(r->ntvfs));
2279 /* NOTE: this request does not generate a reply */
2280 talloc_free(req);
2281 return;
2284 /* TODO: workout the correct error code,
2285 * until we know how the smb signing works
2286 * for ntcancel replies, don't send an error
2288 /*smbsrv_send_error(req, NT_STATUS_FOOBAR);*/
2289 talloc_free(req);
2293 parse the called/calling names from session request
2295 static NTSTATUS parse_session_request(struct smbsrv_request *req)
2297 DATA_BLOB blob;
2298 NTSTATUS status;
2300 blob.data = req->in.buffer + 4;
2301 blob.length = ascii_len_n((const char *)blob.data, req->in.size - PTR_DIFF(blob.data, req->in.buffer));
2302 if (blob.length == 0) return NT_STATUS_BAD_NETWORK_NAME;
2304 req->smb_conn->negotiate.called_name = talloc(req->smb_conn, struct nbt_name);
2305 req->smb_conn->negotiate.calling_name = talloc(req->smb_conn, struct nbt_name);
2306 if (req->smb_conn->negotiate.called_name == NULL ||
2307 req->smb_conn->negotiate.calling_name == NULL) {
2308 return NT_STATUS_NO_MEMORY;
2311 status = nbt_name_from_blob(req->smb_conn, &blob,
2312 req->smb_conn->negotiate.called_name);
2313 NT_STATUS_NOT_OK_RETURN(status);
2315 blob.data += blob.length;
2316 blob.length = ascii_len_n((const char *)blob.data, req->in.size - PTR_DIFF(blob.data, req->in.buffer));
2317 if (blob.length == 0) return NT_STATUS_BAD_NETWORK_NAME;
2319 status = nbt_name_from_blob(req->smb_conn, &blob,
2320 req->smb_conn->negotiate.calling_name);
2321 NT_STATUS_NOT_OK_RETURN(status);
2323 req->smb_conn->negotiate.done_nbt_session = true;
2325 return NT_STATUS_OK;
2330 /****************************************************************************
2331 Reply to a special message - a SMB packet with non zero NBT message type
2332 ****************************************************************************/
2333 void smbsrv_reply_special(struct smbsrv_request *req)
2335 uint8_t msg_type;
2336 uint8_t *buf = talloc_zero_array(req, uint8_t, 4);
2338 msg_type = CVAL(req->in.buffer,0);
2340 SIVAL(buf, 0, 0);
2342 switch (msg_type) {
2343 case NBSSrequest: /* session request */
2344 if (req->smb_conn->negotiate.done_nbt_session) {
2345 DEBUG(0,("Warning: ignoring secondary session request\n"));
2346 return;
2349 SCVAL(buf,0,0x82);
2350 SCVAL(buf,3,0);
2352 /* we don't check the status - samba always accepts session
2353 requests for any name */
2354 parse_session_request(req);
2356 req->out.buffer = buf;
2357 req->out.size = 4;
2358 smbsrv_send_reply_nosign(req);
2359 return;
2361 case 0x89: /* session keepalive request
2362 (some old clients produce this?) */
2363 SCVAL(buf, 0, NBSSkeepalive);
2364 SCVAL(buf, 3, 0);
2365 req->out.buffer = buf;
2366 req->out.size = 4;
2367 smbsrv_send_reply_nosign(req);
2368 return;
2370 case NBSSkeepalive:
2371 /* session keepalive - swallow it */
2372 talloc_free(req);
2373 return;
2376 DEBUG(0,("Unexpected NBT session packet (%d)\n", msg_type));
2377 talloc_free(req);