s3: Optimize g_lock_lock for a heavily contended case
[Samba.git] / source4 / smb_server / smb / reply.c
blob104caca4460acf162878825c754cd740267169c9
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"
32 /****************************************************************************
33 Reply to a simple request (async send)
34 ****************************************************************************/
35 static void reply_simple_send(struct ntvfs_request *ntvfs)
37 struct smbsrv_request *req;
39 SMBSRV_CHECK_ASYNC_STATUS_SIMPLE;
41 smbsrv_setup_reply(req, 0, 0);
42 smbsrv_send_reply(req);
46 /****************************************************************************
47 Reply to a tcon (async reply)
48 ****************************************************************************/
49 static void reply_tcon_send(struct ntvfs_request *ntvfs)
51 struct smbsrv_request *req;
52 union smb_tcon *con;
54 SMBSRV_CHECK_ASYNC_STATUS(con, union smb_tcon);
56 /* construct reply */
57 smbsrv_setup_reply(req, 2, 0);
59 SSVAL(req->out.vwv, VWV(0), con->tcon.out.max_xmit);
60 SSVAL(req->out.vwv, VWV(1), con->tcon.out.tid);
61 SSVAL(req->out.hdr, HDR_TID, req->tcon->tid);
63 smbsrv_send_reply(req);
66 /****************************************************************************
67 Reply to a tcon.
68 ****************************************************************************/
69 void smbsrv_reply_tcon(struct smbsrv_request *req)
71 union smb_tcon *con;
72 NTSTATUS status;
73 uint8_t *p;
75 /* parse request */
76 SMBSRV_CHECK_WCT(req, 0);
78 SMBSRV_TALLOC_IO_PTR(con, union smb_tcon);
80 con->tcon.level = RAW_TCON_TCON;
82 p = req->in.data;
83 p += req_pull_ascii4(&req->in.bufinfo, &con->tcon.in.service, p, STR_TERMINATE);
84 p += req_pull_ascii4(&req->in.bufinfo, &con->tcon.in.password, p, STR_TERMINATE);
85 p += req_pull_ascii4(&req->in.bufinfo, &con->tcon.in.dev, p, STR_TERMINATE);
87 if (!con->tcon.in.service || !con->tcon.in.password || !con->tcon.in.dev) {
88 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
89 return;
92 /* Instantiate backend */
93 status = smbsrv_tcon_backend(req, con);
94 if (!NT_STATUS_IS_OK(status)) {
95 smbsrv_send_error(req, status);
96 return;
99 SMBSRV_SETUP_NTVFS_REQUEST(reply_tcon_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
101 /* Invoke NTVFS connection hook */
102 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_connect(req->ntvfs, con));
106 /****************************************************************************
107 Reply to a tcon and X (async reply)
108 ****************************************************************************/
109 static void reply_tcon_and_X_send(struct ntvfs_request *ntvfs)
111 struct smbsrv_request *req;
112 union smb_tcon *con;
114 SMBSRV_CHECK_ASYNC_STATUS(con, union smb_tcon);
116 /* construct reply - two variants */
117 if (req->smb_conn->negotiate.protocol < PROTOCOL_NT1) {
118 smbsrv_setup_reply(req, 2, 0);
120 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
121 SSVAL(req->out.vwv, VWV(1), 0);
123 req_push_str(req, NULL, con->tconx.out.dev_type, -1, STR_TERMINATE|STR_ASCII);
124 } else {
125 smbsrv_setup_reply(req, 3, 0);
127 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
128 SSVAL(req->out.vwv, VWV(1), 0);
129 SSVAL(req->out.vwv, VWV(2), con->tconx.out.options);
131 req_push_str(req, NULL, con->tconx.out.dev_type, -1, STR_TERMINATE|STR_ASCII);
132 req_push_str(req, NULL, con->tconx.out.fs_type, -1, STR_TERMINATE);
135 /* set the incoming and outgoing tid to the just created one */
136 SSVAL(req->in.hdr, HDR_TID, con->tconx.out.tid);
137 SSVAL(req->out.hdr,HDR_TID, con->tconx.out.tid);
139 smbsrv_chain_reply(req);
142 /****************************************************************************
143 Reply to a tcon and X.
144 ****************************************************************************/
145 void smbsrv_reply_tcon_and_X(struct smbsrv_request *req)
147 NTSTATUS status;
148 union smb_tcon *con;
149 uint8_t *p;
150 uint16_t passlen;
152 SMBSRV_TALLOC_IO_PTR(con, union smb_tcon);
154 con->tconx.level = RAW_TCON_TCONX;
156 /* parse request */
157 SMBSRV_CHECK_WCT(req, 4);
159 con->tconx.in.flags = SVAL(req->in.vwv, VWV(2));
160 passlen = SVAL(req->in.vwv, VWV(3));
162 p = req->in.data;
164 if (!req_pull_blob(&req->in.bufinfo, p, passlen, &con->tconx.in.password)) {
165 smbsrv_send_error(req, NT_STATUS_ILL_FORMED_PASSWORD);
166 return;
168 p += passlen;
170 p += req_pull_string(&req->in.bufinfo, &con->tconx.in.path, p, -1, STR_TERMINATE);
171 p += req_pull_string(&req->in.bufinfo, &con->tconx.in.device, p, -1, STR_ASCII);
173 if (!con->tconx.in.path || !con->tconx.in.device) {
174 smbsrv_send_error(req, NT_STATUS_BAD_DEVICE_TYPE);
175 return;
178 /* Instantiate backend */
179 status = smbsrv_tcon_backend(req, con);
180 if (!NT_STATUS_IS_OK(status)) {
181 smbsrv_send_error(req, status);
182 return;
185 SMBSRV_SETUP_NTVFS_REQUEST(reply_tcon_and_X_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
187 /* Invoke NTVFS connection hook */
188 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_connect(req->ntvfs, con));
192 /****************************************************************************
193 Reply to an unknown request
194 ****************************************************************************/
195 void smbsrv_reply_unknown(struct smbsrv_request *req)
197 int type;
199 type = CVAL(req->in.hdr, HDR_COM);
201 DEBUG(0,("unknown command type %d (0x%X)\n", type, type));
203 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRunknownsmb));
207 /****************************************************************************
208 Reply to an ioctl (async reply)
209 ****************************************************************************/
210 static void reply_ioctl_send(struct ntvfs_request *ntvfs)
212 struct smbsrv_request *req;
213 union smb_ioctl *io;
215 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_ioctl);
217 /* the +1 is for nicer alignment */
218 smbsrv_setup_reply(req, 8, io->ioctl.out.blob.length+1);
219 SSVAL(req->out.vwv, VWV(1), io->ioctl.out.blob.length);
220 SSVAL(req->out.vwv, VWV(5), io->ioctl.out.blob.length);
221 SSVAL(req->out.vwv, VWV(6), PTR_DIFF(req->out.data, req->out.hdr) + 1);
223 memcpy(req->out.data+1, io->ioctl.out.blob.data, io->ioctl.out.blob.length);
225 smbsrv_send_reply(req);
228 /****************************************************************************
229 Reply to an ioctl.
230 ****************************************************************************/
231 void smbsrv_reply_ioctl(struct smbsrv_request *req)
233 union smb_ioctl *io;
235 /* parse request */
236 SMBSRV_CHECK_WCT(req, 3);
237 SMBSRV_TALLOC_IO_PTR(io, union smb_ioctl);
238 SMBSRV_SETUP_NTVFS_REQUEST(reply_ioctl_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
240 io->ioctl.level = RAW_IOCTL_IOCTL;
241 io->ioctl.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
242 io->ioctl.in.request = IVAL(req->in.vwv, VWV(1));
244 SMBSRV_CHECK_FILE_HANDLE_ERROR(io->ioctl.in.file.ntvfs,
245 NT_STATUS_DOS(ERRSRV, ERRerror));
246 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_ioctl(req->ntvfs, io));
250 /****************************************************************************
251 Reply to a chkpth.
252 ****************************************************************************/
253 void smbsrv_reply_chkpth(struct smbsrv_request *req)
255 union smb_chkpath *io;
257 SMBSRV_TALLOC_IO_PTR(io, union smb_chkpath);
258 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
260 req_pull_ascii4(&req->in.bufinfo, &io->chkpath.in.path, req->in.data, STR_TERMINATE);
262 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_chkpath(req->ntvfs, io));
265 /****************************************************************************
266 Reply to a getatr (async reply)
267 ****************************************************************************/
268 static void reply_getatr_send(struct ntvfs_request *ntvfs)
270 struct smbsrv_request *req;
271 union smb_fileinfo *st;
273 SMBSRV_CHECK_ASYNC_STATUS(st, union smb_fileinfo);
275 /* construct reply */
276 smbsrv_setup_reply(req, 10, 0);
278 SSVAL(req->out.vwv, VWV(0), st->getattr.out.attrib);
279 srv_push_dos_date3(req->smb_conn, req->out.vwv, VWV(1), st->getattr.out.write_time);
280 SIVAL(req->out.vwv, VWV(3), st->getattr.out.size);
282 SMBSRV_VWV_RESERVED(5, 5);
284 smbsrv_send_reply(req);
288 /****************************************************************************
289 Reply to a getatr.
290 ****************************************************************************/
291 void smbsrv_reply_getatr(struct smbsrv_request *req)
293 union smb_fileinfo *st;
295 SMBSRV_TALLOC_IO_PTR(st, union smb_fileinfo);
296 SMBSRV_SETUP_NTVFS_REQUEST(reply_getatr_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
298 st->getattr.level = RAW_FILEINFO_GETATTR;
300 /* parse request */
301 req_pull_ascii4(&req->in.bufinfo, &st->getattr.in.file.path, req->in.data, STR_TERMINATE);
302 if (!st->getattr.in.file.path) {
303 smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
304 return;
307 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_qpathinfo(req->ntvfs, st));
311 /****************************************************************************
312 Reply to a setatr.
313 ****************************************************************************/
314 void smbsrv_reply_setatr(struct smbsrv_request *req)
316 union smb_setfileinfo *st;
318 /* parse request */
319 SMBSRV_CHECK_WCT(req, 8);
320 SMBSRV_TALLOC_IO_PTR(st, union smb_setfileinfo);
321 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
323 st->setattr.level = RAW_SFILEINFO_SETATTR;
324 st->setattr.in.attrib = SVAL(req->in.vwv, VWV(0));
325 st->setattr.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(1));
327 req_pull_ascii4(&req->in.bufinfo, &st->setattr.in.file.path, req->in.data, STR_TERMINATE);
329 if (!st->setattr.in.file.path) {
330 smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
331 return;
334 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_setpathinfo(req->ntvfs, st));
338 /****************************************************************************
339 Reply to a dskattr (async reply)
340 ****************************************************************************/
341 static void reply_dskattr_send(struct ntvfs_request *ntvfs)
343 struct smbsrv_request *req;
344 union smb_fsinfo *fs;
346 SMBSRV_CHECK_ASYNC_STATUS(fs, union smb_fsinfo);
348 /* construct reply */
349 smbsrv_setup_reply(req, 5, 0);
351 SSVAL(req->out.vwv, VWV(0), fs->dskattr.out.units_total);
352 SSVAL(req->out.vwv, VWV(1), fs->dskattr.out.blocks_per_unit);
353 SSVAL(req->out.vwv, VWV(2), fs->dskattr.out.block_size);
354 SSVAL(req->out.vwv, VWV(3), fs->dskattr.out.units_free);
356 SMBSRV_VWV_RESERVED(4, 1);
358 smbsrv_send_reply(req);
362 /****************************************************************************
363 Reply to a dskattr.
364 ****************************************************************************/
365 void smbsrv_reply_dskattr(struct smbsrv_request *req)
367 union smb_fsinfo *fs;
369 SMBSRV_TALLOC_IO_PTR(fs, union smb_fsinfo);
370 SMBSRV_SETUP_NTVFS_REQUEST(reply_dskattr_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
372 fs->dskattr.level = RAW_QFS_DSKATTR;
374 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_fsinfo(req->ntvfs, fs));
378 /****************************************************************************
379 Reply to an open (async reply)
380 ****************************************************************************/
381 static void reply_open_send(struct ntvfs_request *ntvfs)
383 struct smbsrv_request *req;
384 union smb_open *oi;
386 SMBSRV_CHECK_ASYNC_STATUS(oi, union smb_open);
388 /* construct reply */
389 smbsrv_setup_reply(req, 7, 0);
391 smbsrv_push_fnum(req->out.vwv, VWV(0), oi->openold.out.file.ntvfs);
392 SSVAL(req->out.vwv, VWV(1), oi->openold.out.attrib);
393 srv_push_dos_date3(req->smb_conn, req->out.vwv, VWV(2), oi->openold.out.write_time);
394 SIVAL(req->out.vwv, VWV(4), oi->openold.out.size);
395 SSVAL(req->out.vwv, VWV(6), oi->openold.out.rmode);
397 smbsrv_send_reply(req);
400 /****************************************************************************
401 Reply to an open.
402 ****************************************************************************/
403 void smbsrv_reply_open(struct smbsrv_request *req)
405 union smb_open *oi;
407 /* parse request */
408 SMBSRV_CHECK_WCT(req, 2);
409 SMBSRV_TALLOC_IO_PTR(oi, union smb_open);
410 SMBSRV_SETUP_NTVFS_REQUEST(reply_open_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
412 oi->openold.level = RAW_OPEN_OPEN;
413 oi->openold.in.open_mode = SVAL(req->in.vwv, VWV(0));
414 oi->openold.in.search_attrs = SVAL(req->in.vwv, VWV(1));
416 req_pull_ascii4(&req->in.bufinfo, &oi->openold.in.fname, req->in.data, STR_TERMINATE);
418 if (!oi->openold.in.fname) {
419 smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
420 return;
423 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, oi));
427 /****************************************************************************
428 Reply to an open and X (async reply)
429 ****************************************************************************/
430 static void reply_open_and_X_send(struct ntvfs_request *ntvfs)
432 struct smbsrv_request *req;
433 union smb_open *oi;
435 SMBSRV_CHECK_ASYNC_STATUS(oi, union smb_open);
437 /* build the reply */
438 if (oi->openx.in.flags & OPENX_FLAGS_EXTENDED_RETURN) {
439 smbsrv_setup_reply(req, 19, 0);
440 } else {
441 smbsrv_setup_reply(req, 15, 0);
444 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
445 SSVAL(req->out.vwv, VWV(1), 0);
446 smbsrv_push_fnum(req->out.vwv, VWV(2), oi->openx.out.file.ntvfs);
447 SSVAL(req->out.vwv, VWV(3), oi->openx.out.attrib);
448 srv_push_dos_date3(req->smb_conn, req->out.vwv, VWV(4), oi->openx.out.write_time);
449 SIVAL(req->out.vwv, VWV(6), oi->openx.out.size);
450 SSVAL(req->out.vwv, VWV(8), oi->openx.out.access);
451 SSVAL(req->out.vwv, VWV(9), oi->openx.out.ftype);
452 SSVAL(req->out.vwv, VWV(10),oi->openx.out.devstate);
453 SSVAL(req->out.vwv, VWV(11),oi->openx.out.action);
454 SIVAL(req->out.vwv, VWV(12),oi->openx.out.unique_fid);
455 SSVAL(req->out.vwv, VWV(14),0); /* reserved */
456 if (oi->openx.in.flags & OPENX_FLAGS_EXTENDED_RETURN) {
457 SIVAL(req->out.vwv, VWV(15),oi->openx.out.access_mask);
458 SMBSRV_VWV_RESERVED(17, 2);
461 req->chained_fnum = SVAL(req->out.vwv, VWV(2));
463 smbsrv_chain_reply(req);
467 /****************************************************************************
468 Reply to an open and X.
469 ****************************************************************************/
470 void smbsrv_reply_open_and_X(struct smbsrv_request *req)
472 union smb_open *oi;
474 /* parse the request */
475 SMBSRV_CHECK_WCT(req, 15);
476 SMBSRV_TALLOC_IO_PTR(oi, union smb_open);
477 SMBSRV_SETUP_NTVFS_REQUEST(reply_open_and_X_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
479 oi->openx.level = RAW_OPEN_OPENX;
480 oi->openx.in.flags = SVAL(req->in.vwv, VWV(2));
481 oi->openx.in.open_mode = SVAL(req->in.vwv, VWV(3));
482 oi->openx.in.search_attrs = SVAL(req->in.vwv, VWV(4));
483 oi->openx.in.file_attrs = SVAL(req->in.vwv, VWV(5));
484 oi->openx.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(6));
485 oi->openx.in.open_func = SVAL(req->in.vwv, VWV(8));
486 oi->openx.in.size = IVAL(req->in.vwv, VWV(9));
487 oi->openx.in.timeout = IVAL(req->in.vwv, VWV(11));
489 req_pull_ascii4(&req->in.bufinfo, &oi->openx.in.fname, req->in.data, STR_TERMINATE);
491 if (!oi->openx.in.fname) {
492 smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
493 return;
496 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, oi));
500 /****************************************************************************
501 Reply to a mknew or a create.
502 ****************************************************************************/
503 static void reply_mknew_send(struct ntvfs_request *ntvfs)
505 struct smbsrv_request *req;
506 union smb_open *oi;
508 SMBSRV_CHECK_ASYNC_STATUS(oi, union smb_open);
510 /* build the reply */
511 smbsrv_setup_reply(req, 1, 0);
513 smbsrv_push_fnum(req->out.vwv, VWV(0), oi->mknew.out.file.ntvfs);
515 smbsrv_send_reply(req);
519 /****************************************************************************
520 Reply to a mknew or a create.
521 ****************************************************************************/
522 void smbsrv_reply_mknew(struct smbsrv_request *req)
524 union smb_open *oi;
526 /* parse the request */
527 SMBSRV_CHECK_WCT(req, 3);
528 SMBSRV_TALLOC_IO_PTR(oi, union smb_open);
529 SMBSRV_SETUP_NTVFS_REQUEST(reply_mknew_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
531 if (CVAL(req->in.hdr, HDR_COM) == SMBmknew) {
532 oi->mknew.level = RAW_OPEN_MKNEW;
533 } else {
534 oi->mknew.level = RAW_OPEN_CREATE;
536 oi->mknew.in.attrib = SVAL(req->in.vwv, VWV(0));
537 oi->mknew.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(1));
539 req_pull_ascii4(&req->in.bufinfo, &oi->mknew.in.fname, req->in.data, STR_TERMINATE);
541 if (!oi->mknew.in.fname) {
542 smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
543 return;
546 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, oi));
549 /****************************************************************************
550 Reply to a create temporary file (async reply)
551 ****************************************************************************/
552 static void reply_ctemp_send(struct ntvfs_request *ntvfs)
554 struct smbsrv_request *req;
555 union smb_open *oi;
557 SMBSRV_CHECK_ASYNC_STATUS(oi, union smb_open);
559 /* build the reply */
560 smbsrv_setup_reply(req, 1, 0);
562 smbsrv_push_fnum(req->out.vwv, VWV(0), oi->ctemp.out.file.ntvfs);
564 /* the returned filename is relative to the directory */
565 req_push_str(req, NULL, oi->ctemp.out.name, -1, STR_TERMINATE | STR_ASCII);
567 smbsrv_send_reply(req);
570 /****************************************************************************
571 Reply to a create temporary file.
572 ****************************************************************************/
573 void smbsrv_reply_ctemp(struct smbsrv_request *req)
575 union smb_open *oi;
577 /* parse the request */
578 SMBSRV_CHECK_WCT(req, 3);
579 SMBSRV_TALLOC_IO_PTR(oi, union smb_open);
580 SMBSRV_SETUP_NTVFS_REQUEST(reply_ctemp_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
582 oi->ctemp.level = RAW_OPEN_CTEMP;
583 oi->ctemp.in.attrib = SVAL(req->in.vwv, VWV(0));
584 oi->ctemp.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(1));
586 /* the filename is actually a directory name, the server provides a filename
587 in that directory */
588 req_pull_ascii4(&req->in.bufinfo, &oi->ctemp.in.directory, req->in.data, STR_TERMINATE);
590 if (!oi->ctemp.in.directory) {
591 smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
592 return;
595 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, oi));
599 /****************************************************************************
600 Reply to a unlink
601 ****************************************************************************/
602 void smbsrv_reply_unlink(struct smbsrv_request *req)
604 union smb_unlink *unl;
606 /* parse the request */
607 SMBSRV_CHECK_WCT(req, 1);
608 SMBSRV_TALLOC_IO_PTR(unl, union smb_unlink);
609 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
611 unl->unlink.in.attrib = SVAL(req->in.vwv, VWV(0));
613 req_pull_ascii4(&req->in.bufinfo, &unl->unlink.in.pattern, req->in.data, STR_TERMINATE);
615 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_unlink(req->ntvfs, unl));
619 /****************************************************************************
620 Reply to a readbraw (core+ protocol).
621 this is a strange packet because it doesn't use a standard SMB header in the reply,
622 only the 4 byte NBT header
623 This command must be replied to synchronously
624 ****************************************************************************/
625 void smbsrv_reply_readbraw(struct smbsrv_request *req)
627 NTSTATUS status;
628 union smb_read io;
630 io.readbraw.level = RAW_READ_READBRAW;
632 /* there are two variants, one with 10 and one with 8 command words */
633 if (req->in.wct < 8) {
634 goto failed;
637 io.readbraw.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
638 io.readbraw.in.offset = IVAL(req->in.vwv, VWV(1));
639 io.readbraw.in.maxcnt = SVAL(req->in.vwv, VWV(3));
640 io.readbraw.in.mincnt = SVAL(req->in.vwv, VWV(4));
641 io.readbraw.in.timeout = IVAL(req->in.vwv, VWV(5));
643 if (!io.readbraw.in.file.ntvfs) {
644 goto failed;
647 /* the 64 bit variant */
648 if (req->in.wct == 10) {
649 uint32_t offset_high = IVAL(req->in.vwv, VWV(8));
650 io.readbraw.in.offset |= (((off_t)offset_high) << 32);
653 /* before calling the backend we setup the raw buffer. This
654 * saves a copy later */
655 req->out.size = io.readbraw.in.maxcnt + NBT_HDR_SIZE;
656 req->out.buffer = talloc_size(req, req->out.size);
657 if (req->out.buffer == NULL) {
658 goto failed;
660 SIVAL(req->out.buffer, 0, 0); /* init NBT header */
662 /* tell the backend where to put the data */
663 io.readbraw.out.data = req->out.buffer + NBT_HDR_SIZE;
665 /* prepare the ntvfs request */
666 req->ntvfs = ntvfs_request_create(req->tcon->ntvfs, req,
667 req->session->session_info,
668 SVAL(req->in.hdr,HDR_PID),
669 req->request_time,
670 req, NULL, 0);
671 if (!req->ntvfs) {
672 goto failed;
675 /* call the backend */
676 status = ntvfs_read(req->ntvfs, &io);
677 if (!NT_STATUS_IS_OK(status)) {
678 goto failed;
681 req->out.size = io.readbraw.out.nread + NBT_HDR_SIZE;
683 smbsrv_send_reply_nosign(req);
684 return;
686 failed:
687 /* any failure in readbraw is equivalent to reading zero bytes */
688 req->out.size = 4;
689 req->out.buffer = talloc_size(req, req->out.size);
690 SIVAL(req->out.buffer, 0, 0); /* init NBT header */
692 smbsrv_send_reply_nosign(req);
696 /****************************************************************************
697 Reply to a lockread (async reply)
698 ****************************************************************************/
699 static void reply_lockread_send(struct ntvfs_request *ntvfs)
701 struct smbsrv_request *req;
702 union smb_read *io;
704 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_read);
706 /* trim packet */
707 io->lockread.out.nread = MIN(io->lockread.out.nread,
708 req_max_data(req) - 3);
709 req_grow_data(req, 3 + io->lockread.out.nread);
711 /* construct reply */
712 SSVAL(req->out.vwv, VWV(0), io->lockread.out.nread);
713 SMBSRV_VWV_RESERVED(1, 4);
715 SCVAL(req->out.data, 0, SMB_DATA_BLOCK);
716 SSVAL(req->out.data, 1, io->lockread.out.nread);
718 smbsrv_send_reply(req);
722 /****************************************************************************
723 Reply to a lockread (core+ protocol).
724 note that the lock is a write lock, not a read lock!
725 ****************************************************************************/
726 void smbsrv_reply_lockread(struct smbsrv_request *req)
728 union smb_read *io;
730 /* parse request */
731 SMBSRV_CHECK_WCT(req, 5);
732 SMBSRV_TALLOC_IO_PTR(io, union smb_read);
733 SMBSRV_SETUP_NTVFS_REQUEST(reply_lockread_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
735 io->lockread.level = RAW_READ_LOCKREAD;
736 io->lockread.in.file.ntvfs= smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
737 io->lockread.in.count = SVAL(req->in.vwv, VWV(1));
738 io->lockread.in.offset = IVAL(req->in.vwv, VWV(2));
739 io->lockread.in.remaining = SVAL(req->in.vwv, VWV(4));
741 /* setup the reply packet assuming the maximum possible read */
742 smbsrv_setup_reply(req, 5, 3 + io->lockread.in.count);
744 /* tell the backend where to put the data */
745 io->lockread.out.data = req->out.data + 3;
747 SMBSRV_CHECK_FILE_HANDLE(io->lockread.in.file.ntvfs);
748 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_read(req->ntvfs, io));
753 /****************************************************************************
754 Reply to a read (async reply)
755 ****************************************************************************/
756 static void reply_read_send(struct ntvfs_request *ntvfs)
758 struct smbsrv_request *req;
759 union smb_read *io;
761 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_read);
763 /* trim packet */
764 io->read.out.nread = MIN(io->read.out.nread,
765 req_max_data(req) - 3);
766 req_grow_data(req, 3 + io->read.out.nread);
768 /* construct reply */
769 SSVAL(req->out.vwv, VWV(0), io->read.out.nread);
770 SMBSRV_VWV_RESERVED(1, 4);
772 SCVAL(req->out.data, 0, SMB_DATA_BLOCK);
773 SSVAL(req->out.data, 1, io->read.out.nread);
775 smbsrv_send_reply(req);
778 /****************************************************************************
779 Reply to a read.
780 ****************************************************************************/
781 void smbsrv_reply_read(struct smbsrv_request *req)
783 union smb_read *io;
785 /* parse request */
786 SMBSRV_CHECK_WCT(req, 5);
787 SMBSRV_TALLOC_IO_PTR(io, union smb_read);
788 SMBSRV_SETUP_NTVFS_REQUEST(reply_read_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
790 io->read.level = RAW_READ_READ;
791 io->read.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
792 io->read.in.count = SVAL(req->in.vwv, VWV(1));
793 io->read.in.offset = IVAL(req->in.vwv, VWV(2));
794 io->read.in.remaining = SVAL(req->in.vwv, VWV(4));
796 /* setup the reply packet assuming the maximum possible read */
797 smbsrv_setup_reply(req, 5, 3 + io->read.in.count);
799 /* tell the backend where to put the data */
800 io->read.out.data = req->out.data + 3;
802 SMBSRV_CHECK_FILE_HANDLE(io->read.in.file.ntvfs);
803 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_read(req->ntvfs, io));
806 /****************************************************************************
807 Reply to a read and X (async reply)
808 ****************************************************************************/
809 static void reply_read_and_X_send(struct ntvfs_request *ntvfs)
811 struct smbsrv_request *req;
812 union smb_read *io;
814 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_read);
816 /* readx reply packets can be over-sized */
817 req->control_flags |= SMBSRV_REQ_CONTROL_LARGE;
818 if (io->readx.in.maxcnt != 0xFFFF &&
819 io->readx.in.mincnt != 0xFFFF) {
820 req_grow_data(req, 1 + io->readx.out.nread);
821 SCVAL(req->out.data, 0, 0); /* padding */
822 } else {
823 req_grow_data(req, io->readx.out.nread);
826 /* construct reply */
827 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
828 SSVAL(req->out.vwv, VWV(1), 0);
829 SSVAL(req->out.vwv, VWV(2), io->readx.out.remaining);
830 SSVAL(req->out.vwv, VWV(3), io->readx.out.compaction_mode);
831 SMBSRV_VWV_RESERVED(4, 1);
832 SSVAL(req->out.vwv, VWV(5), io->readx.out.nread);
833 SSVAL(req->out.vwv, VWV(6), PTR_DIFF(io->readx.out.data, req->out.hdr));
834 SSVAL(req->out.vwv, VWV(7), (io->readx.out.nread>>16));
835 SMBSRV_VWV_RESERVED(8, 4);
837 smbsrv_chain_reply(req);
840 /****************************************************************************
841 Reply to a read and X.
842 ****************************************************************************/
843 void smbsrv_reply_read_and_X(struct smbsrv_request *req)
845 union smb_read *io;
847 /* parse request */
848 if (req->in.wct != 12) {
849 SMBSRV_CHECK_WCT(req, 10);
852 SMBSRV_TALLOC_IO_PTR(io, union smb_read);
853 SMBSRV_SETUP_NTVFS_REQUEST(reply_read_and_X_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
855 io->readx.level = RAW_READ_READX;
856 io->readx.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(2));
857 io->readx.in.offset = IVAL(req->in.vwv, VWV(3));
858 io->readx.in.maxcnt = SVAL(req->in.vwv, VWV(5));
859 io->readx.in.mincnt = SVAL(req->in.vwv, VWV(6));
860 io->readx.in.remaining = SVAL(req->in.vwv, VWV(9));
861 if (req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) {
862 io->readx.in.read_for_execute = true;
863 } else {
864 io->readx.in.read_for_execute = false;
867 if (req->smb_conn->negotiate.client_caps & CAP_LARGE_READX) {
868 uint32_t high_part = IVAL(req->in.vwv, VWV(7));
869 if (high_part == 1) {
870 io->readx.in.maxcnt |= high_part << 16;
874 /* the 64 bit variant */
875 if (req->in.wct == 12) {
876 uint32_t offset_high = IVAL(req->in.vwv, VWV(10));
877 io->readx.in.offset |= (((uint64_t)offset_high) << 32);
880 /* setup the reply packet assuming the maximum possible read */
881 smbsrv_setup_reply(req, 12, 1 + io->readx.in.maxcnt);
883 /* tell the backend where to put the data. Notice the pad byte. */
884 if (io->readx.in.maxcnt != 0xFFFF &&
885 io->readx.in.mincnt != 0xFFFF) {
886 io->readx.out.data = req->out.data + 1;
887 } else {
888 io->readx.out.data = req->out.data;
891 SMBSRV_CHECK_FILE_HANDLE(io->readx.in.file.ntvfs);
892 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_read(req->ntvfs, io));
896 /****************************************************************************
897 Reply to a writebraw (core+ or LANMAN1.0 protocol).
898 ****************************************************************************/
899 void smbsrv_reply_writebraw(struct smbsrv_request *req)
901 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRuseSTD));
905 /****************************************************************************
906 Reply to a writeunlock (async reply)
907 ****************************************************************************/
908 static void reply_writeunlock_send(struct ntvfs_request *ntvfs)
910 struct smbsrv_request *req;
911 union smb_write *io;
913 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_write);
915 /* construct reply */
916 smbsrv_setup_reply(req, 1, 0);
918 SSVAL(req->out.vwv, VWV(0), io->writeunlock.out.nwritten);
920 smbsrv_send_reply(req);
923 /****************************************************************************
924 Reply to a writeunlock (core+).
925 ****************************************************************************/
926 void smbsrv_reply_writeunlock(struct smbsrv_request *req)
928 union smb_write *io;
930 SMBSRV_CHECK_WCT(req, 5);
931 SMBSRV_TALLOC_IO_PTR(io, union smb_write);
932 SMBSRV_SETUP_NTVFS_REQUEST(reply_writeunlock_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
934 io->writeunlock.level = RAW_WRITE_WRITEUNLOCK;
935 io->writeunlock.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
936 io->writeunlock.in.count = SVAL(req->in.vwv, VWV(1));
937 io->writeunlock.in.offset = IVAL(req->in.vwv, VWV(2));
938 io->writeunlock.in.remaining = SVAL(req->in.vwv, VWV(4));
939 io->writeunlock.in.data = req->in.data + 3;
941 /* make sure they gave us the data they promised */
942 if (io->writeunlock.in.count+3 > req->in.data_size) {
943 smbsrv_send_error(req, NT_STATUS_FOOBAR);
944 return;
947 /* make sure the data block is big enough */
948 if (SVAL(req->in.data, 1) < io->writeunlock.in.count) {
949 smbsrv_send_error(req, NT_STATUS_FOOBAR);
950 return;
953 SMBSRV_CHECK_FILE_HANDLE(io->writeunlock.in.file.ntvfs);
954 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
959 /****************************************************************************
960 Reply to a write (async reply)
961 ****************************************************************************/
962 static void reply_write_send(struct ntvfs_request *ntvfs)
964 struct smbsrv_request *req;
965 union smb_write *io;
967 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_write);
969 /* construct reply */
970 smbsrv_setup_reply(req, 1, 0);
972 SSVAL(req->out.vwv, VWV(0), io->write.out.nwritten);
974 smbsrv_send_reply(req);
977 /****************************************************************************
978 Reply to a write
979 ****************************************************************************/
980 void smbsrv_reply_write(struct smbsrv_request *req)
982 union smb_write *io;
984 SMBSRV_CHECK_WCT(req, 5);
985 SMBSRV_TALLOC_IO_PTR(io, union smb_write);
986 SMBSRV_SETUP_NTVFS_REQUEST(reply_write_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
988 io->write.level = RAW_WRITE_WRITE;
989 io->write.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
990 io->write.in.count = SVAL(req->in.vwv, VWV(1));
991 io->write.in.offset = IVAL(req->in.vwv, VWV(2));
992 io->write.in.remaining = SVAL(req->in.vwv, VWV(4));
993 io->write.in.data = req->in.data + 3;
995 /* make sure they gave us the data they promised */
996 if (req_data_oob(&req->in.bufinfo, io->write.in.data, io->write.in.count)) {
997 smbsrv_send_error(req, NT_STATUS_FOOBAR);
998 return;
1001 /* make sure the data block is big enough */
1002 if (SVAL(req->in.data, 1) < io->write.in.count) {
1003 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1004 return;
1007 SMBSRV_CHECK_FILE_HANDLE(io->write.in.file.ntvfs);
1008 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
1012 /****************************************************************************
1013 Reply to a write and X (async reply)
1014 ****************************************************************************/
1015 static void reply_write_and_X_send(struct ntvfs_request *ntvfs)
1017 struct smbsrv_request *req;
1018 union smb_write *io;
1020 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_write);
1022 /* construct reply */
1023 smbsrv_setup_reply(req, 6, 0);
1025 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1026 SSVAL(req->out.vwv, VWV(1), 0);
1027 SSVAL(req->out.vwv, VWV(2), io->writex.out.nwritten & 0xFFFF);
1028 SSVAL(req->out.vwv, VWV(3), io->writex.out.remaining);
1029 SSVAL(req->out.vwv, VWV(4), io->writex.out.nwritten >> 16);
1030 SMBSRV_VWV_RESERVED(5, 1);
1032 smbsrv_chain_reply(req);
1035 /****************************************************************************
1036 Reply to a write and X.
1037 ****************************************************************************/
1038 void smbsrv_reply_write_and_X(struct smbsrv_request *req)
1040 union smb_write *io;
1042 if (req->in.wct != 14) {
1043 SMBSRV_CHECK_WCT(req, 12);
1046 SMBSRV_TALLOC_IO_PTR(io, union smb_write);
1047 SMBSRV_SETUP_NTVFS_REQUEST(reply_write_and_X_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1049 io->writex.level = RAW_WRITE_WRITEX;
1050 io->writex.in.file.ntvfs= smbsrv_pull_fnum(req, req->in.vwv, VWV(2));
1051 io->writex.in.offset = IVAL(req->in.vwv, VWV(3));
1052 io->writex.in.wmode = SVAL(req->in.vwv, VWV(7));
1053 io->writex.in.remaining = SVAL(req->in.vwv, VWV(8));
1054 io->writex.in.count = SVAL(req->in.vwv, VWV(10));
1055 io->writex.in.data = req->in.hdr + SVAL(req->in.vwv, VWV(11));
1057 if (req->in.wct == 14) {
1058 uint32_t offset_high = IVAL(req->in.vwv, VWV(12));
1059 uint16_t count_high = SVAL(req->in.vwv, VWV(9));
1060 io->writex.in.offset |= (((uint64_t)offset_high) << 32);
1061 io->writex.in.count |= ((uint32_t)count_high) << 16;
1064 /* make sure the data is in bounds */
1065 if (req_data_oob(&req->in.bufinfo, io->writex.in.data, io->writex.in.count)) {
1066 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
1067 return;
1070 SMBSRV_CHECK_FILE_HANDLE(io->writex.in.file.ntvfs);
1071 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
1075 /****************************************************************************
1076 Reply to a lseek (async reply)
1077 ****************************************************************************/
1078 static void reply_lseek_send(struct ntvfs_request *ntvfs)
1080 struct smbsrv_request *req;
1081 union smb_seek *io;
1083 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_seek);
1085 /* construct reply */
1086 smbsrv_setup_reply(req, 2, 0);
1088 SIVALS(req->out.vwv, VWV(0), io->lseek.out.offset);
1090 smbsrv_send_reply(req);
1093 /****************************************************************************
1094 Reply to a lseek.
1095 ****************************************************************************/
1096 void smbsrv_reply_lseek(struct smbsrv_request *req)
1098 union smb_seek *io;
1100 SMBSRV_CHECK_WCT(req, 4);
1101 SMBSRV_TALLOC_IO_PTR(io, union smb_seek);
1102 SMBSRV_SETUP_NTVFS_REQUEST(reply_lseek_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1104 io->lseek.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1105 io->lseek.in.mode = SVAL(req->in.vwv, VWV(1));
1106 io->lseek.in.offset = IVALS(req->in.vwv, VWV(2));
1108 SMBSRV_CHECK_FILE_HANDLE(io->lseek.in.file.ntvfs);
1109 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_seek(req->ntvfs, io));
1112 /****************************************************************************
1113 Reply to a flush.
1114 ****************************************************************************/
1115 void smbsrv_reply_flush(struct smbsrv_request *req)
1117 union smb_flush *io;
1118 uint16_t fnum;
1120 /* parse request */
1121 SMBSRV_CHECK_WCT(req, 1);
1122 SMBSRV_TALLOC_IO_PTR(io, union smb_flush);
1123 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1125 fnum = SVAL(req->in.vwv, VWV(0));
1126 if (fnum == 0xFFFF) {
1127 io->flush_all.level = RAW_FLUSH_ALL;
1128 } else {
1129 io->flush.level = RAW_FLUSH_FLUSH;
1130 io->flush.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1131 SMBSRV_CHECK_FILE_HANDLE(io->flush.in.file.ntvfs);
1134 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_flush(req->ntvfs, io));
1137 /****************************************************************************
1138 Reply to a close
1140 Note that this has to deal with closing a directory opened by NT SMB's.
1141 ****************************************************************************/
1142 void smbsrv_reply_close(struct smbsrv_request *req)
1144 union smb_close *io;
1146 /* parse request */
1147 SMBSRV_CHECK_WCT(req, 3);
1148 SMBSRV_TALLOC_IO_PTR(io, union smb_close);
1149 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1151 io->close.level = RAW_CLOSE_CLOSE;
1152 io->close.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1153 io->close.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(1));
1155 SMBSRV_CHECK_FILE_HANDLE(io->close.in.file.ntvfs);
1156 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_close(req->ntvfs, io));
1160 /****************************************************************************
1161 Reply to a writeclose (async reply)
1162 ****************************************************************************/
1163 static void reply_writeclose_send(struct ntvfs_request *ntvfs)
1165 struct smbsrv_request *req;
1166 union smb_write *io;
1168 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_write);
1170 /* construct reply */
1171 smbsrv_setup_reply(req, 1, 0);
1173 SSVAL(req->out.vwv, VWV(0), io->write.out.nwritten);
1175 smbsrv_send_reply(req);
1178 /****************************************************************************
1179 Reply to a writeclose (Core+ protocol).
1180 ****************************************************************************/
1181 void smbsrv_reply_writeclose(struct smbsrv_request *req)
1183 union smb_write *io;
1185 /* this one is pretty weird - the wct can be 6 or 12 */
1186 if (req->in.wct != 12) {
1187 SMBSRV_CHECK_WCT(req, 6);
1190 SMBSRV_TALLOC_IO_PTR(io, union smb_write);
1191 SMBSRV_SETUP_NTVFS_REQUEST(reply_writeclose_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1193 io->writeclose.level = RAW_WRITE_WRITECLOSE;
1194 io->writeclose.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1195 io->writeclose.in.count = SVAL(req->in.vwv, VWV(1));
1196 io->writeclose.in.offset = IVAL(req->in.vwv, VWV(2));
1197 io->writeclose.in.mtime = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(4));
1198 io->writeclose.in.data = req->in.data + 1;
1200 /* make sure they gave us the data they promised */
1201 if (req_data_oob(&req->in.bufinfo, io->writeclose.in.data, io->writeclose.in.count)) {
1202 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1203 return;
1206 SMBSRV_CHECK_FILE_HANDLE(io->writeclose.in.file.ntvfs);
1207 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
1210 /****************************************************************************
1211 Reply to a lock.
1212 ****************************************************************************/
1213 void smbsrv_reply_lock(struct smbsrv_request *req)
1215 union smb_lock *lck;
1217 /* parse request */
1218 SMBSRV_CHECK_WCT(req, 5);
1219 SMBSRV_TALLOC_IO_PTR(lck, union smb_lock);
1220 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1222 lck->lock.level = RAW_LOCK_LOCK;
1223 lck->lock.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1224 lck->lock.in.count = IVAL(req->in.vwv, VWV(1));
1225 lck->lock.in.offset = IVAL(req->in.vwv, VWV(3));
1227 SMBSRV_CHECK_FILE_HANDLE(lck->lock.in.file.ntvfs);
1228 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_lock(req->ntvfs, lck));
1232 /****************************************************************************
1233 Reply to a unlock.
1234 ****************************************************************************/
1235 void smbsrv_reply_unlock(struct smbsrv_request *req)
1237 union smb_lock *lck;
1239 /* parse request */
1240 SMBSRV_CHECK_WCT(req, 5);
1241 SMBSRV_TALLOC_IO_PTR(lck, union smb_lock);
1242 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1244 lck->unlock.level = RAW_LOCK_UNLOCK;
1245 lck->unlock.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1246 lck->unlock.in.count = IVAL(req->in.vwv, VWV(1));
1247 lck->unlock.in.offset = IVAL(req->in.vwv, VWV(3));
1249 SMBSRV_CHECK_FILE_HANDLE(lck->unlock.in.file.ntvfs);
1250 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_lock(req->ntvfs, lck));
1254 /****************************************************************************
1255 Reply to a tdis.
1256 ****************************************************************************/
1257 void smbsrv_reply_tdis(struct smbsrv_request *req)
1259 struct smbsrv_handle *h, *nh;
1261 SMBSRV_CHECK_WCT(req, 0);
1264 * TODO: cancel all pending requests on this tcon
1268 * close all handles on this tcon
1270 for (h=req->tcon->handles.list; h; h=nh) {
1271 nh = h->next;
1272 talloc_free(h);
1275 /* finally destroy the tcon */
1276 talloc_free(req->tcon);
1277 req->tcon = NULL;
1279 smbsrv_setup_reply(req, 0, 0);
1280 smbsrv_send_reply(req);
1284 /****************************************************************************
1285 Reply to a echo. This is one of the few calls that is handled directly (the
1286 backends don't see it at all)
1287 ****************************************************************************/
1288 void smbsrv_reply_echo(struct smbsrv_request *req)
1290 uint16_t count;
1291 int i;
1293 SMBSRV_CHECK_WCT(req, 1);
1295 count = SVAL(req->in.vwv, VWV(0));
1297 smbsrv_setup_reply(req, 1, req->in.data_size);
1299 memcpy(req->out.data, req->in.data, req->in.data_size);
1301 for (i=1; i <= count;i++) {
1302 struct smbsrv_request *this_req;
1304 if (i != count) {
1305 this_req = smbsrv_setup_secondary_request(req);
1306 } else {
1307 this_req = req;
1310 SSVAL(this_req->out.vwv, VWV(0), i);
1311 smbsrv_send_reply(this_req);
1317 /****************************************************************************
1318 Reply to a printopen (async reply)
1319 ****************************************************************************/
1320 static void reply_printopen_send(struct ntvfs_request *ntvfs)
1322 struct smbsrv_request *req;
1323 union smb_open *oi;
1325 SMBSRV_CHECK_ASYNC_STATUS(oi, union smb_open);
1327 /* construct reply */
1328 smbsrv_setup_reply(req, 1, 0);
1330 smbsrv_push_fnum(req->out.vwv, VWV(0), oi->openold.out.file.ntvfs);
1332 smbsrv_send_reply(req);
1335 /****************************************************************************
1336 Reply to a printopen.
1337 ****************************************************************************/
1338 void smbsrv_reply_printopen(struct smbsrv_request *req)
1340 union smb_open *oi;
1342 /* parse request */
1343 SMBSRV_CHECK_WCT(req, 2);
1344 SMBSRV_TALLOC_IO_PTR(oi, union smb_open);
1345 SMBSRV_SETUP_NTVFS_REQUEST(reply_printopen_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1347 oi->splopen.level = RAW_OPEN_SPLOPEN;
1348 oi->splopen.in.setup_length = SVAL(req->in.vwv, VWV(0));
1349 oi->splopen.in.mode = SVAL(req->in.vwv, VWV(1));
1351 req_pull_ascii4(&req->in.bufinfo, &oi->splopen.in.ident, req->in.data, STR_TERMINATE);
1353 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, oi));
1356 /****************************************************************************
1357 Reply to a printclose.
1358 ****************************************************************************/
1359 void smbsrv_reply_printclose(struct smbsrv_request *req)
1361 union smb_close *io;
1363 /* parse request */
1364 SMBSRV_CHECK_WCT(req, 3);
1365 SMBSRV_TALLOC_IO_PTR(io, union smb_close);
1366 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1368 io->splclose.level = RAW_CLOSE_SPLCLOSE;
1369 io->splclose.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1371 SMBSRV_CHECK_FILE_HANDLE(io->splclose.in.file.ntvfs);
1372 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_close(req->ntvfs, io));
1375 /****************************************************************************
1376 Reply to a printqueue.
1377 ****************************************************************************/
1378 static void reply_printqueue_send(struct ntvfs_request *ntvfs)
1380 struct smbsrv_request *req;
1381 union smb_lpq *lpq;
1382 int i, maxcount;
1383 const uint_t el_size = 28;
1385 SMBSRV_CHECK_ASYNC_STATUS(lpq,union smb_lpq);
1387 /* construct reply */
1388 smbsrv_setup_reply(req, 2, 0);
1390 /* truncate the returned list to fit in the negotiated buffer size */
1391 maxcount = (req_max_data(req) - 3) / el_size;
1392 if (maxcount < lpq->retq.out.count) {
1393 lpq->retq.out.count = maxcount;
1396 /* setup enough space in the reply */
1397 req_grow_data(req, 3 + el_size*lpq->retq.out.count);
1399 /* and fill it in */
1400 SSVAL(req->out.vwv, VWV(0), lpq->retq.out.count);
1401 SSVAL(req->out.vwv, VWV(1), lpq->retq.out.restart_idx);
1403 SCVAL(req->out.data, 0, SMB_DATA_BLOCK);
1404 SSVAL(req->out.data, 1, el_size*lpq->retq.out.count);
1406 req->out.ptr = req->out.data + 3;
1408 for (i=0;i<lpq->retq.out.count;i++) {
1409 srv_push_dos_date2(req->smb_conn, req->out.ptr, 0 , lpq->retq.out.queue[i].time);
1410 SCVAL(req->out.ptr, 4, lpq->retq.out.queue[i].status);
1411 SSVAL(req->out.ptr, 5, lpq->retq.out.queue[i].job);
1412 SIVAL(req->out.ptr, 7, lpq->retq.out.queue[i].size);
1413 SCVAL(req->out.ptr, 11, 0); /* reserved */
1414 req_push_str(req, req->out.ptr+12, lpq->retq.out.queue[i].user, 16, STR_ASCII);
1415 req->out.ptr += el_size;
1418 smbsrv_send_reply(req);
1421 /****************************************************************************
1422 Reply to a printqueue.
1423 ****************************************************************************/
1424 void smbsrv_reply_printqueue(struct smbsrv_request *req)
1426 union smb_lpq *lpq;
1428 /* parse request */
1429 SMBSRV_CHECK_WCT(req, 2);
1430 SMBSRV_TALLOC_IO_PTR(lpq, union smb_lpq);
1431 SMBSRV_SETUP_NTVFS_REQUEST(reply_printqueue_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1433 lpq->retq.level = RAW_LPQ_RETQ;
1434 lpq->retq.in.maxcount = SVAL(req->in.vwv, VWV(0));
1435 lpq->retq.in.startidx = SVAL(req->in.vwv, VWV(1));
1437 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_lpq(req->ntvfs, lpq));
1441 /****************************************************************************
1442 Reply to a printwrite.
1443 ****************************************************************************/
1444 void smbsrv_reply_printwrite(struct smbsrv_request *req)
1446 union smb_write *io;
1448 /* parse request */
1449 SMBSRV_CHECK_WCT(req, 1);
1450 SMBSRV_TALLOC_IO_PTR(io, union smb_write);
1451 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1453 if (req->in.data_size < 3) {
1454 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1455 return;
1458 io->splwrite.level = RAW_WRITE_SPLWRITE;
1459 io->splwrite.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1460 io->splwrite.in.count = SVAL(req->in.data, 1);
1461 io->splwrite.in.data = req->in.data + 3;
1463 /* make sure they gave us the data they promised */
1464 if (req_data_oob(&req->in.bufinfo, io->splwrite.in.data, io->splwrite.in.count)) {
1465 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1466 return;
1469 SMBSRV_CHECK_FILE_HANDLE(io->splwrite.in.file.ntvfs);
1470 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
1474 /****************************************************************************
1475 Reply to a mkdir.
1476 ****************************************************************************/
1477 void smbsrv_reply_mkdir(struct smbsrv_request *req)
1479 union smb_mkdir *io;
1481 /* parse the request */
1482 SMBSRV_CHECK_WCT(req, 0);
1483 SMBSRV_TALLOC_IO_PTR(io, union smb_mkdir);
1484 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1486 io->generic.level = RAW_MKDIR_MKDIR;
1487 req_pull_ascii4(&req->in.bufinfo, &io->mkdir.in.path, req->in.data, STR_TERMINATE);
1489 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_mkdir(req->ntvfs, io));
1493 /****************************************************************************
1494 Reply to a rmdir.
1495 ****************************************************************************/
1496 void smbsrv_reply_rmdir(struct smbsrv_request *req)
1498 struct smb_rmdir *io;
1500 /* parse the request */
1501 SMBSRV_CHECK_WCT(req, 0);
1502 SMBSRV_TALLOC_IO_PTR(io, struct smb_rmdir);
1503 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1505 req_pull_ascii4(&req->in.bufinfo, &io->in.path, req->in.data, STR_TERMINATE);
1507 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_rmdir(req->ntvfs, io));
1511 /****************************************************************************
1512 Reply to a mv.
1513 ****************************************************************************/
1514 void smbsrv_reply_mv(struct smbsrv_request *req)
1516 union smb_rename *io;
1517 uint8_t *p;
1519 /* parse the request */
1520 SMBSRV_CHECK_WCT(req, 1);
1521 SMBSRV_TALLOC_IO_PTR(io, union smb_rename);
1522 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1524 io->generic.level = RAW_RENAME_RENAME;
1525 io->rename.in.attrib = SVAL(req->in.vwv, VWV(0));
1527 p = req->in.data;
1528 p += req_pull_ascii4(&req->in.bufinfo, &io->rename.in.pattern1, p, STR_TERMINATE);
1529 p += req_pull_ascii4(&req->in.bufinfo, &io->rename.in.pattern2, p, STR_TERMINATE);
1531 if (!io->rename.in.pattern1 || !io->rename.in.pattern2) {
1532 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1533 return;
1536 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_rename(req->ntvfs, io));
1540 /****************************************************************************
1541 Reply to an NT rename.
1542 ****************************************************************************/
1543 void smbsrv_reply_ntrename(struct smbsrv_request *req)
1545 union smb_rename *io;
1546 uint8_t *p;
1548 /* parse the request */
1549 SMBSRV_CHECK_WCT(req, 4);
1550 SMBSRV_TALLOC_IO_PTR(io, union smb_rename);
1551 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1553 io->generic.level = RAW_RENAME_NTRENAME;
1554 io->ntrename.in.attrib = SVAL(req->in.vwv, VWV(0));
1555 io->ntrename.in.flags = SVAL(req->in.vwv, VWV(1));
1556 io->ntrename.in.cluster_size = IVAL(req->in.vwv, VWV(2));
1558 p = req->in.data;
1559 p += req_pull_ascii4(&req->in.bufinfo, &io->ntrename.in.old_name, p, STR_TERMINATE);
1560 p += req_pull_ascii4(&req->in.bufinfo, &io->ntrename.in.new_name, p, STR_TERMINATE);
1562 if (!io->ntrename.in.old_name || !io->ntrename.in.new_name) {
1563 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1564 return;
1567 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_rename(req->ntvfs, io));
1570 /****************************************************************************
1571 Reply to a file copy (async reply)
1572 ****************************************************************************/
1573 static void reply_copy_send(struct ntvfs_request *ntvfs)
1575 struct smbsrv_request *req;
1576 struct smb_copy *cp;
1578 SMBSRV_CHECK_ASYNC_STATUS(cp, struct smb_copy);
1580 /* build the reply */
1581 smbsrv_setup_reply(req, 1, 0);
1583 SSVAL(req->out.vwv, VWV(0), cp->out.count);
1585 smbsrv_send_reply(req);
1588 /****************************************************************************
1589 Reply to a file copy.
1590 ****************************************************************************/
1591 void smbsrv_reply_copy(struct smbsrv_request *req)
1593 struct smb_copy *cp;
1594 uint8_t *p;
1596 /* parse request */
1597 SMBSRV_CHECK_WCT(req, 3);
1598 SMBSRV_TALLOC_IO_PTR(cp, struct smb_copy);
1599 SMBSRV_SETUP_NTVFS_REQUEST(reply_copy_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1601 cp->in.tid2 = SVAL(req->in.vwv, VWV(0));
1602 cp->in.ofun = SVAL(req->in.vwv, VWV(1));
1603 cp->in.flags = SVAL(req->in.vwv, VWV(2));
1605 p = req->in.data;
1606 p += req_pull_ascii4(&req->in.bufinfo, &cp->in.path1, p, STR_TERMINATE);
1607 p += req_pull_ascii4(&req->in.bufinfo, &cp->in.path2, p, STR_TERMINATE);
1609 if (!cp->in.path1 || !cp->in.path2) {
1610 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1611 return;
1614 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_copy(req->ntvfs, cp));
1617 /****************************************************************************
1618 Reply to a lockingX request (async send)
1619 ****************************************************************************/
1620 static void reply_lockingX_send(struct ntvfs_request *ntvfs)
1622 struct smbsrv_request *req;
1623 union smb_lock *lck;
1625 SMBSRV_CHECK_ASYNC_STATUS(lck, union smb_lock);
1627 /* if it was an oplock break ack then we only send a reply if
1628 there was an error */
1629 if (lck->lockx.in.ulock_cnt + lck->lockx.in.lock_cnt == 0) {
1630 talloc_free(req);
1631 return;
1634 /* construct reply */
1635 smbsrv_setup_reply(req, 2, 0);
1637 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1638 SSVAL(req->out.vwv, VWV(1), 0);
1640 smbsrv_chain_reply(req);
1644 /****************************************************************************
1645 Reply to a lockingX request.
1646 ****************************************************************************/
1647 void smbsrv_reply_lockingX(struct smbsrv_request *req)
1649 union smb_lock *lck;
1650 uint_t total_locks, i;
1651 uint_t lck_size;
1652 uint8_t *p;
1654 /* parse request */
1655 SMBSRV_CHECK_WCT(req, 8);
1656 SMBSRV_TALLOC_IO_PTR(lck, union smb_lock);
1657 SMBSRV_SETUP_NTVFS_REQUEST(reply_lockingX_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1659 lck->lockx.level = RAW_LOCK_LOCKX;
1660 lck->lockx.in.file.ntvfs= smbsrv_pull_fnum(req, req->in.vwv, VWV(2));
1661 lck->lockx.in.mode = SVAL(req->in.vwv, VWV(3));
1662 lck->lockx.in.timeout = IVAL(req->in.vwv, VWV(4));
1663 lck->lockx.in.ulock_cnt = SVAL(req->in.vwv, VWV(6));
1664 lck->lockx.in.lock_cnt = SVAL(req->in.vwv, VWV(7));
1666 total_locks = lck->lockx.in.ulock_cnt + lck->lockx.in.lock_cnt;
1668 /* there are two variants, one with 64 bit offsets and counts */
1669 if (lck->lockx.in.mode & LOCKING_ANDX_LARGE_FILES) {
1670 lck_size = 20;
1671 } else {
1672 lck_size = 10;
1675 /* make sure we got the promised data */
1676 if (req_data_oob(&req->in.bufinfo, req->in.data, total_locks * lck_size)) {
1677 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1678 return;
1681 /* allocate the locks array */
1682 if (total_locks) {
1683 lck->lockx.in.locks = talloc_array(req, struct smb_lock_entry,
1684 total_locks);
1685 if (lck->lockx.in.locks == NULL) {
1686 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
1687 return;
1691 p = req->in.data;
1693 /* construct the locks array */
1694 for (i=0;i<total_locks;i++) {
1695 uint32_t ofs_high=0, count_high=0;
1697 lck->lockx.in.locks[i].pid = SVAL(p, 0);
1699 if (lck->lockx.in.mode & LOCKING_ANDX_LARGE_FILES) {
1700 ofs_high = IVAL(p, 4);
1701 lck->lockx.in.locks[i].offset = IVAL(p, 8);
1702 count_high = IVAL(p, 12);
1703 lck->lockx.in.locks[i].count = IVAL(p, 16);
1704 } else {
1705 lck->lockx.in.locks[i].offset = IVAL(p, 2);
1706 lck->lockx.in.locks[i].count = IVAL(p, 6);
1708 if (ofs_high != 0 || count_high != 0) {
1709 lck->lockx.in.locks[i].count |= ((uint64_t)count_high) << 32;
1710 lck->lockx.in.locks[i].offset |= ((uint64_t)ofs_high) << 32;
1712 p += lck_size;
1715 SMBSRV_CHECK_FILE_HANDLE(lck->lockx.in.file.ntvfs);
1716 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_lock(req->ntvfs, lck));
1719 /****************************************************************************
1720 Reply to a SMBreadbmpx (read block multiplex) request.
1721 ****************************************************************************/
1722 void smbsrv_reply_readbmpx(struct smbsrv_request *req)
1724 /* tell the client to not use a multiplexed read - its too broken to use */
1725 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRuseSTD));
1729 /****************************************************************************
1730 Reply to a SMBsetattrE.
1731 ****************************************************************************/
1732 void smbsrv_reply_setattrE(struct smbsrv_request *req)
1734 union smb_setfileinfo *info;
1736 /* parse request */
1737 SMBSRV_CHECK_WCT(req, 7);
1738 SMBSRV_TALLOC_IO_PTR(info, union smb_setfileinfo);
1739 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1741 info->setattre.level = RAW_SFILEINFO_SETATTRE;
1742 info->setattre.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1743 info->setattre.in.create_time = srv_pull_dos_date2(req->smb_conn, req->in.vwv + VWV(1));
1744 info->setattre.in.access_time = srv_pull_dos_date2(req->smb_conn, req->in.vwv + VWV(3));
1745 info->setattre.in.write_time = srv_pull_dos_date2(req->smb_conn, req->in.vwv + VWV(5));
1747 SMBSRV_CHECK_FILE_HANDLE(info->setattre.in.file.ntvfs);
1748 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_setfileinfo(req->ntvfs, info));
1752 /****************************************************************************
1753 Reply to a SMBwritebmpx (write block multiplex primary) request.
1754 ****************************************************************************/
1755 void smbsrv_reply_writebmpx(struct smbsrv_request *req)
1757 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRuseSTD));
1761 /****************************************************************************
1762 Reply to a SMBwritebs (write block multiplex secondary) request.
1763 ****************************************************************************/
1764 void smbsrv_reply_writebs(struct smbsrv_request *req)
1766 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRuseSTD));
1771 /****************************************************************************
1772 Reply to a SMBgetattrE (async reply)
1773 ****************************************************************************/
1774 static void reply_getattrE_send(struct ntvfs_request *ntvfs)
1776 struct smbsrv_request *req;
1777 union smb_fileinfo *info;
1779 SMBSRV_CHECK_ASYNC_STATUS(info, union smb_fileinfo);
1781 /* setup reply */
1782 smbsrv_setup_reply(req, 11, 0);
1784 srv_push_dos_date2(req->smb_conn, req->out.vwv, VWV(0), info->getattre.out.create_time);
1785 srv_push_dos_date2(req->smb_conn, req->out.vwv, VWV(2), info->getattre.out.access_time);
1786 srv_push_dos_date2(req->smb_conn, req->out.vwv, VWV(4), info->getattre.out.write_time);
1787 SIVAL(req->out.vwv, VWV(6), info->getattre.out.size);
1788 SIVAL(req->out.vwv, VWV(8), info->getattre.out.alloc_size);
1789 SSVAL(req->out.vwv, VWV(10), info->getattre.out.attrib);
1791 smbsrv_send_reply(req);
1794 /****************************************************************************
1795 Reply to a SMBgetattrE.
1796 ****************************************************************************/
1797 void smbsrv_reply_getattrE(struct smbsrv_request *req)
1799 union smb_fileinfo *info;
1801 /* parse request */
1802 SMBSRV_CHECK_WCT(req, 1);
1803 SMBSRV_TALLOC_IO_PTR(info, union smb_fileinfo);
1804 SMBSRV_SETUP_NTVFS_REQUEST(reply_getattrE_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1806 info->getattr.level = RAW_FILEINFO_GETATTRE;
1807 info->getattr.in.file.ntvfs = smbsrv_pull_fnum(req, req->in.vwv, VWV(0));
1809 SMBSRV_CHECK_FILE_HANDLE(info->getattr.in.file.ntvfs);
1810 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_qfileinfo(req->ntvfs, info));
1813 void smbsrv_reply_sesssetup_send(struct smbsrv_request *req,
1814 union smb_sesssetup *io,
1815 NTSTATUS status)
1817 switch (io->old.level) {
1818 case RAW_SESSSETUP_OLD:
1819 if (!NT_STATUS_IS_OK(status)) {
1820 smbsrv_send_error(req, status);
1821 return;
1824 /* construct reply */
1825 smbsrv_setup_reply(req, 3, 0);
1827 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1828 SSVAL(req->out.vwv, VWV(1), 0);
1829 SSVAL(req->out.vwv, VWV(2), io->old.out.action);
1831 SSVAL(req->out.hdr, HDR_UID, io->old.out.vuid);
1833 smbsrv_chain_reply(req);
1834 return;
1836 case RAW_SESSSETUP_NT1:
1837 if (!NT_STATUS_IS_OK(status)) {
1838 smbsrv_send_error(req, status);
1839 return;
1842 /* construct reply */
1843 smbsrv_setup_reply(req, 3, 0);
1845 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1846 SSVAL(req->out.vwv, VWV(1), 0);
1847 SSVAL(req->out.vwv, VWV(2), io->nt1.out.action);
1849 SSVAL(req->out.hdr, HDR_UID, io->nt1.out.vuid);
1851 req_push_str(req, NULL, io->nt1.out.os, -1, STR_TERMINATE);
1852 req_push_str(req, NULL, io->nt1.out.lanman, -1, STR_TERMINATE);
1853 req_push_str(req, NULL, io->nt1.out.domain, -1, STR_TERMINATE);
1855 smbsrv_chain_reply(req);
1856 return;
1858 case RAW_SESSSETUP_SPNEGO:
1859 if (!NT_STATUS_IS_OK(status) &&
1860 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1861 smbsrv_send_error(req, status);
1862 return;
1865 /* construct reply */
1866 smbsrv_setup_reply(req, 4, io->spnego.out.secblob.length);
1868 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1869 smbsrv_setup_error(req, status);
1872 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1873 SSVAL(req->out.vwv, VWV(1), 0);
1874 SSVAL(req->out.vwv, VWV(2), io->spnego.out.action);
1875 SSVAL(req->out.vwv, VWV(3), io->spnego.out.secblob.length);
1877 SSVAL(req->out.hdr, HDR_UID, io->spnego.out.vuid);
1879 memcpy(req->out.data, io->spnego.out.secblob.data, io->spnego.out.secblob.length);
1880 req_push_str(req, NULL, io->spnego.out.os, -1, STR_TERMINATE);
1881 req_push_str(req, NULL, io->spnego.out.lanman, -1, STR_TERMINATE);
1882 req_push_str(req, NULL, io->spnego.out.workgroup, -1, STR_TERMINATE);
1884 smbsrv_chain_reply(req);
1885 return;
1887 case RAW_SESSSETUP_SMB2:
1888 break;
1891 smbsrv_send_error(req, NT_STATUS_INTERNAL_ERROR);
1894 /****************************************************************************
1895 reply to an old style session setup command
1896 ****************************************************************************/
1897 static void reply_sesssetup_old(struct smbsrv_request *req)
1899 uint8_t *p;
1900 uint16_t passlen;
1901 union smb_sesssetup *io;
1903 SMBSRV_TALLOC_IO_PTR(io, union smb_sesssetup);
1905 io->old.level = RAW_SESSSETUP_OLD;
1907 /* parse request */
1908 io->old.in.bufsize = SVAL(req->in.vwv, VWV(2));
1909 io->old.in.mpx_max = SVAL(req->in.vwv, VWV(3));
1910 io->old.in.vc_num = SVAL(req->in.vwv, VWV(4));
1911 io->old.in.sesskey = IVAL(req->in.vwv, VWV(5));
1912 passlen = SVAL(req->in.vwv, VWV(7));
1914 /* check the request isn't malformed */
1915 if (req_data_oob(&req->in.bufinfo, req->in.data, passlen)) {
1916 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1917 return;
1920 p = req->in.data;
1921 if (!req_pull_blob(&req->in.bufinfo, p, passlen, &io->old.in.password)) {
1922 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1923 return;
1925 p += passlen;
1927 p += req_pull_string(&req->in.bufinfo, &io->old.in.user, p, -1, STR_TERMINATE);
1928 p += req_pull_string(&req->in.bufinfo, &io->old.in.domain, p, -1, STR_TERMINATE);
1929 p += req_pull_string(&req->in.bufinfo, &io->old.in.os, p, -1, STR_TERMINATE);
1930 p += req_pull_string(&req->in.bufinfo, &io->old.in.lanman, p, -1, STR_TERMINATE);
1932 /* call the generic handler */
1933 smbsrv_sesssetup_backend(req, io);
1936 /****************************************************************************
1937 reply to an NT1 style session setup command
1938 ****************************************************************************/
1939 static void reply_sesssetup_nt1(struct smbsrv_request *req)
1941 uint8_t *p;
1942 uint16_t passlen1, passlen2;
1943 union smb_sesssetup *io;
1945 SMBSRV_TALLOC_IO_PTR(io, union smb_sesssetup);
1947 io->nt1.level = RAW_SESSSETUP_NT1;
1949 /* parse request */
1950 io->nt1.in.bufsize = SVAL(req->in.vwv, VWV(2));
1951 io->nt1.in.mpx_max = SVAL(req->in.vwv, VWV(3));
1952 io->nt1.in.vc_num = SVAL(req->in.vwv, VWV(4));
1953 io->nt1.in.sesskey = IVAL(req->in.vwv, VWV(5));
1954 passlen1 = SVAL(req->in.vwv, VWV(7));
1955 passlen2 = SVAL(req->in.vwv, VWV(8));
1956 io->nt1.in.capabilities = IVAL(req->in.vwv, VWV(11));
1958 /* check the request isn't malformed */
1959 if (req_data_oob(&req->in.bufinfo, req->in.data, passlen1) ||
1960 req_data_oob(&req->in.bufinfo, req->in.data + passlen1, passlen2)) {
1961 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1962 return;
1965 p = req->in.data;
1966 if (!req_pull_blob(&req->in.bufinfo, p, passlen1, &io->nt1.in.password1)) {
1967 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1968 return;
1970 p += passlen1;
1971 if (!req_pull_blob(&req->in.bufinfo, p, passlen2, &io->nt1.in.password2)) {
1972 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1973 return;
1975 p += passlen2;
1977 p += req_pull_string(&req->in.bufinfo, &io->nt1.in.user, p, -1, STR_TERMINATE);
1978 p += req_pull_string(&req->in.bufinfo, &io->nt1.in.domain, p, -1, STR_TERMINATE);
1979 p += req_pull_string(&req->in.bufinfo, &io->nt1.in.os, p, -1, STR_TERMINATE);
1980 p += req_pull_string(&req->in.bufinfo, &io->nt1.in.lanman, p, -1, STR_TERMINATE);
1982 /* call the generic handler */
1983 smbsrv_sesssetup_backend(req, io);
1987 /****************************************************************************
1988 reply to an SPNEGO style session setup command
1989 ****************************************************************************/
1990 static void reply_sesssetup_spnego(struct smbsrv_request *req)
1992 uint8_t *p;
1993 uint16_t blob_len;
1994 union smb_sesssetup *io;
1996 SMBSRV_TALLOC_IO_PTR(io, union smb_sesssetup);
1998 io->spnego.level = RAW_SESSSETUP_SPNEGO;
2000 /* parse request */
2001 io->spnego.in.bufsize = SVAL(req->in.vwv, VWV(2));
2002 io->spnego.in.mpx_max = SVAL(req->in.vwv, VWV(3));
2003 io->spnego.in.vc_num = SVAL(req->in.vwv, VWV(4));
2004 io->spnego.in.sesskey = IVAL(req->in.vwv, VWV(5));
2005 blob_len = SVAL(req->in.vwv, VWV(7));
2006 io->spnego.in.capabilities = IVAL(req->in.vwv, VWV(10));
2008 p = req->in.data;
2009 if (!req_pull_blob(&req->in.bufinfo, p, blob_len, &io->spnego.in.secblob)) {
2010 smbsrv_send_error(req, NT_STATUS_FOOBAR);
2011 return;
2013 p += blob_len;
2015 p += req_pull_string(&req->in.bufinfo, &io->spnego.in.os, p, -1, STR_TERMINATE);
2016 p += req_pull_string(&req->in.bufinfo, &io->spnego.in.lanman, p, -1, STR_TERMINATE);
2017 p += req_pull_string(&req->in.bufinfo, &io->spnego.in.workgroup, p, -1, STR_TERMINATE);
2019 /* call the generic handler */
2020 smbsrv_sesssetup_backend(req, io);
2024 /****************************************************************************
2025 reply to a session setup command
2026 ****************************************************************************/
2027 void smbsrv_reply_sesssetup(struct smbsrv_request *req)
2029 switch (req->in.wct) {
2030 case 10:
2031 /* a pre-NT1 call */
2032 reply_sesssetup_old(req);
2033 return;
2034 case 13:
2035 /* a NT1 call */
2036 reply_sesssetup_nt1(req);
2037 return;
2038 case 12:
2039 /* a SPNEGO call */
2040 reply_sesssetup_spnego(req);
2041 return;
2044 /* unsupported variant */
2045 smbsrv_send_error(req, NT_STATUS_FOOBAR);
2048 /****************************************************************************
2049 Reply to a exit. This closes all files open by a smbpid
2050 ****************************************************************************/
2051 void smbsrv_reply_exit(struct smbsrv_request *req)
2053 struct smbsrv_handle_session_item *i, *ni;
2054 struct smbsrv_handle *h;
2055 struct smbsrv_tcon *tcon;
2056 uint16_t smbpid;
2058 SMBSRV_CHECK_WCT(req, 0);
2060 smbpid = SVAL(req->in.hdr,HDR_PID);
2062 /* first destroy all handles, which have the same PID as the request */
2063 for (i=req->session->handles; i; i=ni) {
2064 ni = i->next;
2065 h = i->handle;
2066 if (h->smbpid != smbpid) continue;
2068 talloc_free(h);
2072 * then let the ntvfs backends proxy the call if they want to,
2073 * but we didn't check the return value of the backends,
2074 * as for the SMB client the call succeed
2076 for (tcon=req->smb_conn->smb_tcons.list;tcon;tcon=tcon->next) {
2077 req->tcon = tcon;
2078 SMBSRV_SETUP_NTVFS_REQUEST(NULL,0);
2079 ntvfs_exit(req->ntvfs);
2080 talloc_free(req->ntvfs);
2081 req->ntvfs = NULL;
2082 req->tcon = NULL;
2085 smbsrv_setup_reply(req, 0, 0);
2086 smbsrv_send_reply(req);
2089 /****************************************************************************
2090 Reply to a SMBulogoffX.
2091 ****************************************************************************/
2092 void smbsrv_reply_ulogoffX(struct smbsrv_request *req)
2094 struct smbsrv_handle_session_item *i, *ni;
2095 struct smbsrv_handle *h;
2096 struct smbsrv_tcon *tcon;
2098 SMBSRV_CHECK_WCT(req, 2);
2101 * TODO: cancel all pending requests
2105 /* destroy all handles */
2106 for (i=req->session->handles; i; i=ni) {
2107 ni = i->next;
2108 h = i->handle;
2109 talloc_free(h);
2113 * then let the ntvfs backends proxy the call if they want to,
2114 * but we didn't check the return value of the backends,
2115 * as for the SMB client the call succeed
2117 for (tcon=req->smb_conn->smb_tcons.list;tcon;tcon=tcon->next) {
2118 req->tcon = tcon;
2119 SMBSRV_SETUP_NTVFS_REQUEST(NULL,0);
2120 ntvfs_logoff(req->ntvfs);
2121 talloc_free(req->ntvfs);
2122 req->ntvfs = NULL;
2123 req->tcon = NULL;
2126 talloc_free(req->session);
2127 req->session = NULL; /* it is now invalid, don't use on
2128 any chained packets */
2130 smbsrv_setup_reply(req, 2, 0);
2132 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
2133 SSVAL(req->out.vwv, VWV(1), 0);
2135 smbsrv_chain_reply(req);
2138 /****************************************************************************
2139 Reply to an SMBfindclose request
2140 ****************************************************************************/
2141 void smbsrv_reply_findclose(struct smbsrv_request *req)
2143 union smb_search_close *io;
2145 /* parse request */
2146 SMBSRV_CHECK_WCT(req, 1);
2147 SMBSRV_TALLOC_IO_PTR(io, union smb_search_close);
2148 SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
2150 io->findclose.level = RAW_FINDCLOSE_FINDCLOSE;
2151 io->findclose.in.handle = SVAL(req->in.vwv, VWV(0));
2153 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_search_close(req->ntvfs, io));
2156 /****************************************************************************
2157 Reply to an SMBfindnclose request
2158 ****************************************************************************/
2159 void smbsrv_reply_findnclose(struct smbsrv_request *req)
2161 smbsrv_send_error(req, NT_STATUS_FOOBAR);
2165 /****************************************************************************
2166 Reply to an SMBntcreateX request (async send)
2167 ****************************************************************************/
2168 static void reply_ntcreate_and_X_send(struct ntvfs_request *ntvfs)
2170 struct smbsrv_request *req;
2171 union smb_open *io;
2173 SMBSRV_CHECK_ASYNC_STATUS(io, union smb_open);
2175 /* construct reply */
2176 smbsrv_setup_reply(req, 34, 0);
2178 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
2179 SSVAL(req->out.vwv, VWV(1), 0);
2180 SCVAL(req->out.vwv, VWV(2), io->ntcreatex.out.oplock_level);
2182 /* the rest of the parameters are not aligned! */
2183 smbsrv_push_fnum(req->out.vwv, 5, io->ntcreatex.out.file.ntvfs);
2184 SIVAL(req->out.vwv, 7, io->ntcreatex.out.create_action);
2185 push_nttime(req->out.vwv, 11, io->ntcreatex.out.create_time);
2186 push_nttime(req->out.vwv, 19, io->ntcreatex.out.access_time);
2187 push_nttime(req->out.vwv, 27, io->ntcreatex.out.write_time);
2188 push_nttime(req->out.vwv, 35, io->ntcreatex.out.change_time);
2189 SIVAL(req->out.vwv, 43, io->ntcreatex.out.attrib);
2190 SBVAL(req->out.vwv, 47, io->ntcreatex.out.alloc_size);
2191 SBVAL(req->out.vwv, 55, io->ntcreatex.out.size);
2192 SSVAL(req->out.vwv, 63, io->ntcreatex.out.file_type);
2193 SSVAL(req->out.vwv, 65, io->ntcreatex.out.ipc_state);
2194 SCVAL(req->out.vwv, 67, io->ntcreatex.out.is_directory);
2196 req->chained_fnum = SVAL(req->out.vwv, 5);
2198 smbsrv_chain_reply(req);
2201 /****************************************************************************
2202 Reply to an SMBntcreateX request
2203 ****************************************************************************/
2204 void smbsrv_reply_ntcreate_and_X(struct smbsrv_request *req)
2206 union smb_open *io;
2207 uint16_t fname_len;
2209 /* parse the request */
2210 SMBSRV_CHECK_WCT(req, 24);
2211 SMBSRV_TALLOC_IO_PTR(io, union smb_open);
2212 SMBSRV_SETUP_NTVFS_REQUEST(reply_ntcreate_and_X_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
2214 io->ntcreatex.level = RAW_OPEN_NTCREATEX;
2216 /* notice that the word parameters are not word aligned, so we don't use VWV() */
2217 fname_len = SVAL(req->in.vwv, 5);
2218 io->ntcreatex.in.flags = IVAL(req->in.vwv, 7);
2219 io->ntcreatex.in.root_fid = IVAL(req->in.vwv, 11);
2220 io->ntcreatex.in.access_mask = IVAL(req->in.vwv, 15);
2221 io->ntcreatex.in.alloc_size = BVAL(req->in.vwv, 19);
2222 io->ntcreatex.in.file_attr = IVAL(req->in.vwv, 27);
2223 io->ntcreatex.in.share_access = IVAL(req->in.vwv, 31);
2224 io->ntcreatex.in.open_disposition = IVAL(req->in.vwv, 35);
2225 io->ntcreatex.in.create_options = IVAL(req->in.vwv, 39);
2226 io->ntcreatex.in.impersonation = IVAL(req->in.vwv, 43);
2227 io->ntcreatex.in.security_flags = CVAL(req->in.vwv, 47);
2228 io->ntcreatex.in.ea_list = NULL;
2229 io->ntcreatex.in.sec_desc = NULL;
2230 io->ntcreatex.in.query_maximal_access = false;
2232 /* we use a couple of bits of the create options internally */
2233 if (io->ntcreatex.in.create_options & NTCREATEX_OPTIONS_PRIVATE_MASK) {
2234 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
2235 return;
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 0x81: /* 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, SMBkeepalive);
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 SMBkeepalive:
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);