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