Install public header files again and include required prototypes.
[jelmer/samba4-debian.git] / source / smb_server / smb / trans2.c
1 /* 
2    Unix SMB/CIFS implementation.
3    transaction2 handling
4    Copyright (C) Andrew Tridgell 2003
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 /*
20    This file handles the parsing of transact2 requests
21 */
22
23 #include "includes.h"
24 #include "lib/util/dlinklist.h"
25 #include "smb_server/smb_server.h"
26 #include "librpc/gen_ndr/ndr_misc.h"
27 #include "ntvfs/ntvfs.h"
28 #include "libcli/raw/libcliraw.h"
29 #include "libcli/raw/raw_proto.h"
30
31 #define TRANS2_CHECK_ASYNC_STATUS_SIMPLE do { \
32         if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) { \
33                 trans2_setup_reply(trans, 0, 0, 0);\
34                 return req->ntvfs->async_states->status; \
35         } \
36 } while (0)
37 #define TRANS2_CHECK_ASYNC_STATUS(ptr, type) do { \
38         TRANS2_CHECK_ASYNC_STATUS_SIMPLE; \
39         ptr = talloc_get_type(op->op_info, type); \
40 } while (0)
41 #define TRANS2_CHECK(cmd) do { \
42         NTSTATUS _status; \
43         _status = cmd; \
44         NT_STATUS_NOT_OK_RETURN(_status); \
45 } while (0)
46
47 /*
48   hold the state of a nttrans op while in progress. Needed to allow for async backend
49   functions.
50 */
51 struct trans_op {
52         struct smbsrv_request *req;
53         struct smb_trans2 *trans;
54         uint8_t command;
55         NTSTATUS (*send_fn)(struct trans_op *);
56         void *op_info;
57 };
58
59 #define CHECK_MIN_BLOB_SIZE(blob, size) do { \
60         if ((blob)->length < (size)) { \
61                 return NT_STATUS_INFO_LENGTH_MISMATCH; \
62         }} while (0)
63
64 /* setup a trans2 reply, given the data and params sizes */
65 static NTSTATUS trans2_setup_reply(struct smb_trans2 *trans,
66                                    uint16_t param_size, uint16_t data_size,
67                                    uint16_t setup_count)
68 {
69         trans->out.setup_count = setup_count;
70         if (setup_count > 0) {
71                 trans->out.setup = talloc_zero_array(trans, uint16_t, setup_count);
72                 NT_STATUS_HAVE_NO_MEMORY(trans->out.setup);
73         }
74         trans->out.params = data_blob_talloc(trans, NULL, param_size);
75         if (param_size > 0) NT_STATUS_HAVE_NO_MEMORY(trans->out.params.data);
76
77         trans->out.data = data_blob_talloc(trans, NULL, data_size);
78         if (data_size > 0) NT_STATUS_HAVE_NO_MEMORY(trans->out.data.data);
79
80         return NT_STATUS_OK;
81 }
82
83 static NTSTATUS trans2_push_fsinfo(struct smbsrv_connection *smb_conn,
84                                    TALLOC_CTX *mem_ctx,
85                                    DATA_BLOB *blob,
86                                    union smb_fsinfo *fsinfo,
87                                    int default_str_flags)
88 {
89         enum smb_fsinfo_level passthru_level;
90
91         switch (fsinfo->generic.level) {
92         case RAW_QFS_ALLOCATION:
93                 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 18));
94
95                 SIVAL(blob->data,  0, fsinfo->allocation.out.fs_id);
96                 SIVAL(blob->data,  4, fsinfo->allocation.out.sectors_per_unit);
97                 SIVAL(blob->data,  8, fsinfo->allocation.out.total_alloc_units);
98                 SIVAL(blob->data, 12, fsinfo->allocation.out.avail_alloc_units);
99                 SSVAL(blob->data, 16, fsinfo->allocation.out.bytes_per_sector);
100
101                 return NT_STATUS_OK;
102
103         case RAW_QFS_VOLUME:
104                 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 5));
105
106                 SIVAL(blob->data,       0, fsinfo->volume.out.serial_number);
107                 /* w2k3 implements this incorrectly for unicode - it
108                  * leaves the last byte off the string */
109                 TRANS2_CHECK(smbsrv_blob_append_string(mem_ctx, blob,
110                                                        fsinfo->volume.out.volume_name.s,
111                                                        4, default_str_flags,
112                                                        STR_LEN8BIT|STR_NOALIGN));
113
114                 return NT_STATUS_OK;
115
116         case RAW_QFS_VOLUME_INFO:
117                 passthru_level = RAW_QFS_VOLUME_INFORMATION;
118                 break;
119
120         case RAW_QFS_SIZE_INFO:
121                 passthru_level = RAW_QFS_SIZE_INFORMATION;
122                 break;
123
124         case RAW_QFS_DEVICE_INFO:
125                 passthru_level = RAW_QFS_DEVICE_INFORMATION;
126                 break;
127
128         case RAW_QFS_ATTRIBUTE_INFO:
129                 passthru_level = RAW_QFS_ATTRIBUTE_INFORMATION;
130                 break;
131
132         default:
133                 passthru_level = fsinfo->generic.level;
134                 break;
135         }
136
137         return smbsrv_push_passthru_fsinfo(mem_ctx, blob,
138                                            passthru_level, fsinfo,
139                                            default_str_flags);
140 }
141
142 /*
143   trans2 qfsinfo implementation send
144 */
145 static NTSTATUS trans2_qfsinfo_send(struct trans_op *op)
146 {
147         struct smbsrv_request *req = op->req;
148         struct smb_trans2 *trans = op->trans;
149         union smb_fsinfo *fsinfo;
150
151         TRANS2_CHECK_ASYNC_STATUS(fsinfo, union smb_fsinfo);
152
153         TRANS2_CHECK(trans2_setup_reply(trans, 0, 0, 0));
154
155         TRANS2_CHECK(trans2_push_fsinfo(req->smb_conn, trans,
156                                         &trans->out.data, fsinfo,
157                                         SMBSRV_REQ_DEFAULT_STR_FLAGS(req)));
158
159         return NT_STATUS_OK;
160 }
161
162 /*
163   trans2 qfsinfo implementation
164 */
165 static NTSTATUS trans2_qfsinfo(struct smbsrv_request *req, struct trans_op *op)
166 {
167         struct smb_trans2 *trans = op->trans;
168         union smb_fsinfo *fsinfo;
169         uint16_t level;
170
171         /* make sure we got enough parameters */
172         if (trans->in.params.length != 2) {
173                 return NT_STATUS_FOOBAR;
174         }
175
176         fsinfo = talloc(op, union smb_fsinfo);
177         NT_STATUS_HAVE_NO_MEMORY(fsinfo);
178
179         level = SVAL(trans->in.params.data, 0);
180
181         /* work out the backend level - we make it 1-1 in the header */
182         fsinfo->generic.level = (enum smb_fsinfo_level)level;
183         if (fsinfo->generic.level >= RAW_QFS_GENERIC) {
184                 return NT_STATUS_INVALID_LEVEL;
185         }
186
187         op->op_info = fsinfo;
188         op->send_fn = trans2_qfsinfo_send;
189
190         return ntvfs_fsinfo(req->ntvfs, fsinfo);
191 }
192
193
194 /*
195   trans2 open implementation send
196 */
197 static NTSTATUS trans2_open_send(struct trans_op *op)
198 {
199         struct smbsrv_request *req = op->req;
200         struct smb_trans2 *trans = op->trans;
201         union smb_open *io;
202
203         TRANS2_CHECK_ASYNC_STATUS(io, union smb_open);
204
205         TRANS2_CHECK(trans2_setup_reply(trans, 30, 0, 0));
206
207         smbsrv_push_fnum(trans->out.params.data, VWV(0), io->t2open.out.file.ntvfs);
208         SSVAL(trans->out.params.data, VWV(1), io->t2open.out.attrib);
209         srv_push_dos_date3(req->smb_conn, trans->out.params.data, 
210                            VWV(2), io->t2open.out.write_time);
211         SIVAL(trans->out.params.data, VWV(4), io->t2open.out.size);
212         SSVAL(trans->out.params.data, VWV(6), io->t2open.out.access);
213         SSVAL(trans->out.params.data, VWV(7), io->t2open.out.ftype);
214         SSVAL(trans->out.params.data, VWV(8), io->t2open.out.devstate);
215         SSVAL(trans->out.params.data, VWV(9), io->t2open.out.action);
216         SIVAL(trans->out.params.data, VWV(10), 0); /* reserved */
217         SSVAL(trans->out.params.data, VWV(12), 0); /* EaErrorOffset */
218         SIVAL(trans->out.params.data, VWV(13), 0); /* EaLength */
219
220         return NT_STATUS_OK;
221 }
222
223 /*
224   trans2 open implementation
225 */
226 static NTSTATUS trans2_open(struct smbsrv_request *req, struct trans_op *op)
227 {
228         struct smb_trans2 *trans = op->trans;
229         union smb_open *io;
230
231         /* make sure we got enough parameters */
232         if (trans->in.params.length < 29) {
233                 return NT_STATUS_FOOBAR;
234         }
235
236         io = talloc(op, union smb_open);
237         NT_STATUS_HAVE_NO_MEMORY(io);
238
239         io->t2open.level           = RAW_OPEN_T2OPEN;
240         io->t2open.in.flags        = SVAL(trans->in.params.data, VWV(0));
241         io->t2open.in.open_mode    = SVAL(trans->in.params.data, VWV(1));
242         io->t2open.in.search_attrs = SVAL(trans->in.params.data, VWV(2));
243         io->t2open.in.file_attrs   = SVAL(trans->in.params.data, VWV(3));
244         io->t2open.in.write_time   = srv_pull_dos_date(req->smb_conn, 
245                                                     trans->in.params.data + VWV(4));
246         io->t2open.in.open_func    = SVAL(trans->in.params.data, VWV(6));
247         io->t2open.in.size         = IVAL(trans->in.params.data, VWV(7));
248         io->t2open.in.timeout      = IVAL(trans->in.params.data, VWV(9));
249         io->t2open.in.num_eas      = 0;
250         io->t2open.in.eas          = NULL;
251
252         smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 28, &io->t2open.in.fname, 0);
253         if (io->t2open.in.fname == NULL) {
254                 return NT_STATUS_FOOBAR;
255         }
256
257         TRANS2_CHECK(ea_pull_list(&trans->in.data, io, &io->t2open.in.num_eas, &io->t2open.in.eas));
258
259         op->op_info = io;
260         op->send_fn = trans2_open_send;
261
262         return ntvfs_open(req->ntvfs, io);
263 }
264
265
266 /*
267   trans2 simple send
268 */
269 static NTSTATUS trans2_simple_send(struct trans_op *op)
270 {
271         struct smbsrv_request *req = op->req;
272         struct smb_trans2 *trans = op->trans;
273
274         TRANS2_CHECK_ASYNC_STATUS_SIMPLE;
275
276         TRANS2_CHECK(trans2_setup_reply(trans, 2, 0, 0));
277
278         SSVAL(trans->out.params.data, VWV(0), 0);
279
280         return NT_STATUS_OK;
281 }
282
283 /*
284   trans2 mkdir implementation
285 */
286 static NTSTATUS trans2_mkdir(struct smbsrv_request *req, struct trans_op *op)
287 {
288         struct smb_trans2 *trans = op->trans;
289         union smb_mkdir *io;
290
291         /* make sure we got enough parameters */
292         if (trans->in.params.length < 5) {
293                 return NT_STATUS_FOOBAR;
294         }
295
296         io = talloc(op, union smb_mkdir);
297         NT_STATUS_HAVE_NO_MEMORY(io);
298
299         io->t2mkdir.level = RAW_MKDIR_T2MKDIR;
300         smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 4, &io->t2mkdir.in.path, 0);
301         if (io->t2mkdir.in.path == NULL) {
302                 return NT_STATUS_FOOBAR;
303         }
304
305         TRANS2_CHECK(ea_pull_list(&trans->in.data, io, 
306                                   &io->t2mkdir.in.num_eas, 
307                                   &io->t2mkdir.in.eas));
308
309         op->op_info = io;
310         op->send_fn = trans2_simple_send;
311
312         return ntvfs_mkdir(req->ntvfs, io);
313 }
314
315 static NTSTATUS trans2_push_fileinfo(struct smbsrv_connection *smb_conn,
316                                      TALLOC_CTX *mem_ctx,
317                                      DATA_BLOB *blob,
318                                      union smb_fileinfo *st,
319                                      int default_str_flags)
320 {
321         uint32_t list_size;
322         enum smb_fileinfo_level passthru_level;
323
324         switch (st->generic.level) {
325         case RAW_FILEINFO_GENERIC:
326         case RAW_FILEINFO_GETATTR:
327         case RAW_FILEINFO_GETATTRE:
328         case RAW_FILEINFO_SEC_DESC:
329         case RAW_FILEINFO_SMB2_ALL_EAS:
330         case RAW_FILEINFO_SMB2_ALL_INFORMATION:
331                 /* handled elsewhere */
332                 return NT_STATUS_INVALID_LEVEL;
333
334         case RAW_FILEINFO_UNIX_BASIC:
335         case RAW_FILEINFO_UNIX_LINK:
336                 /* not implemented yet */
337                 return NT_STATUS_INVALID_LEVEL;
338
339         case RAW_FILEINFO_STANDARD:
340                 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 22));
341
342                 srv_push_dos_date2(smb_conn, blob->data, 0, st->standard.out.create_time);
343                 srv_push_dos_date2(smb_conn, blob->data, 4, st->standard.out.access_time);
344                 srv_push_dos_date2(smb_conn, blob->data, 8, st->standard.out.write_time);
345                 SIVAL(blob->data,        12, st->standard.out.size);
346                 SIVAL(blob->data,        16, st->standard.out.alloc_size);
347                 SSVAL(blob->data,        20, st->standard.out.attrib);
348                 return NT_STATUS_OK;
349
350         case RAW_FILEINFO_EA_SIZE:
351                 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 26));
352
353                 srv_push_dos_date2(smb_conn, blob->data, 0, st->ea_size.out.create_time);
354                 srv_push_dos_date2(smb_conn, blob->data, 4, st->ea_size.out.access_time);
355                 srv_push_dos_date2(smb_conn, blob->data, 8, st->ea_size.out.write_time);
356                 SIVAL(blob->data,        12, st->ea_size.out.size);
357                 SIVAL(blob->data,        16, st->ea_size.out.alloc_size);
358                 SSVAL(blob->data,        20, st->ea_size.out.attrib);
359                 SIVAL(blob->data,        22, st->ea_size.out.ea_size);
360                 return NT_STATUS_OK;
361
362         case RAW_FILEINFO_EA_LIST:
363                 list_size = ea_list_size(st->ea_list.out.num_eas,
364                                          st->ea_list.out.eas);
365                 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, list_size));
366
367                 ea_put_list(blob->data, 
368                             st->ea_list.out.num_eas, st->ea_list.out.eas);
369                 return NT_STATUS_OK;
370
371         case RAW_FILEINFO_ALL_EAS:
372                 list_size = ea_list_size(st->all_eas.out.num_eas,
373                                                   st->all_eas.out.eas);
374                 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, list_size));
375
376                 ea_put_list(blob->data, 
377                             st->all_eas.out.num_eas, st->all_eas.out.eas);
378                 return NT_STATUS_OK;
379
380         case RAW_FILEINFO_IS_NAME_VALID:
381                 return NT_STATUS_OK;
382
383         case RAW_FILEINFO_BASIC_INFO:
384                 passthru_level = RAW_FILEINFO_BASIC_INFORMATION;
385                 break;
386
387         case RAW_FILEINFO_STANDARD_INFO:
388                 passthru_level = RAW_FILEINFO_STANDARD_INFORMATION;
389                 break;
390
391         case RAW_FILEINFO_EA_INFO:
392                 passthru_level = RAW_FILEINFO_EA_INFORMATION;
393                 break;
394
395         case RAW_FILEINFO_COMPRESSION_INFO:
396                 passthru_level = RAW_FILEINFO_COMPRESSION_INFORMATION;
397                 break;
398
399         case RAW_FILEINFO_ALL_INFO:
400                 passthru_level = RAW_FILEINFO_ALL_INFORMATION;
401                 break;
402
403         case RAW_FILEINFO_NAME_INFO:
404                 passthru_level = RAW_FILEINFO_NAME_INFORMATION;
405                 break;
406
407         case RAW_FILEINFO_ALT_NAME_INFO:
408                 passthru_level = RAW_FILEINFO_ALT_NAME_INFORMATION;
409                 break;
410
411         case RAW_FILEINFO_STREAM_INFO:
412                 passthru_level = RAW_FILEINFO_STREAM_INFORMATION;
413                 break;
414
415         default:
416                 passthru_level = st->generic.level;
417                 break;
418         }
419
420         return smbsrv_push_passthru_fileinfo(mem_ctx, blob,
421                                              passthru_level, st,
422                                              default_str_flags);
423 }
424
425 /*
426   fill in the reply from a qpathinfo or qfileinfo call
427 */
428 static NTSTATUS trans2_fileinfo_send(struct trans_op *op)
429 {
430         struct smbsrv_request *req = op->req;
431         struct smb_trans2 *trans = op->trans;
432         union smb_fileinfo *st;
433
434         TRANS2_CHECK_ASYNC_STATUS(st, union smb_fileinfo);
435
436         TRANS2_CHECK(trans2_setup_reply(trans, 2, 0, 0));
437         SSVAL(trans->out.params.data, 0, 0);
438
439         TRANS2_CHECK(trans2_push_fileinfo(req->smb_conn, trans,
440                                           &trans->out.data, st,
441                                           SMBSRV_REQ_DEFAULT_STR_FLAGS(req)));
442
443         return NT_STATUS_OK;
444 }
445
446 /*
447   trans2 qpathinfo implementation
448 */
449 static NTSTATUS trans2_qpathinfo(struct smbsrv_request *req, struct trans_op *op)
450 {
451         struct smb_trans2 *trans = op->trans;
452         union smb_fileinfo *st;
453         uint16_t level;
454
455         /* make sure we got enough parameters */
456         if (trans->in.params.length < 2) {
457                 return NT_STATUS_FOOBAR;
458         }
459
460         st = talloc(op, union smb_fileinfo);
461         NT_STATUS_HAVE_NO_MEMORY(st);
462
463         level = SVAL(trans->in.params.data, 0);
464
465         smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 6, &st->generic.in.file.path, 0);
466         if (st->generic.in.file.path == NULL) {
467                 return NT_STATUS_FOOBAR;
468         }
469
470         /* work out the backend level - we make it 1-1 in the header */
471         st->generic.level = (enum smb_fileinfo_level)level;
472         if (st->generic.level >= RAW_FILEINFO_GENERIC) {
473                 return NT_STATUS_INVALID_LEVEL;
474         }
475
476         if (st->generic.level == RAW_FILEINFO_EA_LIST) {
477                 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req, 
478                                                &st->ea_list.in.num_names,
479                                                &st->ea_list.in.ea_names));
480         }
481
482         op->op_info = st;
483         op->send_fn = trans2_fileinfo_send;
484
485         return ntvfs_qpathinfo(req->ntvfs, st);
486 }
487
488
489 /*
490   trans2 qpathinfo implementation
491 */
492 static NTSTATUS trans2_qfileinfo(struct smbsrv_request *req, struct trans_op *op)
493 {
494         struct smb_trans2 *trans = op->trans;
495         union smb_fileinfo *st;
496         uint16_t level;
497         struct ntvfs_handle *h;
498
499         /* make sure we got enough parameters */
500         if (trans->in.params.length < 4) {
501                 return NT_STATUS_FOOBAR;
502         }
503
504         st = talloc(op, union smb_fileinfo);
505         NT_STATUS_HAVE_NO_MEMORY(st);
506
507         h     = smbsrv_pull_fnum(req, trans->in.params.data, 0);
508         level = SVAL(trans->in.params.data, 2);
509
510         st->generic.in.file.ntvfs = h;
511         /* work out the backend level - we make it 1-1 in the header */
512         st->generic.level = (enum smb_fileinfo_level)level;
513         if (st->generic.level >= RAW_FILEINFO_GENERIC) {
514                 return NT_STATUS_INVALID_LEVEL;
515         }
516
517         if (st->generic.level == RAW_FILEINFO_EA_LIST) {
518                 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req, 
519                                                &st->ea_list.in.num_names,
520                                                &st->ea_list.in.ea_names));
521         }
522
523         op->op_info = st;
524         op->send_fn = trans2_fileinfo_send;
525
526         SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st->generic.in.file.ntvfs);
527         return ntvfs_qfileinfo(req->ntvfs, st);
528 }
529
530
531 /*
532   parse a trans2 setfileinfo/setpathinfo data blob
533 */
534 static NTSTATUS trans2_parse_sfileinfo(struct smbsrv_request *req,
535                                        union smb_setfileinfo *st,
536                                        const DATA_BLOB *blob)
537 {
538         enum smb_setfileinfo_level passthru_level;
539
540         switch (st->generic.level) {
541         case RAW_SFILEINFO_GENERIC:
542         case RAW_SFILEINFO_SETATTR:
543         case RAW_SFILEINFO_SETATTRE:
544         case RAW_SFILEINFO_SEC_DESC:
545                 /* handled elsewhere */
546                 return NT_STATUS_INVALID_LEVEL;
547
548         case RAW_SFILEINFO_STANDARD:
549                 CHECK_MIN_BLOB_SIZE(blob, 12);
550
551                 st->standard.in.create_time = srv_pull_dos_date2(req->smb_conn, blob->data + 0);
552                 st->standard.in.access_time = srv_pull_dos_date2(req->smb_conn, blob->data + 4);
553                 st->standard.in.write_time  = srv_pull_dos_date2(req->smb_conn, blob->data + 8);
554
555                 return NT_STATUS_OK;
556
557         case RAW_SFILEINFO_EA_SET:
558                 return ea_pull_list(blob, req, 
559                                     &st->ea_set.in.num_eas, 
560                                     &st->ea_set.in.eas);
561
562         case SMB_SFILEINFO_BASIC_INFO:
563         case SMB_SFILEINFO_BASIC_INFORMATION:
564                 passthru_level = SMB_SFILEINFO_BASIC_INFORMATION;
565                 break;
566
567         case SMB_SFILEINFO_DISPOSITION_INFO:
568         case SMB_SFILEINFO_DISPOSITION_INFORMATION:
569                 passthru_level = SMB_SFILEINFO_DISPOSITION_INFORMATION;
570                 break;
571
572         case SMB_SFILEINFO_ALLOCATION_INFO:
573         case SMB_SFILEINFO_ALLOCATION_INFORMATION:
574                 passthru_level = SMB_SFILEINFO_ALLOCATION_INFORMATION;
575                 break;
576
577         case RAW_SFILEINFO_END_OF_FILE_INFO:
578         case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
579                 passthru_level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
580                 break;
581
582         case RAW_SFILEINFO_RENAME_INFORMATION:
583         case RAW_SFILEINFO_POSITION_INFORMATION:
584         case RAW_SFILEINFO_MODE_INFORMATION:
585                 passthru_level = st->generic.level;
586                 break;
587
588         case RAW_SFILEINFO_UNIX_BASIC:
589         case RAW_SFILEINFO_UNIX_LINK:
590         case RAW_SFILEINFO_UNIX_HLINK:
591         case RAW_SFILEINFO_1023:
592         case RAW_SFILEINFO_1025:
593         case RAW_SFILEINFO_1029:
594         case RAW_SFILEINFO_1032:
595         case RAW_SFILEINFO_1039:
596         case RAW_SFILEINFO_1040:
597                 return NT_STATUS_INVALID_LEVEL;
598
599         default:
600                 /* we need a default here to cope with invalid values on the wire */
601                 return NT_STATUS_INVALID_LEVEL;
602         }
603
604         return smbsrv_pull_passthru_sfileinfo(st, passthru_level, st,
605                                               blob, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
606                                               &req->in.bufinfo);
607 }
608
609 /*
610   trans2 setfileinfo implementation
611 */
612 static NTSTATUS trans2_setfileinfo(struct smbsrv_request *req, struct trans_op *op)
613 {
614         struct smb_trans2 *trans = op->trans;
615         union smb_setfileinfo *st;
616         uint16_t level;
617         struct ntvfs_handle *h;
618
619         /* make sure we got enough parameters */
620         if (trans->in.params.length < 4) {
621                 return NT_STATUS_FOOBAR;
622         }
623
624         st = talloc(op, union smb_setfileinfo);
625         NT_STATUS_HAVE_NO_MEMORY(st);
626
627         h     = smbsrv_pull_fnum(req, trans->in.params.data, 0);
628         level = SVAL(trans->in.params.data, 2);
629
630         st->generic.in.file.ntvfs = h;
631         /* work out the backend level - we make it 1-1 in the header */
632         st->generic.level = (enum smb_setfileinfo_level)level;
633         if (st->generic.level >= RAW_SFILEINFO_GENERIC) {
634                 return NT_STATUS_INVALID_LEVEL;
635         }
636
637         TRANS2_CHECK(trans2_parse_sfileinfo(req, st, &trans->in.data));
638
639         op->op_info = st;
640         op->send_fn = trans2_simple_send;
641
642         SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st->generic.in.file.ntvfs);
643         return ntvfs_setfileinfo(req->ntvfs, st);
644 }
645
646 /*
647   trans2 setpathinfo implementation
648 */
649 static NTSTATUS trans2_setpathinfo(struct smbsrv_request *req, struct trans_op *op)
650 {
651         struct smb_trans2 *trans = op->trans;
652         union smb_setfileinfo *st;
653         uint16_t level;
654
655         /* make sure we got enough parameters */
656         if (trans->in.params.length < 4) {
657                 return NT_STATUS_FOOBAR;
658         }
659
660         st = talloc(op, union smb_setfileinfo);
661         NT_STATUS_HAVE_NO_MEMORY(st);
662
663         level = SVAL(trans->in.params.data, 0);
664
665         smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 6, &st->generic.in.file.path, 0);
666         if (st->generic.in.file.path == NULL) {
667                 return NT_STATUS_FOOBAR;
668         }
669
670         /* work out the backend level - we make it 1-1 in the header */
671         st->generic.level = (enum smb_setfileinfo_level)level;
672         if (st->generic.level >= RAW_SFILEINFO_GENERIC) {
673                 return NT_STATUS_INVALID_LEVEL;
674         }
675
676         TRANS2_CHECK(trans2_parse_sfileinfo(req, st, &trans->in.data));
677
678         op->op_info = st;
679         op->send_fn = trans2_simple_send;
680
681         return ntvfs_setpathinfo(req->ntvfs, st);
682 }
683
684
685 /* a structure to encapsulate the state information about an in-progress ffirst/fnext operation */
686 struct find_state {
687         struct trans_op *op;
688         void *search;
689         enum smb_search_data_level data_level;
690         uint16_t last_entry_offset;
691         uint16_t flags;
692 };
693
694 /*
695   fill a single entry in a trans2 find reply 
696 */
697 static NTSTATUS find_fill_info(struct find_state *state,
698                                const union smb_search_data *file)
699 {
700         struct smbsrv_request *req = state->op->req;
701         struct smb_trans2 *trans = state->op->trans;
702         uint8_t *data;
703         uint_t ofs = trans->out.data.length;
704         uint32_t ea_size;
705
706         switch (state->data_level) {
707         case RAW_SEARCH_DATA_GENERIC:
708         case RAW_SEARCH_DATA_SEARCH:
709                 /* handled elsewhere */
710                 return NT_STATUS_INVALID_LEVEL;
711
712         case RAW_SEARCH_DATA_STANDARD:
713                 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
714                         TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 27));
715                         SIVAL(trans->out.data.data, ofs, file->standard.resume_key);
716                         ofs += 4;
717                 } else {
718                         TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 23));
719                 }
720                 data = trans->out.data.data + ofs;
721                 srv_push_dos_date2(req->smb_conn, data, 0, file->standard.create_time);
722                 srv_push_dos_date2(req->smb_conn, data, 4, file->standard.access_time);
723                 srv_push_dos_date2(req->smb_conn, data, 8, file->standard.write_time);
724                 SIVAL(data, 12, file->standard.size);
725                 SIVAL(data, 16, file->standard.alloc_size);
726                 SSVAL(data, 20, file->standard.attrib);
727                 TRANS2_CHECK(smbsrv_blob_append_string(trans, &trans->out.data, file->standard.name.s, 
728                                                        ofs + 22, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
729                                                        STR_LEN8BIT | STR_TERMINATE | STR_LEN_NOTERM));
730                 break;
731
732         case RAW_SEARCH_DATA_EA_SIZE:
733                 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
734                         TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 31));
735                         SIVAL(trans->out.data.data, ofs, file->ea_size.resume_key);
736                         ofs += 4;
737                 } else {
738                         TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 27));
739                 }
740                 data = trans->out.data.data + ofs;
741                 srv_push_dos_date2(req->smb_conn, data, 0, file->ea_size.create_time);
742                 srv_push_dos_date2(req->smb_conn, data, 4, file->ea_size.access_time);
743                 srv_push_dos_date2(req->smb_conn, data, 8, file->ea_size.write_time);
744                 SIVAL(data, 12, file->ea_size.size);
745                 SIVAL(data, 16, file->ea_size.alloc_size);
746                 SSVAL(data, 20, file->ea_size.attrib);
747                 SIVAL(data, 22, file->ea_size.ea_size);
748                 TRANS2_CHECK(smbsrv_blob_append_string(trans, &trans->out.data, file->ea_size.name.s, 
749                                                        ofs + 26, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
750                                                        STR_LEN8BIT | STR_NOALIGN));
751                 TRANS2_CHECK(smbsrv_blob_fill_data(trans, &trans->out.data, trans->out.data.length + 1));
752                 break;
753
754         case RAW_SEARCH_DATA_EA_LIST:
755                 ea_size = ea_list_size(file->ea_list.eas.num_eas, file->ea_list.eas.eas);
756                 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
757                         TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 27 + ea_size));
758                         SIVAL(trans->out.data.data, ofs, file->ea_list.resume_key);
759                         ofs += 4;
760                 } else {
761                         TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 23 + ea_size));
762                 }
763                 data = trans->out.data.data + ofs;
764                 srv_push_dos_date2(req->smb_conn, data, 0, file->ea_list.create_time);
765                 srv_push_dos_date2(req->smb_conn, data, 4, file->ea_list.access_time);
766                 srv_push_dos_date2(req->smb_conn, data, 8, file->ea_list.write_time);
767                 SIVAL(data, 12, file->ea_list.size);
768                 SIVAL(data, 16, file->ea_list.alloc_size);
769                 SSVAL(data, 20, file->ea_list.attrib);
770                 ea_put_list(data+22, file->ea_list.eas.num_eas, file->ea_list.eas.eas);
771                 TRANS2_CHECK(smbsrv_blob_append_string(trans, &trans->out.data, file->ea_list.name.s, 
772                                                        ofs + 22 + ea_size, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
773                                                        STR_LEN8BIT | STR_NOALIGN));
774                 TRANS2_CHECK(smbsrv_blob_fill_data(trans, &trans->out.data, trans->out.data.length + 1));
775                 break;
776
777         case RAW_SEARCH_DATA_DIRECTORY_INFO:
778         case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO:
779         case RAW_SEARCH_DATA_NAME_INFO:
780         case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO:
781         case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO:
782         case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO:
783                 return smbsrv_push_passthru_search(trans, &trans->out.data, state->data_level, file,
784                                                    SMBSRV_REQ_DEFAULT_STR_FLAGS(req));
785
786         case RAW_SEARCH_DATA_UNIX_INFO:
787                 return NT_STATUS_INVALID_LEVEL;
788         }
789
790         return NT_STATUS_OK;
791 }
792
793 /* callback function for trans2 findfirst/findnext */
794 static bool find_callback(void *private, const union smb_search_data *file)
795 {
796         struct find_state *state = talloc_get_type(private, struct find_state);
797         struct smb_trans2 *trans = state->op->trans;
798         uint_t old_length;
799
800         old_length = trans->out.data.length;
801
802         if (!NT_STATUS_IS_OK(find_fill_info(state, file)) ||
803             trans->out.data.length > trans->in.max_data) {
804                 /* restore the old length and tell the backend to stop */
805                 smbsrv_blob_grow_data(trans, &trans->out.data, old_length);
806                 return false;
807         }
808
809         state->last_entry_offset = old_length;  
810         return true;
811 }
812
813 /*
814   trans2 findfirst send
815  */
816 static NTSTATUS trans2_findfirst_send(struct trans_op *op)
817 {
818         struct smbsrv_request *req = op->req;
819         struct smb_trans2 *trans = op->trans;
820         union smb_search_first *search;
821         struct find_state *state;
822         uint8_t *param;
823
824         TRANS2_CHECK_ASYNC_STATUS(state, struct find_state);
825         search = talloc_get_type(state->search, union smb_search_first);
826
827         /* fill in the findfirst reply header */
828         param = trans->out.params.data;
829         SSVAL(param, VWV(0), search->t2ffirst.out.handle);
830         SSVAL(param, VWV(1), search->t2ffirst.out.count);
831         SSVAL(param, VWV(2), search->t2ffirst.out.end_of_search);
832         SSVAL(param, VWV(3), 0);
833         SSVAL(param, VWV(4), state->last_entry_offset);
834
835         return NT_STATUS_OK;
836 }
837
838
839 /*
840   trans2 findfirst implementation
841 */
842 static NTSTATUS trans2_findfirst(struct smbsrv_request *req, struct trans_op *op)
843 {
844         struct smb_trans2 *trans = op->trans;
845         union smb_search_first *search;
846         uint16_t level;
847         struct find_state *state;
848
849         /* make sure we got all the parameters */
850         if (trans->in.params.length < 14) {
851                 return NT_STATUS_FOOBAR;
852         }
853
854         search = talloc(op, union smb_search_first);
855         NT_STATUS_HAVE_NO_MEMORY(search);
856
857         search->t2ffirst.in.search_attrib = SVAL(trans->in.params.data, 0);
858         search->t2ffirst.in.max_count     = SVAL(trans->in.params.data, 2);
859         search->t2ffirst.in.flags         = SVAL(trans->in.params.data, 4);
860         level                             = SVAL(trans->in.params.data, 6);
861         search->t2ffirst.in.storage_type  = IVAL(trans->in.params.data, 8);
862
863         smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 12, &search->t2ffirst.in.pattern, 0);
864         if (search->t2ffirst.in.pattern == NULL) {
865                 return NT_STATUS_FOOBAR;
866         }
867
868         search->t2ffirst.level = RAW_SEARCH_TRANS2;
869         search->t2ffirst.data_level = (enum smb_search_data_level)level;
870         if (search->t2ffirst.data_level >= RAW_SEARCH_DATA_GENERIC) {
871                 return NT_STATUS_INVALID_LEVEL;
872         }
873
874         if (search->t2ffirst.data_level == RAW_SEARCH_DATA_EA_LIST) {
875                 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
876                                                &search->t2ffirst.in.num_names, 
877                                                &search->t2ffirst.in.ea_names));
878         }
879
880         /* setup the private state structure that the backend will
881            give us in the callback */
882         state = talloc(op, struct find_state);
883         NT_STATUS_HAVE_NO_MEMORY(state);
884         state->op               = op;
885         state->search           = search;
886         state->data_level       = search->t2ffirst.data_level;
887         state->last_entry_offset= 0;
888         state->flags            = search->t2ffirst.in.flags;
889
890         /* setup for just a header in the reply */
891         TRANS2_CHECK(trans2_setup_reply(trans, 10, 0, 0));
892
893         op->op_info = state;
894         op->send_fn = trans2_findfirst_send;
895
896         return ntvfs_search_first(req->ntvfs, search, state, find_callback);
897 }
898
899
900 /*
901   trans2 findnext send
902 */
903 static NTSTATUS trans2_findnext_send(struct trans_op *op)
904 {
905         struct smbsrv_request *req = op->req;
906         struct smb_trans2 *trans = op->trans;
907         union smb_search_next *search;
908         struct find_state *state;
909         uint8_t *param;
910
911         TRANS2_CHECK_ASYNC_STATUS(state, struct find_state);
912         search = talloc_get_type(state->search, union smb_search_next);
913
914         /* fill in the findfirst reply header */
915         param = trans->out.params.data;
916         SSVAL(param, VWV(0), search->t2fnext.out.count);
917         SSVAL(param, VWV(1), search->t2fnext.out.end_of_search);
918         SSVAL(param, VWV(2), 0);
919         SSVAL(param, VWV(3), state->last_entry_offset);
920         
921         return NT_STATUS_OK;
922 }
923
924
925 /*
926   trans2 findnext implementation
927 */
928 static NTSTATUS trans2_findnext(struct smbsrv_request *req, struct trans_op *op)
929 {
930         struct smb_trans2 *trans = op->trans;
931         union smb_search_next *search;
932         uint16_t level;
933         struct find_state *state;
934
935         /* make sure we got all the parameters */
936         if (trans->in.params.length < 12) {
937                 return NT_STATUS_FOOBAR;
938         }
939
940         search = talloc(op, union smb_search_next);
941         NT_STATUS_HAVE_NO_MEMORY(search);
942
943         search->t2fnext.in.handle        = SVAL(trans->in.params.data, 0);
944         search->t2fnext.in.max_count     = SVAL(trans->in.params.data, 2);
945         level                            = SVAL(trans->in.params.data, 4);
946         search->t2fnext.in.resume_key    = IVAL(trans->in.params.data, 6);
947         search->t2fnext.in.flags         = SVAL(trans->in.params.data, 10);
948
949         smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 12, &search->t2fnext.in.last_name, 0);
950         if (search->t2fnext.in.last_name == NULL) {
951                 return NT_STATUS_FOOBAR;
952         }
953
954         search->t2fnext.level = RAW_SEARCH_TRANS2;
955         search->t2fnext.data_level = (enum smb_search_data_level)level;
956         if (search->t2fnext.data_level >= RAW_SEARCH_DATA_GENERIC) {
957                 return NT_STATUS_INVALID_LEVEL;
958         }
959
960         if (search->t2fnext.data_level == RAW_SEARCH_DATA_EA_LIST) {
961                 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
962                                                &search->t2fnext.in.num_names, 
963                                                &search->t2fnext.in.ea_names));
964         }
965
966         /* setup the private state structure that the backend will give us in the callback */
967         state = talloc(op, struct find_state);
968         NT_STATUS_HAVE_NO_MEMORY(state);
969         state->op               = op;
970         state->search           = search;
971         state->data_level       = search->t2fnext.data_level;
972         state->last_entry_offset= 0;
973         state->flags            = search->t2fnext.in.flags;
974
975         /* setup for just a header in the reply */
976         TRANS2_CHECK(trans2_setup_reply(trans, 8, 0, 0));
977
978         op->op_info = state;
979         op->send_fn = trans2_findnext_send;
980
981         return ntvfs_search_next(req->ntvfs, search, state, find_callback);
982 }
983
984
985 /*
986   backend for trans2 requests
987 */
988 static NTSTATUS trans2_backend(struct smbsrv_request *req, struct trans_op *op)
989 {
990         struct smb_trans2 *trans = op->trans;
991         NTSTATUS status;
992
993         /* direct trans2 pass thru */
994         status = ntvfs_trans2(req->ntvfs, trans);
995         if (!NT_STATUS_EQUAL(NT_STATUS_NOT_IMPLEMENTED, status)) {
996                 return status;
997         }
998
999         /* must have at least one setup word */
1000         if (trans->in.setup_count < 1) {
1001                 return NT_STATUS_FOOBAR;
1002         }
1003
1004         /* the trans2 command is in setup[0] */
1005         switch (trans->in.setup[0]) {
1006         case TRANSACT2_FINDFIRST:
1007                 return trans2_findfirst(req, op);
1008         case TRANSACT2_FINDNEXT:
1009                 return trans2_findnext(req, op);
1010         case TRANSACT2_QPATHINFO:
1011                 return trans2_qpathinfo(req, op);
1012         case TRANSACT2_QFILEINFO:
1013                 return trans2_qfileinfo(req, op);
1014         case TRANSACT2_SETFILEINFO:
1015                 return trans2_setfileinfo(req, op);
1016         case TRANSACT2_SETPATHINFO:
1017                 return trans2_setpathinfo(req, op);
1018         case TRANSACT2_QFSINFO:
1019                 return trans2_qfsinfo(req, op);
1020         case TRANSACT2_OPEN:
1021                 return trans2_open(req, op);
1022         case TRANSACT2_MKDIR:
1023                 return trans2_mkdir(req, op);
1024         }
1025
1026         /* an unknown trans2 command */
1027         return NT_STATUS_FOOBAR;
1028 }
1029
1030
1031 /*
1032   send a continue request
1033 */
1034 static void reply_trans_continue(struct smbsrv_request *req, uint8_t command,
1035                                  struct smb_trans2 *trans)
1036 {
1037         struct smbsrv_trans_partial *tp;
1038         int count;
1039
1040         /* make sure they don't flood us */
1041         for (count=0,tp=req->smb_conn->trans_partial;tp;tp=tp->next) count++;
1042         if (count > 100) {
1043                 smbsrv_send_error(req, NT_STATUS_INSUFFICIENT_RESOURCES);
1044                 return;
1045         }
1046
1047         tp = talloc(req, struct smbsrv_trans_partial);
1048
1049         tp->req = talloc_reference(tp, req);
1050         tp->trans = trans;
1051         tp->command = command;
1052
1053         DLIST_ADD(req->smb_conn->trans_partial, tp);
1054
1055         /* send a 'please continue' reply */
1056         smbsrv_setup_reply(req, 0, 0);
1057         smbsrv_send_reply(req);
1058 }
1059
1060
1061 /*
1062   answer a reconstructed trans request
1063 */
1064 static void reply_trans_send(struct ntvfs_request *ntvfs)
1065 {
1066         struct smbsrv_request *req;
1067         struct trans_op *op;
1068         struct smb_trans2 *trans;
1069         uint16_t params_left, data_left;
1070         uint8_t *params, *data;
1071         int i;
1072
1073         SMBSRV_CHECK_ASYNC_STATUS_ERR(op, struct trans_op);
1074         trans = op->trans;
1075
1076         /* if this function needs work to form the nttrans reply buffer, then
1077            call that now */
1078         if (op->send_fn != NULL) {
1079                 NTSTATUS status;
1080                 status = op->send_fn(op);
1081                 if (!NT_STATUS_IS_OK(status)) {
1082                         smbsrv_send_error(req, status);
1083                         return;
1084                 }
1085         }
1086
1087         params_left = trans->out.params.length;
1088         data_left   = trans->out.data.length;
1089         params      = trans->out.params.data;
1090         data        = trans->out.data.data;
1091
1092         smbsrv_setup_reply(req, 10 + trans->out.setup_count, 0);
1093
1094         if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) {
1095                 smbsrv_setup_error(req, req->ntvfs->async_states->status);
1096         }
1097
1098         /* we need to divide up the reply into chunks that fit into
1099            the negotiated buffer size */
1100         do {
1101                 uint16_t this_data, this_param, max_bytes;
1102                 uint_t align1 = 1, align2 = (params_left ? 2 : 0);
1103                 struct smbsrv_request *this_req;
1104
1105                 max_bytes = req_max_data(req) - (align1 + align2);
1106
1107                 this_param = params_left;
1108                 if (this_param > max_bytes) {
1109                         this_param = max_bytes;
1110                 }
1111                 max_bytes -= this_param;
1112
1113                 this_data = data_left;
1114                 if (this_data > max_bytes) {
1115                         this_data = max_bytes;
1116                 }
1117
1118                 /* don't destroy unless this is the last chunk */
1119                 if (params_left - this_param != 0 || 
1120                     data_left - this_data != 0) {
1121                         this_req = smbsrv_setup_secondary_request(req);
1122                 } else {
1123                         this_req = req;
1124                 }
1125
1126                 req_grow_data(this_req, this_param + this_data + (align1 + align2));
1127
1128                 SSVAL(this_req->out.vwv, VWV(0), trans->out.params.length);
1129                 SSVAL(this_req->out.vwv, VWV(1), trans->out.data.length);
1130                 SSVAL(this_req->out.vwv, VWV(2), 0);
1131
1132                 SSVAL(this_req->out.vwv, VWV(3), this_param);
1133                 SSVAL(this_req->out.vwv, VWV(4), align1 + PTR_DIFF(this_req->out.data, this_req->out.hdr));
1134                 SSVAL(this_req->out.vwv, VWV(5), PTR_DIFF(params, trans->out.params.data));
1135
1136                 SSVAL(this_req->out.vwv, VWV(6), this_data);
1137                 SSVAL(this_req->out.vwv, VWV(7), align1 + align2 + 
1138                       PTR_DIFF(this_req->out.data + this_param, this_req->out.hdr));
1139                 SSVAL(this_req->out.vwv, VWV(8), PTR_DIFF(data, trans->out.data.data));
1140
1141                 SSVAL(this_req->out.vwv, VWV(9), trans->out.setup_count);
1142                 for (i=0;i<trans->out.setup_count;i++) {
1143                         SSVAL(this_req->out.vwv, VWV(10+i), trans->out.setup[i]);
1144                 }
1145
1146                 memset(this_req->out.data, 0, align1);
1147                 if (this_param != 0) {
1148                         memcpy(this_req->out.data + align1, params, this_param);
1149                 }
1150                 memset(this_req->out.data+this_param+align1, 0, align2);
1151                 if (this_data != 0) {
1152                         memcpy(this_req->out.data+this_param+align1+align2, data, this_data);
1153                 }
1154
1155                 params_left -= this_param;
1156                 data_left -= this_data;
1157                 params += this_param;
1158                 data += this_data;
1159
1160                 smbsrv_send_reply(this_req);
1161         } while (params_left != 0 || data_left != 0);
1162 }
1163
1164
1165 /*
1166   answer a reconstructed trans request
1167 */
1168 static void reply_trans_complete(struct smbsrv_request *req, uint8_t command,
1169                                  struct smb_trans2 *trans)
1170 {
1171         struct trans_op *op;
1172
1173         SMBSRV_TALLOC_IO_PTR(op, struct trans_op);
1174         SMBSRV_SETUP_NTVFS_REQUEST(reply_trans_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1175
1176         op->req         = req;
1177         op->trans       = trans;
1178         op->command     = command;
1179         op->op_info     = NULL;
1180         op->send_fn     = NULL;
1181
1182         /* its a full request, give it to the backend */
1183         if (command == SMBtrans) {
1184                 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_trans(req->ntvfs, trans));
1185                 return;
1186         } else {
1187                 SMBSRV_CALL_NTVFS_BACKEND(trans2_backend(req, op));
1188                 return;
1189         }
1190 }
1191
1192 /*
1193   Reply to an SMBtrans or SMBtrans2 request
1194 */
1195 static void reply_trans_generic(struct smbsrv_request *req, uint8_t command)
1196 {
1197         struct smb_trans2 *trans;
1198         int i;
1199         uint16_t param_ofs, data_ofs;
1200         uint16_t param_count, data_count;
1201         uint16_t param_total, data_total;
1202
1203         /* parse request */
1204         if (req->in.wct < 14) {
1205                 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1206                 return;
1207         }
1208
1209         trans = talloc(req, struct smb_trans2);
1210         if (trans == NULL) {
1211                 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
1212                 return;
1213         }
1214
1215         param_total           = SVAL(req->in.vwv, VWV(0));
1216         data_total            = SVAL(req->in.vwv, VWV(1));
1217         trans->in.max_param   = SVAL(req->in.vwv, VWV(2));
1218         trans->in.max_data    = SVAL(req->in.vwv, VWV(3));
1219         trans->in.max_setup   = CVAL(req->in.vwv, VWV(4));
1220         trans->in.flags       = SVAL(req->in.vwv, VWV(5));
1221         trans->in.timeout     = IVAL(req->in.vwv, VWV(6));
1222         param_count           = SVAL(req->in.vwv, VWV(9));
1223         param_ofs             = SVAL(req->in.vwv, VWV(10));
1224         data_count            = SVAL(req->in.vwv, VWV(11));
1225         data_ofs              = SVAL(req->in.vwv, VWV(12));
1226         trans->in.setup_count = CVAL(req->in.vwv, VWV(13));
1227
1228         if (req->in.wct != 14 + trans->in.setup_count) {
1229                 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
1230                 return;
1231         }
1232
1233         /* parse out the setup words */
1234         trans->in.setup = talloc_array(trans, uint16_t, trans->in.setup_count);
1235         if (trans->in.setup_count && !trans->in.setup) {
1236                 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
1237                 return;
1238         }
1239         for (i=0;i<trans->in.setup_count;i++) {
1240                 trans->in.setup[i] = SVAL(req->in.vwv, VWV(14+i));
1241         }
1242
1243         if (command == SMBtrans) {
1244                 req_pull_string(&req->in.bufinfo, &trans->in.trans_name, req->in.data, -1, STR_TERMINATE);
1245         }
1246
1247         if (!req_pull_blob(&req->in.bufinfo, req->in.hdr + param_ofs, param_count, &trans->in.params) ||
1248             !req_pull_blob(&req->in.bufinfo, req->in.hdr + data_ofs, data_count, &trans->in.data)) {
1249                 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1250                 return;
1251         }
1252
1253         /* is it a partial request? if so, then send a 'send more' message */
1254         if (param_total > param_count || data_total > data_count) {
1255                 reply_trans_continue(req, command, trans);
1256                 return;
1257         }
1258
1259         reply_trans_complete(req, command, trans);
1260 }
1261
1262
1263 /*
1264   Reply to an SMBtranss2 request
1265 */
1266 static void reply_transs_generic(struct smbsrv_request *req, uint8_t command)
1267 {
1268         struct smbsrv_trans_partial *tp;
1269         struct smb_trans2 *trans = NULL;
1270         uint16_t param_ofs, data_ofs;
1271         uint16_t param_count, data_count;
1272         uint16_t param_disp, data_disp;
1273         uint16_t param_total, data_total;
1274         DATA_BLOB params, data;
1275
1276         /* parse request */
1277         if (req->in.wct < 8) {
1278                 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1279                 return;
1280         }
1281
1282         for (tp=req->smb_conn->trans_partial;tp;tp=tp->next) {
1283                 if (tp->command == command &&
1284                     SVAL(tp->req->in.hdr, HDR_MID) == SVAL(req->in.hdr, HDR_MID)) {
1285 /* TODO: check the VUID, PID and TID too? */
1286                         break;
1287                 }
1288         }
1289
1290         if (tp == NULL) {
1291                 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1292                 return;
1293         }
1294
1295         trans = tp->trans;
1296
1297         param_total           = SVAL(req->in.vwv, VWV(0));
1298         data_total            = SVAL(req->in.vwv, VWV(1));
1299         param_count           = SVAL(req->in.vwv, VWV(2));
1300         param_ofs             = SVAL(req->in.vwv, VWV(3));
1301         param_disp            = SVAL(req->in.vwv, VWV(4));
1302         data_count            = SVAL(req->in.vwv, VWV(5));
1303         data_ofs              = SVAL(req->in.vwv, VWV(6));
1304         data_disp             = SVAL(req->in.vwv, VWV(7));
1305
1306         if (!req_pull_blob(&req->in.bufinfo, req->in.hdr + param_ofs, param_count, &params) ||
1307             !req_pull_blob(&req->in.bufinfo, req->in.hdr + data_ofs, data_count, &data)) {
1308                 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1309                 return;
1310         }
1311
1312         /* only allow contiguous requests */
1313         if ((param_count != 0 &&
1314              param_disp != trans->in.params.length) ||
1315             (data_count != 0 && 
1316              data_disp != trans->in.data.length)) {
1317                 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1318                 return;         
1319         }
1320
1321         /* add to the existing request */
1322         if (param_count != 0) {
1323                 trans->in.params.data = talloc_realloc(trans, 
1324                                                          trans->in.params.data, 
1325                                                          uint8_t, 
1326                                                          param_disp + param_count);
1327                 if (trans->in.params.data == NULL) {
1328                         goto failed;
1329                 }
1330                 trans->in.params.length = param_disp + param_count;
1331         }
1332
1333         if (data_count != 0) {
1334                 trans->in.data.data = talloc_realloc(trans, 
1335                                                        trans->in.data.data, 
1336                                                        uint8_t, 
1337                                                        data_disp + data_count);
1338                 if (trans->in.data.data == NULL) {
1339                         goto failed;
1340                 }
1341                 trans->in.data.length = data_disp + data_count;
1342         }
1343
1344         memcpy(trans->in.params.data + param_disp, params.data, params.length);
1345         memcpy(trans->in.data.data + data_disp, data.data, data.length);
1346
1347         /* the sequence number of the reply is taken from the last secondary
1348            response */
1349         tp->req->seq_num = req->seq_num;
1350
1351         /* we don't reply to Transs2 requests */
1352         talloc_free(req);
1353
1354         if (trans->in.params.length == param_total &&
1355             trans->in.data.length == data_total) {
1356                 /* its now complete */
1357                 DLIST_REMOVE(tp->req->smb_conn->trans_partial, tp);
1358                 reply_trans_complete(tp->req, command, trans);
1359         }
1360         return;
1361
1362 failed: 
1363         smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
1364         DLIST_REMOVE(req->smb_conn->trans_partial, tp);
1365         talloc_free(req);
1366         talloc_free(tp);
1367 }
1368
1369
1370 /*
1371   Reply to an SMBtrans2
1372 */
1373 void smbsrv_reply_trans2(struct smbsrv_request *req)
1374 {
1375         reply_trans_generic(req, SMBtrans2);
1376 }
1377
1378 /*
1379   Reply to an SMBtrans
1380 */
1381 void smbsrv_reply_trans(struct smbsrv_request *req)
1382 {
1383         reply_trans_generic(req, SMBtrans);
1384 }
1385
1386 /*
1387   Reply to an SMBtranss request
1388 */
1389 void smbsrv_reply_transs(struct smbsrv_request *req)
1390 {
1391         reply_transs_generic(req, SMBtrans);
1392 }
1393
1394 /*
1395   Reply to an SMBtranss2 request
1396 */
1397 void smbsrv_reply_transs2(struct smbsrv_request *req)
1398 {
1399         reply_transs_generic(req, SMBtrans2);
1400 }