94317bfc39830bffd46963ab3feb9a32207c396f
[samba.git] / source4 / smb_server / reply.c
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
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21 /*
22    This file handles most of the reply_ calls that the server
23    makes to handle specific protocols
24 */
25
26 #include "includes.h"
27
28 /* useful way of catching wct errors with file and line number */
29 #define REQ_CHECK_WCT(req, wcount) do { \
30         if ((req)->in.wct != (wcount)) { \
31                 DEBUG(1,("Unexpected WCT %d at %s(%d) - expected %d\n", \
32                          (req)->in.wct, __FILE__, __LINE__, wcount)); \
33                 req_reply_dos_error(req, ERRSRV, ERRerror); \
34                 return; \
35         }} while (0)
36
37 /* check req->async.status and if not OK then send an error reply */
38 #define CHECK_ASYNC_STATUS do { \
39         if (!NT_STATUS_IS_OK(req->async.status)) { \
40                 req_reply_error(req, req->async.status); \
41                 return; \
42         }} while (0)
43         
44 /* useful wrapper for talloc with NO_MEMORY reply */
45 #define REQ_TALLOC(ptr, size) do { \
46         ptr = talloc(req, size); \
47         if (!ptr) { \
48                 req_reply_error(req, NT_STATUS_NO_MEMORY); \
49                 return; \
50         }} while (0)
51
52 /* 
53    check if the backend wants to handle the request asynchronously.
54    if it wants it handled synchronously then call the send function
55    immediately
56 */
57 #define REQ_ASYNC_TAIL do { \
58         if (!(req->control_flags & REQ_CONTROL_ASYNC)) { \
59                 req->async.send_fn(req); \
60         }} while (0)
61
62 /* zero out some reserved fields in a reply */
63 #define REQ_VWV_RESERVED(start, count) memset(req->out.vwv + VWV(start), 0, (count)*2)
64
65 /****************************************************************************
66  Reply to a simple request (async send)
67 ****************************************************************************/
68 static void reply_simple_send(struct smbsrv_request *req)
69 {
70         CHECK_ASYNC_STATUS;
71
72         req_setup_reply(req, 0, 0);
73         req_send_reply(req);
74 }
75
76
77 /****************************************************************************
78  Reply to a tcon.
79 ****************************************************************************/
80 void reply_tcon(struct smbsrv_request *req)
81 {
82         union smb_tcon con;
83         NTSTATUS status;
84         char *p;
85         
86         /* parse request */
87         REQ_CHECK_WCT(req, 0);
88
89         con.tcon.level = RAW_TCON_TCON;
90
91         p = req->in.data;       
92         p += req_pull_ascii4(req, &con.tcon.in.service, p, STR_TERMINATE);
93         p += req_pull_ascii4(req, &con.tcon.in.password, p, STR_TERMINATE);
94         p += req_pull_ascii4(req, &con.tcon.in.dev, p, STR_TERMINATE);
95
96         if (!con.tcon.in.service || !con.tcon.in.password || !con.tcon.in.dev) {
97                 req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
98                 return;
99         }
100
101         /* call backend */
102         status = tcon_backend(req, &con);
103
104         if (!NT_STATUS_IS_OK(status)) {
105                 req_reply_error(req, status);
106                 return;
107         }
108
109         /* construct reply */
110         req_setup_reply(req, 2, 0);
111
112         SSVAL(req->out.vwv, VWV(0), con.tcon.out.max_xmit);
113         SSVAL(req->out.vwv, VWV(1), con.tcon.out.cnum);
114         SSVAL(req->out.hdr, HDR_TID, req->tcon->cnum);
115   
116         req_send_reply(req);
117 }
118
119
120 /****************************************************************************
121  Reply to a tcon and X.
122 ****************************************************************************/
123 void reply_tcon_and_X(struct smbsrv_request *req)
124 {
125         NTSTATUS status;
126         union smb_tcon con;
127         char *p;
128         uint16_t passlen;
129
130         con.tconx.level = RAW_TCON_TCONX;
131
132         /* parse request */
133         REQ_CHECK_WCT(req, 4);
134
135         con.tconx.in.flags  = SVAL(req->in.vwv, VWV(2));
136         passlen             = SVAL(req->in.vwv, VWV(3));
137
138         p = req->in.data;
139
140         if (!req_pull_blob(req, p, passlen, &con.tconx.in.password)) {
141                 req_reply_error(req, NT_STATUS_ILL_FORMED_PASSWORD);
142                 return;
143         }
144         p += passlen;
145
146         p += req_pull_string(req, &con.tconx.in.path, p, -1, STR_TERMINATE);
147         p += req_pull_string(req, &con.tconx.in.device, p, -1, STR_ASCII);
148
149         if (!con.tconx.in.path || !con.tconx.in.device) {
150                 req_reply_error(req, NT_STATUS_BAD_DEVICE_TYPE);
151                 return;
152         }
153
154         /* call backend */
155         status = tcon_backend(req, &con);
156
157         if (!NT_STATUS_IS_OK(status)) {
158                 req_reply_error(req, status);
159                 return;
160         }
161
162         /* construct reply - two variants */
163         if (req->smb_conn->negotiate.protocol < PROTOCOL_NT1) {
164                 req_setup_reply(req, 2, 0);
165
166                 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
167                 SSVAL(req->out.vwv, VWV(1), 0);
168
169                 req_push_str(req, NULL, con.tconx.out.dev_type, -1, STR_TERMINATE|STR_ASCII);
170         } else {
171                 req_setup_reply(req, 3, 0);
172
173                 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
174                 SSVAL(req->out.vwv, VWV(1), 0);
175                 SSVAL(req->out.vwv, VWV(2), con.tconx.out.options);
176
177                 req_push_str(req, NULL, con.tconx.out.dev_type, -1, STR_TERMINATE|STR_ASCII);
178                 req_push_str(req, NULL, con.tconx.out.fs_type, -1, STR_TERMINATE);
179         }
180
181         /* set the incoming and outgoing tid to the just created one */
182         SSVAL(req->in.hdr, HDR_TID, con.tconx.out.cnum);
183         SSVAL(req->out.hdr,HDR_TID, con.tconx.out.cnum);
184
185         chain_reply(req);
186 }
187
188
189 /****************************************************************************
190  Reply to an unknown request
191 ****************************************************************************/
192 void reply_unknown(struct smbsrv_request *req)
193 {
194         int type;
195
196         type = CVAL(req->in.hdr, HDR_COM);
197   
198         DEBUG(0,("unknown command type %d (0x%X)\n", type, type));
199
200         req_reply_dos_error(req, ERRSRV, ERRunknownsmb);
201 }
202
203
204 /****************************************************************************
205  Reply to an ioctl (async reply)
206 ****************************************************************************/
207 static void reply_ioctl_send(struct smbsrv_request *req)
208 {
209         union smb_ioctl *io = req->async.private;
210
211         CHECK_ASYNC_STATUS;
212
213         /* the +1 is for nicer alignment */
214         req_setup_reply(req, 8, io->ioctl.out.blob.length+1);
215         SSVAL(req->out.vwv, VWV(1), io->ioctl.out.blob.length);
216         SSVAL(req->out.vwv, VWV(5), io->ioctl.out.blob.length);
217         SSVAL(req->out.vwv, VWV(6), PTR_DIFF(req->out.data, req->out.hdr) + 1);
218
219         memcpy(req->out.data+1, io->ioctl.out.blob.data, io->ioctl.out.blob.length);
220
221         req_send_reply(req);
222 }
223
224 /****************************************************************************
225  Reply to an ioctl.
226 ****************************************************************************/
227 void reply_ioctl(struct smbsrv_request *req)
228 {
229         union smb_ioctl *io;
230
231         /* parse request */
232         REQ_CHECK_WCT(req, 3);
233         REQ_TALLOC(io, sizeof(*io));
234
235         io->ioctl.level = RAW_IOCTL_IOCTL;
236         io->ioctl.in.fnum     = req_fnum(req, req->in.vwv, VWV(0));
237         io->ioctl.in.request  = IVAL(req->in.vwv, VWV(1));
238
239         req->async.send_fn = reply_ioctl_send;
240         req->async.private = io;
241
242         /* call backend */
243         req->async.status = req->tcon->ntvfs_ops->ioctl(req, io);
244
245         REQ_ASYNC_TAIL;
246 }
247
248
249 /****************************************************************************
250  Reply to a chkpth.
251 ****************************************************************************/
252 void reply_chkpth(struct smbsrv_request *req)
253 {
254         struct smb_chkpath *io;
255
256         REQ_TALLOC(io, sizeof(*io));
257
258         req_pull_ascii4(req, &io->in.path, req->in.data, STR_TERMINATE);
259
260         req->async.send_fn = reply_simple_send;
261
262         req->async.status = req->tcon->ntvfs_ops->chkpath(req, io);
263
264         REQ_ASYNC_TAIL;
265 }
266
267 /****************************************************************************
268  Reply to a getatr (async reply)
269 ****************************************************************************/
270 static void reply_getatr_send(struct smbsrv_request *req)
271 {
272         union smb_fileinfo *st = req->async.private;
273
274         CHECK_ASYNC_STATUS;
275         
276         /* construct reply */
277         req_setup_reply(req, 10, 0);
278
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);
282
283         REQ_VWV_RESERVED(5, 5);
284
285         req_send_reply(req);
286 }
287
288
289 /****************************************************************************
290  Reply to a getatr.
291 ****************************************************************************/
292 void reply_getatr(struct smbsrv_request *req)
293 {
294         union smb_fileinfo *st;
295
296         REQ_TALLOC(st, sizeof(*st));
297         
298         st->getattr.level = RAW_FILEINFO_GETATTR;
299
300         /* parse request */
301         req_pull_ascii4(req, &st->getattr.in.fname, req->in.data, STR_TERMINATE);
302         if (!st->getattr.in.fname) {
303                 req_reply_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
304                 return;
305         }
306
307         req->async.send_fn = reply_getatr_send;
308         req->async.private = st;
309
310         /* call backend */
311         req->async.status = req->tcon->ntvfs_ops->qpathinfo(req, st);
312
313         REQ_ASYNC_TAIL;
314 }
315
316
317 /****************************************************************************
318  Reply to a setatr.
319 ****************************************************************************/
320 void reply_setatr(struct smbsrv_request *req)
321 {
322         union smb_setfileinfo *st;
323
324         /* parse request */
325         REQ_CHECK_WCT(req, 8);
326         REQ_TALLOC(st, sizeof(*st));
327
328         st->setattr.level = RAW_SFILEINFO_SETATTR;
329         st->setattr.in.attrib     = SVAL(req->in.vwv, VWV(0));
330         st->setattr.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(1));
331         
332         req_pull_ascii4(req, &st->setattr.file.fname, req->in.data, STR_TERMINATE);
333
334         if (!st->setattr.file.fname) {
335                 req_reply_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
336                 return;
337         }
338         
339         req->async.send_fn = reply_simple_send;
340
341         /* call backend */
342         req->async.status = req->tcon->ntvfs_ops->setpathinfo(req, st);
343
344         REQ_ASYNC_TAIL;
345 }
346
347
348 /****************************************************************************
349  Reply to a dskattr (async reply)
350 ****************************************************************************/
351 static void reply_dskattr_send(struct smbsrv_request *req)
352 {
353         union smb_fsinfo *fs = req->async.private;
354
355         CHECK_ASYNC_STATUS;
356         
357         /* construct reply */
358         req_setup_reply(req, 5, 0);
359
360         SSVAL(req->out.vwv, VWV(0), fs->dskattr.out.units_total);
361         SSVAL(req->out.vwv, VWV(1), fs->dskattr.out.blocks_per_unit);
362         SSVAL(req->out.vwv, VWV(2), fs->dskattr.out.block_size);
363         SSVAL(req->out.vwv, VWV(3), fs->dskattr.out.units_free);
364
365         REQ_VWV_RESERVED(4, 1);
366
367         req_send_reply(req);
368 }
369
370
371 /****************************************************************************
372  Reply to a dskattr.
373 ****************************************************************************/
374 void reply_dskattr(struct smbsrv_request *req)
375 {
376         union smb_fsinfo *fs;
377
378         REQ_TALLOC(fs, sizeof(*fs));
379         
380         fs->dskattr.level = RAW_QFS_DSKATTR;
381
382         req->async.send_fn = reply_dskattr_send;
383         req->async.private = fs;
384
385         /* call backend */
386         req->async.status = req->tcon->ntvfs_ops->fsinfo(req, fs);
387
388         REQ_ASYNC_TAIL;
389 }
390
391
392
393 /****************************************************************************
394  Reply to an open (async reply)
395 ****************************************************************************/
396 static void reply_open_send(struct smbsrv_request *req)
397 {
398         union smb_open *oi = req->async.private;
399
400         CHECK_ASYNC_STATUS;
401
402         /* construct reply */
403         req_setup_reply(req, 7, 0);
404
405         SSVAL(req->out.vwv, VWV(0), oi->open.out.fnum);
406         SSVAL(req->out.vwv, VWV(1), oi->open.out.attrib);
407         srv_push_dos_date3(req->smb_conn, req->out.vwv, VWV(2), oi->open.out.write_time);
408         SIVAL(req->out.vwv, VWV(4), oi->open.out.size);
409         SSVAL(req->out.vwv, VWV(6), oi->open.out.rmode);
410
411         req_send_reply(req);
412 }
413
414 /****************************************************************************
415  Reply to an open.
416 ****************************************************************************/
417 void reply_open(struct smbsrv_request *req)
418 {
419         union smb_open *oi;
420
421         /* parse request */
422         REQ_CHECK_WCT(req, 2);
423         REQ_TALLOC(oi, sizeof(*oi));
424
425         oi->open.level = RAW_OPEN_OPEN;
426         oi->open.in.flags = SVAL(req->in.vwv, VWV(0));
427         oi->open.in.search_attrs = SVAL(req->in.vwv, VWV(1));
428
429         req_pull_ascii4(req, &oi->open.in.fname, req->in.data, STR_TERMINATE);
430
431         if (!oi->open.in.fname) {
432                 req_reply_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
433                 return;
434         }
435
436         req->async.send_fn = reply_open_send;
437         req->async.private = oi;
438         
439         /* call backend */
440         req->async.status = req->tcon->ntvfs_ops->open(req, oi);
441
442         REQ_ASYNC_TAIL;
443 }
444
445
446 /****************************************************************************
447  Reply to an open and X (async reply)
448 ****************************************************************************/
449 static void reply_open_and_X_send(struct smbsrv_request *req)
450 {
451         union smb_open *oi = req->async.private;
452
453         CHECK_ASYNC_STATUS;
454
455         /* build the reply */
456         if (oi->openx.in.flags & OPENX_FLAGS_EXTENDED_RETURN) {
457                 req_setup_reply(req, 19, 0);
458         } else {
459                 req_setup_reply(req, 15, 0);
460         }
461
462         SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
463         SSVAL(req->out.vwv, VWV(1), 0);
464         SSVAL(req->out.vwv, VWV(2), oi->openx.out.fnum);
465         SSVAL(req->out.vwv, VWV(3), oi->openx.out.attrib);
466         srv_push_dos_date3(req->smb_conn, req->out.vwv, VWV(4), oi->openx.out.write_time);
467         SIVAL(req->out.vwv, VWV(6), oi->openx.out.size);
468         SSVAL(req->out.vwv, VWV(8), oi->openx.out.access);
469         SSVAL(req->out.vwv, VWV(9), oi->openx.out.ftype);
470         SSVAL(req->out.vwv, VWV(10),oi->openx.out.devstate);
471         SSVAL(req->out.vwv, VWV(11),oi->openx.out.action);
472         SIVAL(req->out.vwv, VWV(12),oi->openx.out.unique_fid);
473         SSVAL(req->out.vwv, VWV(14),0); /* reserved */
474         if (oi->openx.in.flags & OPENX_FLAGS_EXTENDED_RETURN) {
475                 SIVAL(req->out.vwv, VWV(15),oi->openx.out.access_mask);
476                 REQ_VWV_RESERVED(17, 2);
477         }
478
479         chain_reply(req);
480 }
481
482
483 /****************************************************************************
484  Reply to an open and X.
485 ****************************************************************************/
486 void reply_open_and_X(struct smbsrv_request *req)
487 {
488         union smb_open *oi;
489
490         /* parse the request */
491         REQ_CHECK_WCT(req, 15);
492         REQ_TALLOC(oi, sizeof(*oi));
493
494         oi->openx.level = RAW_OPEN_OPENX;
495         oi->openx.in.flags        = SVAL(req->in.vwv, VWV(2));
496         oi->openx.in.open_mode    = SVAL(req->in.vwv, VWV(3));
497         oi->openx.in.search_attrs = SVAL(req->in.vwv, VWV(4));
498         oi->openx.in.file_attrs   = SVAL(req->in.vwv, VWV(5));
499         oi->openx.in.write_time   = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(6));
500         oi->openx.in.open_func    = SVAL(req->in.vwv, VWV(8));
501         oi->openx.in.size         = IVAL(req->in.vwv, VWV(9));
502         oi->openx.in.timeout      = IVAL(req->in.vwv, VWV(11));
503
504         req_pull_ascii4(req, &oi->openx.in.fname, req->in.data, STR_TERMINATE);
505
506         if (!oi->openx.in.fname) {
507                 req_reply_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
508                 return;
509         }
510
511         req->async.send_fn = reply_open_and_X_send;
512         req->async.private = oi;
513
514         /* call the backend */
515         req->async.status = req->tcon->ntvfs_ops->open(req, oi);
516
517         REQ_ASYNC_TAIL;
518 }
519
520
521 /****************************************************************************
522  Reply to a mknew or a create.
523 ****************************************************************************/
524 static void reply_mknew_send(struct smbsrv_request *req)
525 {
526         union smb_open *oi = req->async.private;
527
528         CHECK_ASYNC_STATUS;
529
530         /* build the reply */
531         req_setup_reply(req, 1, 0);
532
533         SSVAL(req->out.vwv, VWV(0), oi->mknew.out.fnum);
534
535         req_send_reply(req);
536 }
537
538
539 /****************************************************************************
540  Reply to a mknew or a create.
541 ****************************************************************************/
542 void reply_mknew(struct smbsrv_request *req)
543 {
544         union smb_open *oi;
545
546         /* parse the request */
547         REQ_CHECK_WCT(req, 3);
548         REQ_TALLOC(oi, sizeof(*oi));
549
550         oi->mknew.level = RAW_OPEN_MKNEW;
551         oi->mknew.in.attrib  = SVAL(req->in.vwv, VWV(0));
552         oi->mknew.in.write_time  = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(1));
553
554         req_pull_ascii4(req, &oi->mknew.in.fname, req->in.data, STR_TERMINATE);
555
556         if (!oi->mknew.in.fname) {
557                 req_reply_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
558                 return;
559         }
560
561         req->async.send_fn = reply_mknew_send;
562         req->async.private = oi;
563
564         /* call the backend */
565         req->async.status = req->tcon->ntvfs_ops->open(req, oi);
566
567         REQ_ASYNC_TAIL;
568 }
569
570 /****************************************************************************
571  Reply to a create temporary file (async reply)
572 ****************************************************************************/
573 static void reply_ctemp_send(struct smbsrv_request *req)
574 {
575         union smb_open *oi = req->async.private;
576
577         CHECK_ASYNC_STATUS;
578
579         /* build the reply */
580         req_setup_reply(req, 1, 0);
581
582         SSVAL(req->out.vwv, VWV(0), oi->ctemp.out.fnum);
583
584         /* the returned filename is relative to the directory */
585         req_push_str(req, NULL, oi->ctemp.out.name, -1, STR_TERMINATE);
586
587         req_send_reply(req);
588 }
589
590 /****************************************************************************
591  Reply to a create temporary file.
592 ****************************************************************************/
593 void reply_ctemp(struct smbsrv_request *req)
594 {
595         union smb_open *oi;
596
597         /* parse the request */
598         REQ_CHECK_WCT(req, 3);
599         REQ_TALLOC(oi, sizeof(*oi));
600
601         oi->ctemp.level = RAW_OPEN_CTEMP;
602         oi->ctemp.in.attrib = SVAL(req->in.vwv, VWV(0));
603         oi->ctemp.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(1));
604
605         /* the filename is actually a directory name, the server provides a filename
606            in that directory */
607         req_pull_ascii4(req, &oi->ctemp.in.directory, req->in.data, STR_TERMINATE);
608
609         if (!oi->ctemp.in.directory) {
610                 req_reply_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
611                 return;
612         }
613
614         req->async.send_fn = reply_ctemp_send;
615         req->async.private = oi;
616
617         /* call the backend */
618         req->async.status = req->tcon->ntvfs_ops->open(req, oi);
619
620         REQ_ASYNC_TAIL;
621 }
622
623
624 /****************************************************************************
625  Reply to a unlink
626 ****************************************************************************/
627 void reply_unlink(struct smbsrv_request *req)
628 {
629         struct smb_unlink *unl;
630
631         /* parse the request */
632         REQ_CHECK_WCT(req, 1);
633         REQ_TALLOC(unl, sizeof(*unl));
634         
635         unl->in.attrib = SVAL(req->in.vwv, VWV(0));
636
637         req_pull_ascii4(req, &unl->in.pattern, req->in.data, STR_TERMINATE);
638         
639         req->async.send_fn = reply_simple_send;
640
641         /* call backend */
642         req->async.status = req->tcon->ntvfs_ops->unlink(req, unl);
643
644         REQ_ASYNC_TAIL;
645 }
646
647
648 /****************************************************************************
649  Reply to a readbraw (core+ protocol).
650  this is a strange packet because it doesn't use a standard SMB header in the reply,
651  only the 4 byte NBT header
652  This command must be replied to synchronously
653 ****************************************************************************/
654 void reply_readbraw(struct smbsrv_request *req)
655 {
656         NTSTATUS status;
657         union smb_read io;
658
659         io.readbraw.level = RAW_READ_READBRAW;
660
661         /* there are two variants, one with 10 and one with 8 command words */
662         if (req->in.wct != 10) {
663                 REQ_CHECK_WCT(req, 8);
664         }
665
666         io.readbraw.in.fnum    = req_fnum(req, req->in.vwv, VWV(0));
667         io.readbraw.in.offset  = IVAL(req->in.vwv, VWV(1));
668         io.readbraw.in.mincnt  = SVAL(req->in.vwv, VWV(3));
669         io.readbraw.in.maxcnt  = SVAL(req->in.vwv, VWV(4));
670         io.readbraw.in.timeout = IVAL(req->in.vwv, VWV(5));
671
672         /* the 64 bit variant */
673         if (req->in.wct == 10) {
674                 uint32_t offset_high = IVAL(req->in.vwv, VWV(8));
675                 io.readbraw.in.offset |= (((SMB_OFF_T)offset_high) << 32);
676         }
677
678         /* before calling the backend we setup the raw buffer. This
679          * saves a copy later */
680         req->out.size = io.readbraw.in.maxcnt + NBT_HDR_SIZE;
681         req->out.buffer = talloc(req, req->out.size);
682         if (req->out.buffer == NULL) {
683                 goto failed;
684         }
685         SIVAL(req->out.buffer, 0, 0); /* init NBT header */
686
687         /* tell the backend where to put the data */
688         io.readbraw.out.data = req->out.buffer + NBT_HDR_SIZE;
689
690         /* call the backend */
691         status = req->tcon->ntvfs_ops->read(req, &io);
692
693         if (!NT_STATUS_IS_OK(status)) {
694                 goto failed;
695         }
696
697         req->out.size = io.readbraw.out.nread + NBT_HDR_SIZE;
698
699         req_send_reply(req);
700         return;
701
702 failed:
703         /* any failure in readbraw is equivalent to reading zero bytes */
704         req->out.size = 4;
705         req->out.buffer = talloc(req, req->out.size);
706         SIVAL(req->out.buffer, 0, 0); /* init NBT header */
707
708         req_send_reply_nosign(req);
709 }
710
711
712 /****************************************************************************
713  Reply to a lockread (async reply)
714 ****************************************************************************/
715 static void reply_lockread_send(struct smbsrv_request *req)
716 {
717         union smb_read *io = req->async.private;
718
719         CHECK_ASYNC_STATUS;
720
721         /* trim packet */
722         io->lockread.out.nread = MIN(io->lockread.out.nread,
723                 req_max_data(req) - 3);
724         req_grow_data(req, 3 + io->lockread.out.nread);
725
726         /* construct reply */
727         SSVAL(req->out.vwv, VWV(0), io->lockread.out.nread);
728         REQ_VWV_RESERVED(1, 4);
729
730         SCVAL(req->out.data, 0, SMB_DATA_BLOCK);
731         SSVAL(req->out.data, 1, io->lockread.out.nread);
732
733         req_send_reply(req);
734 }
735
736
737 /****************************************************************************
738  Reply to a lockread (core+ protocol).
739  note that the lock is a write lock, not a read lock!
740 ****************************************************************************/
741 void reply_lockread(struct smbsrv_request *req)
742 {
743         union smb_read *io;
744         
745         /* parse request */
746         REQ_CHECK_WCT(req, 5);
747         REQ_TALLOC(io, sizeof(*io));
748
749         io->lockread.level = RAW_READ_LOCKREAD;
750         io->lockread.in.fnum      = req_fnum(req, req->in.vwv, VWV(0));
751         io->lockread.in.count     = SVAL(req->in.vwv, VWV(1));
752         io->lockread.in.offset    = IVAL(req->in.vwv, VWV(2));
753         io->lockread.in.remaining = SVAL(req->in.vwv, VWV(4));
754         
755         /* setup the reply packet assuming the maximum possible read */
756         req_setup_reply(req, 5, 3 + io->lockread.in.count);
757
758         /* tell the backend where to put the data */
759         io->lockread.out.data = req->out.data + 3;
760
761         req->async.send_fn = reply_lockread_send;
762         req->async.private = io;
763
764         /* call backend */
765         req->async.status = req->tcon->ntvfs_ops->read(req, io);
766
767         REQ_ASYNC_TAIL;
768 }
769
770
771
772 /****************************************************************************
773  Reply to a read (async reply)
774 ****************************************************************************/
775 static void reply_read_send(struct smbsrv_request *req)
776 {
777         union smb_read *io = req->async.private;
778
779         CHECK_ASYNC_STATUS;
780
781         /* trim packet */
782         io->read.out.nread = MIN(io->read.out.nread,
783                 req_max_data(req) - 3);
784         req_grow_data(req, 3 + io->read.out.nread);
785
786         /* construct reply */
787         SSVAL(req->out.vwv, VWV(0), io->read.out.nread);
788         REQ_VWV_RESERVED(1, 4);
789
790         SCVAL(req->out.data, 0, SMB_DATA_BLOCK);
791         SSVAL(req->out.data, 1, io->read.out.nread);
792
793         req_send_reply(req);
794 }
795
796 /****************************************************************************
797  Reply to a read.
798 ****************************************************************************/
799 void reply_read(struct smbsrv_request *req)
800 {
801         union smb_read *io;
802
803         /* parse request */
804         REQ_CHECK_WCT(req, 5);
805         REQ_TALLOC(io, sizeof(*io));
806         
807         io->read.level = RAW_READ_READ;
808         io->read.in.fnum          = req_fnum(req, req->in.vwv, VWV(0));
809         io->read.in.count         = SVAL(req->in.vwv, VWV(1));
810         io->read.in.offset        = IVAL(req->in.vwv, VWV(2));
811         io->read.in.remaining     = SVAL(req->in.vwv, VWV(4));
812         
813         /* setup the reply packet assuming the maximum possible read */
814         req_setup_reply(req, 5, 3 + io->read.in.count);
815
816         /* tell the backend where to put the data */
817         io->read.out.data = req->out.data + 3;
818
819         req->async.send_fn = reply_read_send;
820         req->async.private = io;
821
822         /* call backend */
823         req->async.status = req->tcon->ntvfs_ops->read(req, io);
824
825         REQ_ASYNC_TAIL;
826 }
827
828
829
830 /****************************************************************************
831  Reply to a read and X (async reply)
832 ****************************************************************************/
833 static void reply_read_and_X_send(struct smbsrv_request *req)
834 {
835         union smb_read *io = req->async.private;
836
837         CHECK_ASYNC_STATUS;
838
839         /* readx reply packets can be over-sized */
840         req->control_flags |= REQ_CONTROL_LARGE;
841         req_grow_data(req, 1 + io->readx.out.nread);
842
843         /* construct reply */
844         SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
845         SSVAL(req->out.vwv, VWV(1), 0);
846         SSVAL(req->out.vwv, VWV(2), io->readx.out.remaining);
847         SSVAL(req->out.vwv, VWV(3), io->readx.out.compaction_mode);
848         REQ_VWV_RESERVED(4, 1);
849         SSVAL(req->out.vwv, VWV(5), io->readx.out.nread);
850         SSVAL(req->out.vwv, VWV(6), PTR_DIFF(io->readx.out.data, req->out.hdr));
851         SCVAL(req->out.data, 0, 0); /* padding */
852         REQ_VWV_RESERVED(7, 5);
853
854         chain_reply(req);
855 }
856
857 /****************************************************************************
858  Reply to a read and X.
859 ****************************************************************************/
860 void reply_read_and_X(struct smbsrv_request *req)
861 {
862         union smb_read *io;
863
864         /* parse request */
865         if (req->in.wct != 12) {
866                 REQ_CHECK_WCT(req, 10);
867         }
868
869         REQ_TALLOC(io, sizeof(*io));
870
871         io->readx.level = RAW_READ_READX;
872         io->readx.in.fnum          = req_fnum(req, req->in.vwv, VWV(2));
873         io->readx.in.offset        = IVAL(req->in.vwv, VWV(3));
874         io->readx.in.maxcnt        = SVAL(req->in.vwv, VWV(5));
875         io->readx.in.mincnt        = SVAL(req->in.vwv, VWV(6));
876         io->readx.in.remaining     = SVAL(req->in.vwv, VWV(9));
877         
878         /* the 64 bit variant */
879         if (req->in.wct == 12) {
880                 uint32_t offset_high = IVAL(req->in.vwv, VWV(10));
881                 io->readx.in.offset |= (((uint64_t)offset_high) << 32);
882         }
883
884         /* setup the reply packet assuming the maximum possible read */
885         req_setup_reply(req, 12, 1 + io->readx.in.maxcnt);
886
887         /* tell the backend where to put the data. Notice the pad byte. */
888         io->readx.out.data = req->out.data + 1;
889
890         req->async.send_fn = reply_read_and_X_send;
891         req->async.private = io;
892
893         /* call backend */
894         req->async.status = req->tcon->ntvfs_ops->read(req, io);
895
896         REQ_ASYNC_TAIL;
897 }
898
899
900 /****************************************************************************
901  Reply to a writebraw (core+ or LANMAN1.0 protocol).
902 ****************************************************************************/
903 void reply_writebraw(struct smbsrv_request *req)
904 {
905         /* this one is damn complex - put it off for now */
906         req_reply_error(req, NT_STATUS_FOOBAR);
907 }
908
909
910 /****************************************************************************
911  Reply to a writeunlock (async reply)
912 ****************************************************************************/
913 static void reply_writeunlock_send(struct smbsrv_request *req)
914 {
915         union smb_write *io = req->async.private;
916
917         CHECK_ASYNC_STATUS;
918
919         /* construct reply */
920         req_setup_reply(req, 1, 0);
921
922         SSVAL(req->out.vwv, VWV(0), io->writeunlock.out.nwritten);
923
924         req_send_reply(req);
925 }
926
927 /****************************************************************************
928  Reply to a writeunlock (core+).
929 ****************************************************************************/
930 void reply_writeunlock(struct smbsrv_request *req)
931 {
932         union smb_write *io;
933
934         REQ_CHECK_WCT(req, 5);
935         REQ_TALLOC(io, sizeof(*io));
936
937         io->writeunlock.level = RAW_WRITE_WRITEUNLOCK;
938         io->writeunlock.in.fnum        = req_fnum(req, req->in.vwv, VWV(0));
939         io->writeunlock.in.count       = SVAL(req->in.vwv, VWV(1));
940         io->writeunlock.in.offset      = IVAL(req->in.vwv, VWV(2));
941         io->writeunlock.in.remaining   = SVAL(req->in.vwv, VWV(4));
942         io->writeunlock.in.data        = req->in.data + 3;
943
944         /* make sure they gave us the data they promised */
945         if (io->writeunlock.in.count+3 > req->in.data_size) {
946                 req_reply_error(req, NT_STATUS_FOOBAR);
947                 return;
948         }
949
950         /* make sure the data block is big enough */
951         if (SVAL(req->in.data, 1) < io->writeunlock.in.count) {
952                 req_reply_error(req, NT_STATUS_FOOBAR);
953                 return;
954         }
955
956         req->async.send_fn = reply_writeunlock_send;
957         req->async.private = io;
958
959         /* call backend */
960         req->async.status = req->tcon->ntvfs_ops->write(req, io);
961
962         REQ_ASYNC_TAIL;
963 }
964
965
966
967 /****************************************************************************
968  Reply to a write (async reply)
969 ****************************************************************************/
970 static void reply_write_send(struct smbsrv_request *req)
971 {
972         union smb_write *io = req->async.private;
973         
974         CHECK_ASYNC_STATUS;
975
976         /* construct reply */
977         req_setup_reply(req, 1, 0);
978
979         SSVAL(req->out.vwv, VWV(0), io->write.out.nwritten);
980
981         req_send_reply(req);
982 }
983
984 /****************************************************************************
985  Reply to a write
986 ****************************************************************************/
987 void reply_write(struct smbsrv_request *req)
988 {
989         union smb_write *io;
990
991         REQ_CHECK_WCT(req, 5);
992         REQ_TALLOC(io, sizeof(*io));
993
994         io->write.level = RAW_WRITE_WRITE;
995         io->write.in.fnum        = req_fnum(req, req->in.vwv, VWV(0));
996         io->write.in.count       = SVAL(req->in.vwv, VWV(1));
997         io->write.in.offset      = IVAL(req->in.vwv, VWV(2));
998         io->write.in.remaining   = SVAL(req->in.vwv, VWV(4));
999         io->write.in.data        = req->in.data + 3;
1000
1001         /* make sure they gave us the data they promised */
1002         if (req_data_oob(req, io->write.in.data, io->write.in.count)) {
1003                 req_reply_error(req, NT_STATUS_FOOBAR);
1004                 return;
1005         }
1006
1007         /* make sure the data block is big enough */
1008         if (SVAL(req->in.data, 1) < io->write.in.count) {
1009                 req_reply_error(req, NT_STATUS_FOOBAR);
1010                 return;
1011         }
1012
1013         req->async.send_fn = reply_write_send;
1014         req->async.private = io;
1015
1016         /* call backend */
1017         req->async.status = req->tcon->ntvfs_ops->write(req, io);
1018
1019         REQ_ASYNC_TAIL;
1020 }
1021
1022
1023 /****************************************************************************
1024  Reply to a write and X (async reply)
1025 ****************************************************************************/
1026 static void reply_write_and_X_send(struct smbsrv_request *req)
1027 {
1028         union smb_write *io = req->async.private;
1029
1030         CHECK_ASYNC_STATUS;
1031
1032         /* construct reply */
1033         req_setup_reply(req, 6, 0);
1034
1035         SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1036         SSVAL(req->out.vwv, VWV(1), 0);
1037         SSVAL(req->out.vwv, VWV(2), io->writex.out.nwritten & 0xFFFF);
1038         SSVAL(req->out.vwv, VWV(3), io->writex.out.remaining);
1039         SSVAL(req->out.vwv, VWV(4), io->writex.out.nwritten >> 16);
1040         REQ_VWV_RESERVED(5, 1);
1041
1042         chain_reply(req);
1043 }
1044
1045 /****************************************************************************
1046  Reply to a write and X.
1047 ****************************************************************************/
1048 void reply_write_and_X(struct smbsrv_request *req)
1049 {
1050         union smb_write *io;
1051         
1052         if (req->in.wct != 14) {
1053                 REQ_CHECK_WCT(req, 12);
1054         }
1055
1056         REQ_TALLOC(io, sizeof(*io));
1057
1058         io->writex.level = RAW_WRITE_WRITEX;
1059         io->writex.in.fnum      = req_fnum(req, req->in.vwv, VWV(2));
1060         io->writex.in.offset    = IVAL(req->in.vwv, VWV(3));
1061         io->writex.in.wmode     = SVAL(req->in.vwv, VWV(7));
1062         io->writex.in.remaining = SVAL(req->in.vwv, VWV(8));
1063         io->writex.in.count     = SVAL(req->in.vwv, VWV(10));
1064         io->writex.in.data      = req->in.hdr + SVAL(req->in.vwv, VWV(11));
1065
1066         if (req->in.wct == 14) {
1067                 uint32_t offset_high = IVAL(req->in.vwv, VWV(12));
1068                 uint16_t count_high = SVAL(req->in.vwv, VWV(9));
1069                 io->writex.in.offset |= (((uint64_t)offset_high) << 32);
1070                 io->writex.in.count |= ((uint32_t)count_high) << 16;
1071         }
1072
1073         /* make sure the data is in bounds */
1074         if (req_data_oob(req, io->writex.in.data, io->writex.in.count)) {
1075                 req_reply_error(req, NT_STATUS_FOOBAR);
1076                 return;
1077         } 
1078
1079         req->async.send_fn = reply_write_and_X_send;
1080         req->async.private = io;
1081
1082         /* call backend */
1083         req->async.status = req->tcon->ntvfs_ops->write(req, io);
1084
1085         REQ_ASYNC_TAIL;
1086 }
1087
1088
1089 /****************************************************************************
1090  Reply to a lseek (async reply)
1091 ****************************************************************************/
1092 static void reply_lseek_send(struct smbsrv_request *req)
1093 {
1094         struct smb_seek *io = req->async.private;
1095
1096         CHECK_ASYNC_STATUS;
1097
1098         /* construct reply */
1099         req_setup_reply(req, 2, 0);
1100
1101         SIVALS(req->out.vwv, VWV(0), io->out.offset);
1102
1103         req_send_reply(req);
1104 }
1105
1106 /****************************************************************************
1107  Reply to a lseek.
1108 ****************************************************************************/
1109 void reply_lseek(struct smbsrv_request *req)
1110 {
1111         struct smb_seek *io;
1112
1113         REQ_CHECK_WCT(req, 4);
1114         REQ_TALLOC(io, sizeof(*io));
1115
1116         io->in.fnum   = req_fnum(req, req->in.vwv,  VWV(0));
1117         io->in.mode   = SVAL(req->in.vwv,  VWV(1));
1118         io->in.offset = IVALS(req->in.vwv, VWV(2));
1119
1120         req->async.send_fn = reply_lseek_send;
1121         req->async.private = io;
1122         
1123         /* call backend */
1124         req->async.status = req->tcon->ntvfs_ops->seek(req, io);
1125
1126         REQ_ASYNC_TAIL;
1127 }
1128
1129 /****************************************************************************
1130  Reply to a flush.
1131 ****************************************************************************/
1132 void reply_flush(struct smbsrv_request *req)
1133 {
1134         struct smb_flush *io;
1135
1136         /* parse request */
1137         REQ_CHECK_WCT(req, 1);
1138         REQ_TALLOC(io, sizeof(*io));
1139
1140         io->in.fnum   = req_fnum(req, req->in.vwv,  VWV(0));
1141         
1142         req->async.send_fn = reply_simple_send;
1143
1144         /* call backend */
1145         req->async.status = req->tcon->ntvfs_ops->flush(req, io);
1146         
1147         REQ_ASYNC_TAIL;
1148 }
1149
1150
1151 /****************************************************************************
1152  Reply to a exit. This closes all files open by a smbpid
1153 ****************************************************************************/
1154 void reply_exit(struct smbsrv_request *req)
1155 {
1156         NTSTATUS status;
1157         struct smbsrv_tcon *tcon;
1158         REQ_CHECK_WCT(req, 0);
1159
1160         for (tcon=req->smb_conn->tree.tcons;tcon;tcon=tcon->next) {
1161                 req->tcon = tcon;
1162                 status = tcon->ntvfs_ops->exit(req);
1163                 req->tcon = NULL;
1164                 if (!NT_STATUS_IS_OK(status)) {
1165                         req_reply_error(req, status);
1166                         return;
1167                 }
1168         }
1169
1170         req_setup_reply(req, 0, 0);
1171         req_send_reply(req);
1172 }
1173
1174
1175 /****************************************************************************
1176  Reply to a close 
1177
1178  Note that this has to deal with closing a directory opened by NT SMB's.
1179 ****************************************************************************/
1180 void reply_close(struct smbsrv_request *req)
1181 {
1182         union smb_close *io;
1183
1184         /* parse request */
1185         REQ_CHECK_WCT(req, 3);
1186         REQ_TALLOC(io, sizeof(*io));
1187
1188         io->close.level = RAW_CLOSE_CLOSE;
1189         io->close.in.fnum  = req_fnum(req, req->in.vwv,  VWV(0));
1190         io->close.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(1));
1191
1192         req->async.send_fn = reply_simple_send;
1193
1194         /* call backend */
1195         req->async.status = req->tcon->ntvfs_ops->close(req, io);
1196
1197         REQ_ASYNC_TAIL;
1198 }
1199
1200
1201
1202 /****************************************************************************
1203  Reply to a writeclose (async reply)
1204 ****************************************************************************/
1205 static void reply_writeclose_send(struct smbsrv_request *req)
1206 {
1207         union smb_write *io = req->async.private;
1208
1209         CHECK_ASYNC_STATUS;
1210
1211         /* construct reply */
1212         req_setup_reply(req, 1, 0);
1213
1214         SSVAL(req->out.vwv, VWV(0), io->write.out.nwritten);
1215
1216         req_send_reply(req);
1217 }
1218
1219 /****************************************************************************
1220  Reply to a writeclose (Core+ protocol).
1221 ****************************************************************************/
1222 void reply_writeclose(struct smbsrv_request *req)
1223 {
1224         union smb_write *io;
1225
1226         /* this one is pretty weird - the wct can be 6 or 12 */
1227         if (req->in.wct != 12) {
1228                 REQ_CHECK_WCT(req, 6);
1229         }
1230
1231         REQ_TALLOC(io, sizeof(*io));
1232
1233         io->writeclose.level = RAW_WRITE_WRITECLOSE;
1234         io->writeclose.in.fnum   = req_fnum(req, req->in.vwv, VWV(0));
1235         io->writeclose.in.count  = SVAL(req->in.vwv, VWV(1));
1236         io->writeclose.in.offset = IVAL(req->in.vwv, VWV(2));
1237         io->writeclose.in.mtime  = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(4));
1238         io->writeclose.in.data   = req->in.data + 1;
1239
1240         /* make sure they gave us the data they promised */
1241         if (req_data_oob(req, io->writeclose.in.data, io->writeclose.in.count)) {
1242                 req_reply_error(req, NT_STATUS_FOOBAR);
1243                 return;
1244         }
1245
1246         req->async.send_fn = reply_writeclose_send;
1247         req->async.private = io;
1248
1249         /* call backend */
1250         req->async.status = req->tcon->ntvfs_ops->write(req, io);
1251
1252         REQ_ASYNC_TAIL;
1253 }
1254
1255 /****************************************************************************
1256  Reply to a lock.
1257 ****************************************************************************/
1258 void reply_lock(struct smbsrv_request *req)
1259 {
1260         union smb_lock *lck;
1261
1262         /* parse request */
1263         REQ_CHECK_WCT(req, 5);
1264         REQ_TALLOC(lck, sizeof(*lck));
1265
1266         lck->lock.level     = RAW_LOCK_LOCK;
1267         lck->lock.in.fnum   = req_fnum(req, req->in.vwv, VWV(0));
1268         lck->lock.in.count  = IVAL(req->in.vwv, VWV(1));
1269         lck->lock.in.offset = IVAL(req->in.vwv, VWV(3));
1270
1271         req->async.send_fn = reply_simple_send;
1272
1273         /* call backend */
1274         req->async.status = req->tcon->ntvfs_ops->lock(req, lck);
1275
1276         REQ_ASYNC_TAIL;
1277 }
1278
1279
1280 /****************************************************************************
1281  Reply to a unlock.
1282 ****************************************************************************/
1283 void reply_unlock(struct smbsrv_request *req)
1284 {
1285         union smb_lock *lck;
1286
1287         /* parse request */
1288         REQ_CHECK_WCT(req, 5);
1289         REQ_TALLOC(lck, sizeof(*lck));
1290
1291         lck->unlock.level = RAW_LOCK_UNLOCK;
1292         lck->unlock.in.fnum   = req_fnum(req, req->in.vwv, VWV(0));
1293         lck->unlock.in.count  = IVAL(req->in.vwv, VWV(1));
1294         lck->unlock.in.offset = IVAL(req->in.vwv, VWV(3));
1295
1296         req->async.send_fn = reply_simple_send;
1297
1298         /* call backend */
1299         req->async.status = req->tcon->ntvfs_ops->lock(req, lck);
1300
1301         REQ_ASYNC_TAIL;
1302 }
1303
1304
1305 /****************************************************************************
1306  Reply to a tdis.
1307 ****************************************************************************/
1308 void reply_tdis(struct smbsrv_request *req)
1309 {
1310         REQ_CHECK_WCT(req, 0);
1311
1312         close_cnum(req->tcon);
1313
1314         /* construct reply */
1315         req_setup_reply(req, 0, 0);
1316
1317         req_send_reply(req);
1318 }
1319
1320
1321 /****************************************************************************
1322  Reply to a echo. This is one of the few calls that is handled directly (the
1323  backends don't see it at all)
1324 ****************************************************************************/
1325 void reply_echo(struct smbsrv_request *req)
1326 {
1327         uint16_t count;
1328         int i;
1329
1330         REQ_CHECK_WCT(req, 0);
1331
1332         count = SVAL(req->in.vwv, VWV(0));
1333
1334         req_setup_reply(req, 1, req->in.data_size);
1335
1336         memcpy(req->out.data, req->in.data, req->in.data_size);
1337
1338         for (i=1; i <= count;i++) {
1339                 if (i != count) {
1340                         talloc_increase_ref_count(req);
1341                 }
1342
1343                 SSVAL(req->out.vwv, VWV(0), i);
1344                 req_send_reply(req);
1345         }
1346 }
1347
1348
1349
1350 /****************************************************************************
1351  Reply to a printopen (async reply)
1352 ****************************************************************************/
1353 static void reply_printopen_send(struct smbsrv_request *req)
1354 {
1355         union smb_open *oi = req->async.private;
1356
1357         CHECK_ASYNC_STATUS;
1358
1359         /* construct reply */
1360         req_setup_reply(req, 1, 0);
1361
1362         SSVAL(req->out.vwv, VWV(0), oi->open.out.fnum);
1363
1364         req_send_reply(req);
1365 }
1366
1367 /****************************************************************************
1368  Reply to a printopen.
1369 ****************************************************************************/
1370 void reply_printopen(struct smbsrv_request *req)
1371 {
1372         union smb_open *oi;
1373
1374         /* parse request */
1375         REQ_CHECK_WCT(req, 2);
1376         REQ_TALLOC(oi, sizeof(*oi));
1377
1378         oi->splopen.level = RAW_OPEN_SPLOPEN;
1379         oi->splopen.in.setup_length = SVAL(req->in.vwv, VWV(0));
1380         oi->splopen.in.mode         = SVAL(req->in.vwv, VWV(1));
1381
1382         req_pull_ascii4(req, &oi->splopen.in.ident, req->in.data, STR_TERMINATE);
1383
1384         req->async.send_fn = reply_printopen_send;
1385         req->async.private = oi;
1386
1387         /* call backend */
1388         req->async.status = req->tcon->ntvfs_ops->open(req, oi);
1389
1390         REQ_ASYNC_TAIL;
1391 }
1392
1393 /****************************************************************************
1394  Reply to a printclose.
1395 ****************************************************************************/
1396 void reply_printclose(struct smbsrv_request *req)
1397 {
1398         union smb_close *io;
1399
1400         /* parse request */
1401         REQ_CHECK_WCT(req, 3);
1402         REQ_TALLOC(io, sizeof(*io));
1403
1404         io->splclose.level = RAW_CLOSE_SPLCLOSE;
1405         io->splclose.in.fnum = req_fnum(req, req->in.vwv,  VWV(0));
1406
1407         req->async.send_fn = reply_simple_send;
1408
1409         /* call backend */
1410         req->async.status = req->tcon->ntvfs_ops->close(req, io);
1411
1412         REQ_ASYNC_TAIL;
1413 }
1414
1415 /****************************************************************************
1416  Reply to a printqueue.
1417 ****************************************************************************/
1418 void reply_printqueue_send(struct smbsrv_request *req)
1419 {
1420         union smb_lpq *lpq = req->async.private;
1421         int i, maxcount;
1422         const uint_t el_size = 28;      
1423
1424         CHECK_ASYNC_STATUS;
1425
1426         /* construct reply */
1427         req_setup_reply(req, 2, 0);
1428
1429         /* truncate the returned list to fit in the negotiated buffer size */
1430         maxcount = (req_max_data(req) - 3) / el_size;
1431         if (maxcount < lpq->retq.out.count) {
1432                 lpq->retq.out.count = maxcount;
1433         }
1434
1435         /* setup enough space in the reply */
1436         req_grow_data(req, 3 + el_size*lpq->retq.out.count);
1437         
1438         /* and fill it in */
1439         SSVAL(req->out.vwv, VWV(0), lpq->retq.out.count);
1440         SSVAL(req->out.vwv, VWV(1), lpq->retq.out.restart_idx);
1441
1442         SCVAL(req->out.data, 0, SMB_DATA_BLOCK);
1443         SSVAL(req->out.data, 1, el_size*lpq->retq.out.count);
1444
1445         req->out.ptr = req->out.data + 3;
1446
1447         for (i=0;i<lpq->retq.out.count;i++) {
1448                 srv_push_dos_date2(req->smb_conn, req->out.ptr, 0 , lpq->retq.out.queue[i].time);
1449                 SCVAL(req->out.ptr,  4, lpq->retq.out.queue[i].status);
1450                 SSVAL(req->out.ptr,  5, lpq->retq.out.queue[i].job);
1451                 SIVAL(req->out.ptr,  7, lpq->retq.out.queue[i].size);
1452                 SCVAL(req->out.ptr, 11, 0); /* reserved */
1453                 req_push_str(req, req->out.ptr+12, lpq->retq.out.queue[i].user, 16, STR_ASCII);
1454                 req->out.ptr += el_size;
1455         }
1456
1457         req_send_reply(req);
1458 }
1459
1460 /****************************************************************************
1461  Reply to a printqueue.
1462 ****************************************************************************/
1463 void reply_printqueue(struct smbsrv_request *req)
1464 {
1465         union smb_lpq *lpq;
1466
1467         /* parse request */
1468         REQ_CHECK_WCT(req, 2);
1469         REQ_TALLOC(lpq, sizeof(*lpq));
1470
1471         lpq->retq.level = RAW_LPQ_RETQ;
1472         lpq->retq.in.maxcount = SVAL(req->in.vwv,  VWV(0));
1473         lpq->retq.in.startidx = SVAL(req->in.vwv,  VWV(1));
1474
1475         req->async.send_fn = reply_printqueue_send;
1476         req->async.private = lpq;
1477
1478         /* call backend */
1479         req->async.status = req->tcon->ntvfs_ops->lpq(req, lpq);
1480
1481         REQ_ASYNC_TAIL;
1482 }
1483
1484
1485 /****************************************************************************
1486  Reply to a printwrite.
1487 ****************************************************************************/
1488 void reply_printwrite(struct smbsrv_request *req)
1489 {
1490         union smb_write *io;
1491
1492         /* parse request */
1493         REQ_CHECK_WCT(req, 1);
1494         REQ_TALLOC(io, sizeof(*io));
1495
1496         io->splwrite.level = RAW_WRITE_SPLWRITE;
1497
1498         if (req->in.data_size < 3) {
1499                 req_reply_error(req, NT_STATUS_FOOBAR);
1500                 return;
1501         }
1502
1503         io->splwrite.in.fnum  = req_fnum(req, req->in.vwv, VWV(0));
1504         io->splwrite.in.count = SVAL(req->in.data, 1);
1505         io->splwrite.in.data  = req->in.data + 3;
1506
1507         /* make sure they gave us the data they promised */
1508         if (req_data_oob(req, io->splwrite.in.data, io->splwrite.in.count)) {
1509                 req_reply_error(req, NT_STATUS_FOOBAR);
1510                 return;
1511         }
1512
1513         req->async.send_fn = reply_simple_send;
1514
1515         /* call backend */
1516         req->async.status = req->tcon->ntvfs_ops->write(req, io);
1517
1518         REQ_ASYNC_TAIL;
1519 }
1520
1521
1522 /****************************************************************************
1523  Reply to a mkdir.
1524 ****************************************************************************/
1525 void reply_mkdir(struct smbsrv_request *req)
1526 {
1527         union smb_mkdir *io;
1528
1529         /* parse the request */
1530         REQ_CHECK_WCT(req, 0);
1531         REQ_TALLOC(io, sizeof(*io));
1532
1533         io->generic.level = RAW_MKDIR_MKDIR;
1534         req_pull_ascii4(req, &io->mkdir.in.path, req->in.data, STR_TERMINATE);
1535
1536         req->async.send_fn = reply_simple_send;
1537
1538         /* call backend */
1539         req->async.status = req->tcon->ntvfs_ops->mkdir(req, io);
1540
1541         REQ_ASYNC_TAIL;
1542 }
1543
1544
1545 /****************************************************************************
1546  Reply to a rmdir.
1547 ****************************************************************************/
1548 void reply_rmdir(struct smbsrv_request *req)
1549 {
1550         struct smb_rmdir *io;
1551  
1552         /* parse the request */
1553         REQ_CHECK_WCT(req, 0);
1554         REQ_TALLOC(io, sizeof(*io));
1555
1556         req_pull_ascii4(req, &io->in.path, req->in.data, STR_TERMINATE);
1557
1558         req->async.send_fn = reply_simple_send;
1559
1560         /* call backend */
1561         req->async.status = req->tcon->ntvfs_ops->rmdir(req, io);
1562
1563         REQ_ASYNC_TAIL;
1564 }
1565
1566
1567 /****************************************************************************
1568  Reply to a mv.
1569 ****************************************************************************/
1570 void reply_mv(struct smbsrv_request *req)
1571 {
1572         union smb_rename *io;
1573         char *p;
1574  
1575         /* parse the request */
1576         REQ_CHECK_WCT(req, 1);
1577         REQ_TALLOC(io, sizeof(*io));
1578
1579         io->generic.level = RAW_RENAME_RENAME;
1580         io->rename.in.attrib = SVAL(req->in.vwv, VWV(0));
1581
1582         p = req->in.data;
1583         p += req_pull_ascii4(req, &io->rename.in.pattern1, p, STR_TERMINATE);
1584         p += req_pull_ascii4(req, &io->rename.in.pattern2, p, STR_TERMINATE);
1585
1586         if (!io->rename.in.pattern1 || !io->rename.in.pattern2) {
1587                 req_reply_error(req, NT_STATUS_FOOBAR);
1588                 return;
1589         }
1590
1591         req->async.send_fn = reply_simple_send;
1592
1593         /* call backend */
1594         req->async.status = req->tcon->ntvfs_ops->rename(req, io);
1595
1596         REQ_ASYNC_TAIL;
1597 }
1598
1599
1600 /****************************************************************************
1601  Reply to an NT rename.
1602 ****************************************************************************/
1603 void reply_ntrename(struct smbsrv_request *req)
1604 {
1605         union smb_rename *io;
1606         char *p;
1607  
1608         /* parse the request */
1609         REQ_CHECK_WCT(req, 4);
1610         REQ_TALLOC(io, sizeof(*io));
1611
1612         io->generic.level = RAW_RENAME_NTRENAME;
1613         io->ntrename.in.attrib  = SVAL(req->in.vwv, VWV(0));
1614         io->ntrename.in.flags   = SVAL(req->in.vwv, VWV(1));
1615         io->ntrename.in.cluster_size = IVAL(req->in.vwv, VWV(2));
1616
1617         p = req->in.data;
1618         p += req_pull_ascii4(req, &io->ntrename.in.old_name, p, STR_TERMINATE);
1619         p += req_pull_ascii4(req, &io->ntrename.in.new_name, p, STR_TERMINATE);
1620
1621         if (!io->ntrename.in.old_name || !io->ntrename.in.new_name) {
1622                 req_reply_error(req, NT_STATUS_FOOBAR);
1623                 return;
1624         }
1625
1626         req->async.send_fn = reply_simple_send;
1627
1628         /* call backend */
1629         req->async.status = req->tcon->ntvfs_ops->rename(req, io);
1630
1631         REQ_ASYNC_TAIL;
1632 }
1633
1634 /****************************************************************************
1635  Reply to a file copy (async reply)
1636 ****************************************************************************/
1637 static void reply_copy_send(struct smbsrv_request *req)
1638 {
1639         struct smb_copy *cp = req->async.private;
1640
1641         CHECK_ASYNC_STATUS;
1642
1643         /* build the reply */
1644         req_setup_reply(req, 1, 0);
1645
1646         SSVAL(req->out.vwv, VWV(0), cp->out.count);
1647
1648         req_send_reply(req);
1649 }
1650
1651 /****************************************************************************
1652  Reply to a file copy.
1653 ****************************************************************************/
1654 void reply_copy(struct smbsrv_request *req)
1655 {
1656         struct smb_copy *cp;
1657         char *p;
1658
1659         /* parse request */
1660         REQ_CHECK_WCT(req, 3);
1661         REQ_TALLOC(cp, sizeof(*cp));
1662
1663         cp->in.tid2  = SVAL(req->in.vwv, VWV(0));
1664         cp->in.ofun  = SVAL(req->in.vwv, VWV(1));
1665         cp->in.flags = SVAL(req->in.vwv, VWV(2));
1666
1667         p = req->in.data;
1668         p += req_pull_ascii4(req, &cp->in.path1, p, STR_TERMINATE);
1669         p += req_pull_ascii4(req, &cp->in.path2, p, STR_TERMINATE);
1670
1671         if (!cp->in.path1 || !cp->in.path2) {
1672                 req_reply_error(req, NT_STATUS_FOOBAR);
1673                 return;
1674         }
1675
1676         req->async.send_fn = reply_copy_send;
1677         req->async.private = cp;
1678
1679         /* call backend */
1680         req->async.status = req->tcon->ntvfs_ops->copy(req, cp);
1681
1682         REQ_ASYNC_TAIL;
1683 }
1684
1685 /****************************************************************************
1686  Reply to a lockingX request (async send)
1687 ****************************************************************************/
1688 static void reply_lockingX_send(struct smbsrv_request *req)
1689 {
1690         union smb_lock *lck = req->async.private;
1691
1692         CHECK_ASYNC_STATUS;
1693
1694         /* if it was an oplock break ack then we only send a reply if
1695            there was an error */
1696         if (lck->lockx.in.ulock_cnt + lck->lockx.in.lock_cnt == 0) {
1697                 req_destroy(req);
1698                 return;
1699         }
1700
1701         /* construct reply */
1702         req_setup_reply(req, 2, 0);
1703         
1704         SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1705         SSVAL(req->out.vwv, VWV(1), 0);
1706
1707         chain_reply(req);
1708 }
1709
1710
1711 /****************************************************************************
1712  Reply to a lockingX request.
1713 ****************************************************************************/
1714 void reply_lockingX(struct smbsrv_request *req)
1715 {
1716         union smb_lock *lck;
1717         uint_t total_locks, i;
1718         uint_t lck_size;
1719         char *p;
1720
1721         /* parse request */
1722         REQ_CHECK_WCT(req, 8);
1723         REQ_TALLOC(lck, sizeof(*lck));
1724
1725         lck->lockx.level = RAW_LOCK_LOCKX;
1726         lck->lockx.in.fnum      = req_fnum(req, req->in.vwv, VWV(2));
1727         lck->lockx.in.mode      = SVAL(req->in.vwv, VWV(3));
1728         lck->lockx.in.timeout   = IVAL(req->in.vwv, VWV(4));
1729         lck->lockx.in.ulock_cnt = SVAL(req->in.vwv, VWV(6));
1730         lck->lockx.in.lock_cnt  = SVAL(req->in.vwv, VWV(7));
1731
1732         total_locks = lck->lockx.in.ulock_cnt + lck->lockx.in.lock_cnt;
1733
1734         /* there are two variants, one with 64 bit offsets and counts */
1735         if (lck->lockx.in.mode & LOCKING_ANDX_LARGE_FILES) {
1736                 lck_size = 20;
1737         } else {
1738                 lck_size = 10;          
1739         }
1740
1741         /* make sure we got the promised data */
1742         if (req_data_oob(req, req->in.data, total_locks * lck_size)) {
1743                 req_reply_error(req, NT_STATUS_FOOBAR);
1744                 return;
1745         }
1746
1747         /* allocate the locks array */
1748         if (total_locks) {
1749                 REQ_TALLOC(lck->lockx.in.locks, total_locks * sizeof(lck->lockx.in.locks[0]));
1750         }
1751
1752         p = req->in.data;
1753
1754         /* construct the locks array */
1755         for (i=0;i<total_locks;i++) {
1756                 uint32_t ofs_high=0, count_high=0;
1757
1758                 lck->lockx.in.locks[i].pid = SVAL(p, 0);
1759
1760                 if (lck->lockx.in.mode & LOCKING_ANDX_LARGE_FILES) {
1761                         ofs_high   = IVAL(p, 4);
1762                         lck->lockx.in.locks[i].offset = IVAL(p, 8);
1763                         count_high = IVAL(p, 12);
1764                         lck->lockx.in.locks[i].count  = IVAL(p, 16);
1765                 } else {
1766                         lck->lockx.in.locks[i].offset = IVAL(p, 2);
1767                         lck->lockx.in.locks[i].count  = IVAL(p, 6);
1768                 }
1769                 if (ofs_high != 0 || count_high != 0) {
1770                         lck->lockx.in.locks[i].count  |= ((uint64_t)count_high) << 32;
1771                         lck->lockx.in.locks[i].offset |= ((uint64_t)ofs_high) << 32;
1772                 }
1773                 p += lck_size;
1774         }
1775
1776         req->async.send_fn = reply_lockingX_send;
1777         req->async.private = lck;
1778
1779         /* call backend */
1780         req->async.status = req->tcon->ntvfs_ops->lock(req, lck);
1781
1782         REQ_ASYNC_TAIL;
1783 }
1784
1785 /****************************************************************************
1786  Reply to a SMBreadbmpx (read block multiplex) request.
1787 ****************************************************************************/
1788 void reply_readbmpx(struct smbsrv_request *req)
1789 {
1790         /* tell the client to not use a multiplexed read - its too broken to use */
1791         req_reply_dos_error(req, ERRSRV, ERRuseSTD);
1792 }
1793
1794
1795 /****************************************************************************
1796  Reply to a SMBsetattrE.
1797 ****************************************************************************/
1798 void reply_setattrE(struct smbsrv_request *req)
1799 {
1800         union smb_setfileinfo *info;
1801
1802         /* parse request */
1803         REQ_CHECK_WCT(req, 7);
1804         REQ_TALLOC(info, sizeof(*info));
1805
1806         info->setattre.level = RAW_SFILEINFO_SETATTRE;
1807         info->setattre.file.fnum =      req_fnum(req, req->in.vwv,    VWV(0));
1808         info->setattre.in.create_time = srv_pull_dos_date2(req->smb_conn, req->in.vwv + VWV(1));
1809         info->setattre.in.access_time = srv_pull_dos_date2(req->smb_conn, req->in.vwv + VWV(3));
1810         info->setattre.in.write_time  = srv_pull_dos_date2(req->smb_conn, req->in.vwv + VWV(5));
1811
1812         req->async.send_fn = reply_simple_send;
1813
1814         /* call backend */
1815         req->async.status = req->tcon->ntvfs_ops->setfileinfo(req, info);
1816
1817         REQ_ASYNC_TAIL;
1818 }
1819
1820
1821 /****************************************************************************
1822  Reply to a SMBwritebmpx (write block multiplex primary) request.
1823 ****************************************************************************/
1824 void reply_writebmpx(struct smbsrv_request *req)
1825 {
1826         /* we will need to implement this one for OS/2, but right now I can't be bothered */
1827         req_reply_error(req, NT_STATUS_FOOBAR);
1828 }
1829
1830
1831 /****************************************************************************
1832  Reply to a SMBwritebs (write block multiplex secondary) request.
1833 ****************************************************************************/
1834 void reply_writebs(struct smbsrv_request *req)
1835 {
1836         /* see reply_writebmpx */
1837         req_reply_error(req, NT_STATUS_FOOBAR);
1838 }
1839
1840
1841
1842 /****************************************************************************
1843  Reply to a SMBgetattrE (async reply)
1844 ****************************************************************************/
1845 static void reply_getattrE_send(struct smbsrv_request *req)
1846 {
1847         union smb_fileinfo *info = req->async.private;
1848
1849         CHECK_ASYNC_STATUS;
1850
1851         /* setup reply */
1852         req_setup_reply(req, 11, 0);
1853
1854         srv_push_dos_date2(req->smb_conn, req->out.vwv, VWV(0), info->getattre.out.create_time);
1855         srv_push_dos_date2(req->smb_conn, req->out.vwv, VWV(2), info->getattre.out.access_time);
1856         srv_push_dos_date2(req->smb_conn, req->out.vwv, VWV(4), info->getattre.out.write_time);
1857         SIVAL(req->out.vwv,         VWV(6), info->getattre.out.size);
1858         SIVAL(req->out.vwv,         VWV(8), info->getattre.out.alloc_size);
1859         SSVAL(req->out.vwv,        VWV(10), info->getattre.out.attrib);
1860
1861         req_send_reply(req);
1862 }
1863
1864 /****************************************************************************
1865  Reply to a SMBgetattrE.
1866 ****************************************************************************/
1867 void reply_getattrE(struct smbsrv_request *req)
1868 {
1869         union smb_fileinfo *info;
1870
1871         /* parse request */
1872         REQ_CHECK_WCT(req, 1);
1873         REQ_TALLOC(info, sizeof(*info));
1874
1875         info->getattr.level = RAW_FILEINFO_GETATTRE;
1876         info->getattr.in.fnum = req_fnum(req, req->in.vwv, VWV(0));
1877
1878         req->async.send_fn = reply_getattrE_send;
1879         req->async.private = info;
1880
1881         /* call backend */
1882         req->async.status = req->tcon->ntvfs_ops->qfileinfo(req, info);
1883
1884         REQ_ASYNC_TAIL;
1885 }
1886
1887
1888 /****************************************************************************
1889 reply to an old style session setup command
1890 ****************************************************************************/
1891 static void reply_sesssetup_old(struct smbsrv_request *req)
1892 {
1893         NTSTATUS status;
1894         union smb_sesssetup sess;
1895         char *p;
1896         uint16_t passlen;
1897
1898         sess.old.level = RAW_SESSSETUP_OLD;
1899
1900         /* parse request */
1901         sess.old.in.bufsize = SVAL(req->in.vwv, VWV(2));
1902         sess.old.in.mpx_max = SVAL(req->in.vwv, VWV(3));
1903         sess.old.in.vc_num  = SVAL(req->in.vwv, VWV(4));
1904         sess.old.in.sesskey = IVAL(req->in.vwv, VWV(5));
1905         passlen             = SVAL(req->in.vwv, VWV(7));
1906
1907         /* check the request isn't malformed */
1908         if (req_data_oob(req, req->in.data, passlen)) {
1909                 req_reply_error(req, NT_STATUS_FOOBAR);
1910                 return;
1911         }
1912         
1913         p = req->in.data;
1914         if (!req_pull_blob(req, p, passlen, &sess.old.in.password)) {
1915                 req_reply_error(req, NT_STATUS_FOOBAR);
1916                 return;
1917         }
1918         p += passlen;
1919         
1920         p += req_pull_string(req, &sess.old.in.user,   p, -1, STR_TERMINATE);
1921         p += req_pull_string(req, &sess.old.in.domain, p, -1, STR_TERMINATE);
1922         p += req_pull_string(req, &sess.old.in.os,     p, -1, STR_TERMINATE);
1923         p += req_pull_string(req, &sess.old.in.lanman, p, -1, STR_TERMINATE);
1924
1925         /* call the generic handler */
1926         status = sesssetup_backend(req, &sess);
1927
1928         if (!NT_STATUS_IS_OK(status)) {
1929                 req_reply_error(req, status);
1930                 return;
1931         }
1932
1933         /* construct reply */
1934         req_setup_reply(req, 3, 0);
1935
1936         SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
1937         SSVAL(req->out.vwv, VWV(1), 0);
1938         SSVAL(req->out.vwv, VWV(2), sess.old.out.action);
1939
1940         SSVAL(req->out.hdr, HDR_UID, sess.old.out.vuid);
1941
1942         chain_reply(req);
1943 }
1944
1945
1946 /****************************************************************************
1947 reply to an NT1 style session setup command
1948 ****************************************************************************/
1949 static void reply_sesssetup_nt1(struct smbsrv_request *req)
1950 {
1951         NTSTATUS status;
1952         union smb_sesssetup sess;
1953         char *p;
1954         uint16_t passlen1, passlen2;
1955
1956         sess.nt1.level = RAW_SESSSETUP_NT1;
1957
1958         /* parse request */
1959         sess.nt1.in.bufsize      = SVAL(req->in.vwv, VWV(2));
1960         sess.nt1.in.mpx_max      = SVAL(req->in.vwv, VWV(3));
1961         sess.nt1.in.vc_num       = SVAL(req->in.vwv, VWV(4));
1962         sess.nt1.in.sesskey      = IVAL(req->in.vwv, VWV(5));
1963         passlen1                 = SVAL(req->in.vwv, VWV(7));
1964         passlen2                 = SVAL(req->in.vwv, VWV(8));
1965         sess.nt1.in.capabilities = IVAL(req->in.vwv, VWV(11));
1966
1967         /* check the request isn't malformed */
1968         if (req_data_oob(req, req->in.data, passlen1) ||
1969             req_data_oob(req, req->in.data + passlen1, passlen2)) {
1970                 req_reply_error(req, NT_STATUS_FOOBAR);
1971                 return;
1972         }
1973         
1974         p = req->in.data;
1975         if (!req_pull_blob(req, p, passlen1, &sess.nt1.in.password1)) {
1976                 req_reply_error(req, NT_STATUS_FOOBAR);
1977                 return;
1978         }
1979         p += passlen1;
1980         if (!req_pull_blob(req, p, passlen2, &sess.nt1.in.password2)) {
1981                 req_reply_error(req, NT_STATUS_FOOBAR);
1982                 return;
1983         }
1984         p += passlen2;
1985         
1986         p += req_pull_string(req, &sess.nt1.in.user,   p, -1, STR_TERMINATE);
1987         p += req_pull_string(req, &sess.nt1.in.domain, p, -1, STR_TERMINATE);
1988         p += req_pull_string(req, &sess.nt1.in.os,     p, -1, STR_TERMINATE);
1989         p += req_pull_string(req, &sess.nt1.in.lanman, p, -1, STR_TERMINATE);
1990
1991         /* call the generic handler */
1992         status = sesssetup_backend(req, &sess);
1993
1994         if (!NT_STATUS_IS_OK(status)) {
1995                 req_reply_error(req, status);
1996                 return;
1997         }
1998
1999         /* construct reply */
2000         req_setup_reply(req, 3, 0);
2001
2002         SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
2003         SSVAL(req->out.vwv, VWV(1), 0);
2004         SSVAL(req->out.vwv, VWV(2), sess.nt1.out.action);
2005
2006         SSVAL(req->out.hdr, HDR_UID, sess.nt1.out.vuid);
2007
2008         req_push_str(req, NULL, sess.nt1.out.os, -1, STR_TERMINATE);
2009         req_push_str(req, NULL, sess.nt1.out.lanman, -1, STR_TERMINATE);
2010         req_push_str(req, NULL, sess.nt1.out.domain, -1, STR_TERMINATE);
2011
2012         chain_reply(req);
2013 }
2014
2015
2016 /****************************************************************************
2017 reply to an SPNEGO style session setup command
2018 ****************************************************************************/
2019 static void reply_sesssetup_spnego(struct smbsrv_request *req)
2020 {
2021         NTSTATUS status;
2022         union smb_sesssetup sess;
2023         char *p;
2024         uint16_t blob_len;
2025
2026         sess.spnego.level = RAW_SESSSETUP_SPNEGO;
2027
2028         /* parse request */
2029         sess.spnego.in.bufsize      = SVAL(req->in.vwv, VWV(2));
2030         sess.spnego.in.mpx_max      = SVAL(req->in.vwv, VWV(3));
2031         sess.spnego.in.vc_num       = SVAL(req->in.vwv, VWV(4));
2032         sess.spnego.in.sesskey      = IVAL(req->in.vwv, VWV(5));
2033         blob_len                    = SVAL(req->in.vwv, VWV(7));
2034         sess.spnego.in.capabilities = IVAL(req->in.vwv, VWV(10));
2035
2036         p = req->in.data;
2037         if (!req_pull_blob(req, p, blob_len, &sess.spnego.in.secblob)) {
2038                 req_reply_error(req, NT_STATUS_FOOBAR);
2039                 return;
2040         }
2041         p += blob_len;
2042         
2043         p += req_pull_string(req, &sess.spnego.in.os,     p, -1, STR_TERMINATE);
2044         p += req_pull_string(req, &sess.spnego.in.lanman, p, -1, STR_TERMINATE);
2045         p += req_pull_string(req, &sess.spnego.in.domain, p, -1, STR_TERMINATE);
2046
2047         /* call the generic handler */
2048         status = sesssetup_backend(req, &sess);
2049
2050         if (!NT_STATUS_IS_OK(status) && 
2051             !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
2052                 req_reply_error(req, status);
2053                 return;
2054         }
2055
2056         /* construct reply */
2057         req_setup_reply(req, 4, sess.spnego.out.secblob.length);
2058
2059         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
2060                 req_setup_error(req, status);
2061         }
2062
2063         SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
2064         SSVAL(req->out.vwv, VWV(1), 0);
2065         SSVAL(req->out.vwv, VWV(2), sess.spnego.out.action);
2066         SSVAL(req->out.vwv, VWV(3), sess.spnego.out.secblob.length);
2067
2068         SSVAL(req->out.hdr, HDR_UID, sess.spnego.out.vuid);
2069
2070         memcpy(req->out.data, sess.spnego.out.secblob.data, sess.spnego.out.secblob.length);
2071         req_push_str(req, NULL, sess.spnego.out.os, -1, STR_TERMINATE);
2072         req_push_str(req, NULL, sess.spnego.out.lanman, -1, STR_TERMINATE);
2073         req_push_str(req, NULL, sess.spnego.out.domain, -1, STR_TERMINATE);
2074
2075         chain_reply(req);
2076 }
2077
2078
2079 /****************************************************************************
2080 reply to a session setup command
2081 ****************************************************************************/
2082 void reply_sesssetup(struct smbsrv_request *req)
2083 {
2084         switch (req->in.wct) {
2085         case 10:
2086                 /* a pre-NT1 call */
2087                 reply_sesssetup_old(req);
2088                 return;
2089         case 13:
2090                 /* a NT1 call */
2091                 reply_sesssetup_nt1(req);
2092                 return;
2093         case 12:
2094                 /* a SPNEGO call */
2095                 reply_sesssetup_spnego(req);
2096                 return;
2097         }
2098
2099         /* unsupported variant */
2100         req_reply_error(req, NT_STATUS_FOOBAR);
2101 }
2102
2103 /****************************************************************************
2104  Reply to a SMBulogoffX.
2105 ****************************************************************************/
2106 void reply_ulogoffX(struct smbsrv_request *req)
2107 {
2108         struct smbsrv_tcon *tcon;
2109         uint16_t vuid;
2110         NTSTATUS status;
2111
2112         vuid = SVAL(req->in.hdr, HDR_UID);
2113
2114         /* in user level security we are supposed to close any files
2115            open by this user on all open tree connects */
2116         if ((vuid != 0) && (lp_security() != SEC_SHARE)) {
2117                 for (tcon=req->smb_conn->tree.tcons;tcon;tcon=tcon->next) {
2118                         req->tcon = tcon;
2119                         status = tcon->ntvfs_ops->logoff(req);
2120                         req->tcon = NULL;
2121                         if (!NT_STATUS_IS_OK(status)) {
2122                                 req_reply_error(req, status);
2123                                 return;
2124                         }
2125                 }
2126         }
2127
2128         smbsrv_invalidate_vuid(req->smb_conn, vuid);
2129
2130         req_setup_reply(req, 2, 0);
2131
2132         SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
2133         SSVAL(req->out.vwv, VWV(1), 0); 
2134         
2135         chain_reply(req);
2136 }
2137
2138
2139 /****************************************************************************
2140  Reply to an SMBfindclose request
2141 ****************************************************************************/
2142 void reply_findclose(struct smbsrv_request *req)
2143 {
2144         NTSTATUS status;
2145         union smb_search_close io;
2146
2147         io.findclose.level = RAW_FINDCLOSE_FINDCLOSE;
2148
2149         /* parse request */
2150         REQ_CHECK_WCT(req, 1);
2151
2152         io.findclose.in.handle  = SVAL(req->in.vwv, VWV(0));
2153         
2154         /* call backend */
2155         status = req->tcon->ntvfs_ops->search_close(req, &io);
2156
2157         if (!NT_STATUS_IS_OK(status)) {
2158                 req_reply_error(req, status);
2159                 return;
2160         }
2161
2162         /* construct reply */
2163         req_setup_reply(req, 0, 0);
2164
2165         req_send_reply(req);    
2166 }
2167
2168 /****************************************************************************
2169  Reply to an SMBfindnclose request
2170 ****************************************************************************/
2171 void reply_findnclose(struct smbsrv_request *req)
2172 {
2173         req_reply_error(req, NT_STATUS_FOOBAR);
2174 }
2175
2176
2177 /****************************************************************************
2178  Reply to an SMBntcreateX request (async send)
2179 ****************************************************************************/
2180 static void reply_ntcreate_and_X_send(struct smbsrv_request *req)
2181 {
2182         union smb_open *io = req->async.private;
2183
2184         CHECK_ASYNC_STATUS;
2185
2186         /* construct reply */
2187         req_setup_reply(req, 34, 0);
2188
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);
2192
2193         /* the rest of the parameters are not aligned! */
2194         SSVAL(req->out.vwv,        5, io->ntcreatex.out.fnum);
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);
2206
2207         chain_reply(req);
2208 }
2209
2210 /****************************************************************************
2211  Reply to an SMBntcreateX request
2212 ****************************************************************************/
2213 void reply_ntcreate_and_X(struct smbsrv_request *req)
2214 {
2215         union smb_open *io;
2216         uint16_t fname_len;
2217
2218         /* parse the request */
2219         REQ_CHECK_WCT(req, 24);
2220         REQ_TALLOC(io, sizeof(*io));
2221
2222         io->ntcreatex.level = RAW_OPEN_NTCREATEX;
2223
2224         /* notice that the word parameters are not word aligned, so we don't use VWV() */
2225         fname_len =                         SVAL(req->in.vwv, 5);
2226         io->ntcreatex.in.flags =            IVAL(req->in.vwv, 7);
2227         io->ntcreatex.in.root_fid =         IVAL(req->in.vwv, 11);
2228         io->ntcreatex.in.access_mask =      IVAL(req->in.vwv, 15);
2229         io->ntcreatex.in.alloc_size =       BVAL(req->in.vwv, 19);
2230         io->ntcreatex.in.file_attr =        IVAL(req->in.vwv, 27);
2231         io->ntcreatex.in.share_access =     IVAL(req->in.vwv, 31);
2232         io->ntcreatex.in.open_disposition = IVAL(req->in.vwv, 35);
2233         io->ntcreatex.in.create_options =   IVAL(req->in.vwv, 39);
2234         io->ntcreatex.in.impersonation =    IVAL(req->in.vwv, 43);
2235         io->ntcreatex.in.security_flags =   CVAL(req->in.vwv, 47);
2236
2237         /* we need a neater way to handle this alignment */
2238         if ((req->flags2 & FLAGS2_UNICODE_STRINGS) && 
2239             ucs2_align(req->in.buffer, req->in.data, STR_TERMINATE|STR_UNICODE)) {
2240                 fname_len++;
2241         }
2242
2243         req_pull_string(req, &io->ntcreatex.in.fname, req->in.data, fname_len, STR_TERMINATE);
2244         if (!io->ntcreatex.in.fname) {
2245                 req_reply_error(req, NT_STATUS_FOOBAR);
2246                 return;
2247         }
2248
2249         req->async.send_fn = reply_ntcreate_and_X_send;
2250         req->async.private = io;
2251
2252         /* call the backend */
2253         req->async.status = req->tcon->ntvfs_ops->open(req, io);
2254
2255         REQ_ASYNC_TAIL;
2256 }
2257
2258
2259 /****************************************************************************
2260  Reply to an SMBntcancel request
2261 ****************************************************************************/
2262 void reply_ntcancel(struct smbsrv_request *req)
2263 {
2264         req_reply_error(req, NT_STATUS_FOOBAR);
2265 }
2266
2267 /****************************************************************************
2268  Reply to an SMBsends request
2269 ****************************************************************************/
2270 void reply_sends(struct smbsrv_request *req)
2271 {
2272         req_reply_error(req, NT_STATUS_FOOBAR);
2273 }
2274
2275 /****************************************************************************
2276  Reply to an SMBsendstrt request
2277 ****************************************************************************/
2278 void reply_sendstrt(struct smbsrv_request *req)
2279 {
2280         req_reply_error(req, NT_STATUS_FOOBAR);
2281 }
2282
2283 /****************************************************************************
2284  Reply to an SMBsendend request
2285 ****************************************************************************/
2286 void reply_sendend(struct smbsrv_request *req)
2287 {
2288         req_reply_error(req, NT_STATUS_FOOBAR);
2289 }
2290
2291 /****************************************************************************
2292  Reply to an SMBsendtxt request
2293 ****************************************************************************/
2294 void reply_sendtxt(struct smbsrv_request *req)
2295 {
2296         req_reply_error(req, NT_STATUS_FOOBAR);
2297 }
2298
2299
2300
2301 /****************************************************************************
2302  Reply to a special message - a SMB packet with non zero NBT message type
2303 ****************************************************************************/
2304 void reply_special(struct smbsrv_request *req)
2305 {
2306         uint8_t msg_type;
2307         char buf[4];
2308         
2309         msg_type = CVAL(req->in.buffer,0);
2310
2311         SIVAL(buf, 0, 0);
2312         
2313         switch (msg_type) {
2314         case 0x81: /* session request */
2315                 if (req->smb_conn->negotiate.done_nbt_session) {
2316                         smbsrv_terminate_connection(req->smb_conn, "multiple session request not permitted");
2317                 }
2318                 
2319                 SCVAL(buf,0,0x82);
2320                 SCVAL(buf,3,0);
2321                 
2322                 DEBUG(0,("REWRITE: not parsing netbios names in NBT session request!\n"));
2323                 /* TODO: store the name for the session setup 'remote machine' code, as well as smbstatus */
2324
2325                 req->smb_conn->negotiate.done_nbt_session = True;
2326                 
2327                 req->out.buffer = buf;
2328                 req->out.size = 4;
2329                 req_send_reply_nosign(req);
2330                 return;
2331                 
2332         case 0x89: /* session keepalive request 
2333                       (some old clients produce this?) */
2334                 SCVAL(buf, 0, SMBkeepalive);
2335                 SCVAL(buf, 3, 0);
2336                 req->out.buffer = buf;
2337                 req->out.size = 4;
2338                 req_send_reply_nosign(req);
2339                 return;
2340                 
2341         case SMBkeepalive: 
2342                 /* session keepalive - swallow it */
2343                 req_destroy(req);
2344                 return;
2345         }
2346
2347         DEBUG(0,("Unexpected NBT session packet (%d)\n", msg_type));
2348         req_destroy(req);
2349 }