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