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