r16443: add push code for SMB2 levels
[ira/wip.git] / source / smb_server / smb / trans2.c
1 /* 
2    Unix SMB/CIFS implementation.
3    transaction2 handling
4    Copyright (C) Andrew Tridgell 2003
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 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, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20 /*
21    This file handles the parsing of transact2 requests
22 */
23
24 #include "includes.h"
25 #include "dlinklist.h"
26 #include "smb_server/smb_server.h"
27 #include "librpc/gen_ndr/ndr_misc.h"
28 #include "ntvfs/ntvfs.h"
29 #include "libcli/raw/libcliraw.h"
30
31 #define TRANS2_CHECK_ASYNC_STATUS_SIMPLE do { \
32         if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) { \
33                 trans2_setup_reply(trans, 0, 0, 0);\
34                 return req->ntvfs->async_states->status; \
35         } \
36 } while (0)
37 #define TRANS2_CHECK_ASYNC_STATUS(ptr, type) do { \
38         TRANS2_CHECK_ASYNC_STATUS_SIMPLE; \
39         ptr = talloc_get_type(op->op_info, type); \
40 } while (0)
41 #define TRANS2_CHECK(cmd) do { \
42         NTSTATUS _status; \
43         _status = cmd; \
44         NT_STATUS_NOT_OK_RETURN(_status); \
45 } while (0)
46
47 /*
48   hold the state of a nttrans op while in progress. Needed to allow for async backend
49   functions.
50 */
51 struct trans_op {
52         struct smbsrv_request *req;
53         struct smb_trans2 *trans;
54         uint8_t command;
55         NTSTATUS (*send_fn)(struct trans_op *);
56         void *op_info;
57 };
58
59 #define CHECK_MIN_BLOB_SIZE(blob, size) do { \
60         if ((blob)->length < (size)) { \
61                 return NT_STATUS_INFO_LENGTH_MISMATCH; \
62         }} while (0)
63
64 /* grow the data size of a trans2 reply */
65 static NTSTATUS trans2_grow_data(TALLOC_CTX *mem_ctx,
66                                  DATA_BLOB *blob,
67                                  uint32_t new_size)
68 {
69         if (new_size > blob->length) {
70                 uint8_t *p;
71                 p = talloc_realloc(mem_ctx, blob->data, uint8_t, new_size);
72                 NT_STATUS_HAVE_NO_MEMORY(p);
73                 blob->data = p;
74         }
75         blob->length = new_size;
76         return NT_STATUS_OK;
77 }
78
79 /* grow the data, zero filling any new bytes */
80 static NTSTATUS trans2_grow_data_fill(TALLOC_CTX *mem_ctx,
81                                       DATA_BLOB *blob,
82                                       uint32_t new_size)
83 {
84         uint32_t old_size = blob->length;
85         TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, new_size));
86         if (new_size > old_size) {
87                 memset(blob->data + old_size, 0, new_size - old_size);
88         }
89         return NT_STATUS_OK;
90 }
91
92
93 /* setup a trans2 reply, given the data and params sizes */
94 static NTSTATUS trans2_setup_reply(struct smb_trans2 *trans,
95                                    uint16_t param_size, uint16_t data_size,
96                                    uint16_t setup_count)
97 {
98         trans->out.setup_count = setup_count;
99         if (setup_count > 0) {
100                 trans->out.setup = talloc_zero_array(trans, uint16_t, setup_count);
101                 NT_STATUS_HAVE_NO_MEMORY(trans->out.setup);
102         }
103         trans->out.params = data_blob_talloc(trans, NULL, param_size);
104         if (param_size > 0) NT_STATUS_HAVE_NO_MEMORY(trans->out.params.data);
105
106         trans->out.data = data_blob_talloc(trans, NULL, data_size);
107         if (data_size > 0) NT_STATUS_HAVE_NO_MEMORY(trans->out.data.data);
108
109         return NT_STATUS_OK;
110 }
111
112
113 /*
114   pull a string from a blob in a trans2 request
115 */
116 static size_t trans2_pull_blob_string(struct smbsrv_request *req, 
117                                       const DATA_BLOB *blob,
118                                       uint16_t offset,
119                                       const char **str,
120                                       int flags)
121 {
122         *str = NULL;
123         /* we use STR_NO_RANGE_CHECK because the params are allocated
124            separately in a DATA_BLOB, so we need to do our own range
125            checking */
126         if (offset >= blob->length) {
127                 return 0;
128         }
129         
130         return req_pull_string(req, str, 
131                                blob->data + offset, 
132                                blob->length - offset,
133                                STR_NO_RANGE_CHECK | flags);
134 }
135
136 #define TRANS2_REQ_DEFAULT_STR_FLAGS(req) (((req)->flags2 & FLAGS2_UNICODE_STRINGS) ? STR_UNICODE : STR_ASCII)
137
138 /*
139   push a string into the data section of a trans2 request
140   return the number of bytes consumed in the output
141 */
142 static size_t trans2_push_data_string(TALLOC_CTX *mem_ctx,
143                                       DATA_BLOB *blob,
144                                       uint32_t len_offset,
145                                       uint32_t offset,
146                                       const char *str,
147                                       int dest_len,
148                                       int default_flags,
149                                       int flags)
150 {
151         int alignment = 0, ret = 0, pkt_len;
152
153         /* we use STR_NO_RANGE_CHECK because the params are allocated
154            separately in a DATA_BLOB, so we need to do our own range
155            checking */
156         if (!str || offset >= blob->length) {
157                 if (flags & STR_LEN8BIT) {
158                         SCVAL(blob->data, len_offset, 0);
159                 } else {
160                         SIVAL(blob->data, len_offset, 0);
161                 }
162                 return 0;
163         }
164
165         flags |= STR_NO_RANGE_CHECK;
166
167         if (dest_len == -1 || (dest_len > blob->length - offset)) {
168                 dest_len = blob->length - offset;
169         }
170
171         if (!(flags & (STR_ASCII|STR_UNICODE))) {
172                 flags |= default_flags;
173         }
174
175         if ((offset&1) && (flags & STR_UNICODE) && !(flags & STR_NOALIGN)) {
176                 alignment = 1;
177                 if (dest_len > 0) {
178                         SCVAL(blob->data + offset, 0, 0);
179                         ret = push_string(blob->data + offset + 1, str, dest_len-1, flags);
180                 }
181         } else {
182                 ret = push_string(blob->data + offset, str, dest_len, flags);
183         }
184
185         /* sometimes the string needs to be terminated, but the length
186            on the wire must not include the termination! */
187         pkt_len = ret;
188
189         if ((flags & STR_LEN_NOTERM) && (flags & STR_TERMINATE)) {
190                 if ((flags & STR_UNICODE) && ret >= 2) {
191                         pkt_len = ret-2;
192                 }
193                 if ((flags & STR_ASCII) && ret >= 1) {
194                         pkt_len = ret-1;
195                 }
196         }
197
198         if (flags & STR_LEN8BIT) {
199                 SCVAL(blob->data, len_offset, pkt_len);
200         } else {
201                 SIVAL(blob->data, len_offset, pkt_len);
202         }
203
204         return ret + alignment;
205 }
206
207 /*
208   append a string to the data section of a trans2 reply
209   len_offset points to the place in the packet where the length field
210   should go
211 */
212 static NTSTATUS trans2_append_data_string(TALLOC_CTX *mem_ctx,
213                                           DATA_BLOB *blob,
214                                           const char *str,
215                                           uint_t len_offset,
216                                           int default_flags,
217                                           int flags)
218 {
219         size_t ret;
220         uint32_t offset;
221         const int max_bytes_per_char = 3;
222
223         offset = blob->length;
224         TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, offset + (2+strlen_m(str))*max_bytes_per_char));
225         ret = trans2_push_data_string(mem_ctx, blob, len_offset, offset, str, -1, default_flags, flags);
226         if (ret < 0) {
227                 return NT_STATUS_FOOBAR;
228         }
229         TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, offset + ret));
230         return NT_STATUS_OK;
231 }
232
233 /*
234   align the end of the data section of a trans reply on an even boundary
235 */
236 static NTSTATUS trans2_align_data(struct smb_trans2 *trans)
237 {
238         if (trans->out.data.length & 1) {
239                 TRANS2_CHECK(trans2_grow_data_fill(trans, &trans->out.data, trans->out.data.length+1));
240         }
241         return NT_STATUS_OK;
242 }
243
244 static NTSTATUS trans2_push_fsinfo(struct smbsrv_connection *smb_conn,
245                                    TALLOC_CTX *mem_ctx,
246                                    DATA_BLOB *blob,
247                                    union smb_fsinfo *fsinfo,
248                                    int default_str_flags)
249 {
250         uint_t i;
251         DATA_BLOB guid_blob;
252
253         switch (fsinfo->generic.level) {
254         case SMB_QFS_ALLOCATION:
255                 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 18));
256
257                 SIVAL(blob->data,  0, fsinfo->allocation.out.fs_id);
258                 SIVAL(blob->data,  4, fsinfo->allocation.out.sectors_per_unit);
259                 SIVAL(blob->data,  8, fsinfo->allocation.out.total_alloc_units);
260                 SIVAL(blob->data, 12, fsinfo->allocation.out.avail_alloc_units);
261                 SSVAL(blob->data, 16, fsinfo->allocation.out.bytes_per_sector);
262
263                 return NT_STATUS_OK;
264
265         case SMB_QFS_VOLUME:
266                 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 5));
267
268                 SIVAL(blob->data,       0, fsinfo->volume.out.serial_number);
269                 /* w2k3 implements this incorrectly for unicode - it
270                  * leaves the last byte off the string */
271                 TRANS2_CHECK(trans2_append_data_string(mem_ctx, blob,
272                                                        fsinfo->volume.out.volume_name.s,
273                                                        4, default_str_flags,
274                                                        STR_LEN8BIT|STR_NOALIGN));
275
276                 return NT_STATUS_OK;
277
278         case SMB_QFS_VOLUME_INFO:
279         case SMB_QFS_VOLUME_INFORMATION:
280                 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 18));
281
282                 push_nttime(blob->data, 0, fsinfo->volume_info.out.create_time);
283                 SIVAL(blob->data,       8, fsinfo->volume_info.out.serial_number);
284                 SSVAL(blob->data,      16, 0); /* padding */
285                 TRANS2_CHECK(trans2_append_data_string(mem_ctx, blob,
286                                                        fsinfo->volume_info.out.volume_name.s, 
287                                                        12, default_str_flags,
288                                                        STR_UNICODE));
289
290                 return NT_STATUS_OK;
291
292         case SMB_QFS_SIZE_INFO:
293         case SMB_QFS_SIZE_INFORMATION:
294                 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 24));
295
296                 SBVAL(blob->data,  0, fsinfo->size_info.out.total_alloc_units);
297                 SBVAL(blob->data,  8, fsinfo->size_info.out.avail_alloc_units);
298                 SIVAL(blob->data, 16, fsinfo->size_info.out.sectors_per_unit);
299                 SIVAL(blob->data, 20, fsinfo->size_info.out.bytes_per_sector);
300
301                 return NT_STATUS_OK;
302
303         case SMB_QFS_DEVICE_INFO:
304         case SMB_QFS_DEVICE_INFORMATION:
305                 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 8));
306
307                 SIVAL(blob->data,      0, fsinfo->device_info.out.device_type);
308                 SIVAL(blob->data,      4, fsinfo->device_info.out.characteristics);
309
310                 return NT_STATUS_OK;
311
312         case SMB_QFS_ATTRIBUTE_INFO:
313         case SMB_QFS_ATTRIBUTE_INFORMATION:
314                 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 12));
315
316                 SIVAL(blob->data, 0, fsinfo->attribute_info.out.fs_attr);
317                 SIVAL(blob->data, 4, fsinfo->attribute_info.out.max_file_component_length);
318                 /* this must not be null terminated or win98 gets
319                    confused!  also note that w2k3 returns this as
320                    unicode even when ascii is negotiated */
321                 TRANS2_CHECK(trans2_append_data_string(mem_ctx, blob,
322                                                        fsinfo->attribute_info.out.fs_type.s,
323                                                        8, default_str_flags,
324                                                        STR_UNICODE));
325                 return NT_STATUS_OK;
326
327
328         case SMB_QFS_QUOTA_INFORMATION:
329                 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 48));
330
331                 SBVAL(blob->data,   0, fsinfo->quota_information.out.unknown[0]);
332                 SBVAL(blob->data,   8, fsinfo->quota_information.out.unknown[1]);
333                 SBVAL(blob->data,  16, fsinfo->quota_information.out.unknown[2]);
334                 SBVAL(blob->data,  24, fsinfo->quota_information.out.quota_soft);
335                 SBVAL(blob->data,  32, fsinfo->quota_information.out.quota_hard);
336                 SBVAL(blob->data,  40, fsinfo->quota_information.out.quota_flags);
337
338                 return NT_STATUS_OK;
339
340
341         case SMB_QFS_FULL_SIZE_INFORMATION:
342                 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 32));
343
344                 SBVAL(blob->data,  0, fsinfo->full_size_information.out.total_alloc_units);
345                 SBVAL(blob->data,  8, fsinfo->full_size_information.out.call_avail_alloc_units);
346                 SBVAL(blob->data, 16, fsinfo->full_size_information.out.actual_avail_alloc_units);
347                 SIVAL(blob->data, 24, fsinfo->full_size_information.out.sectors_per_unit);
348                 SIVAL(blob->data, 28, fsinfo->full_size_information.out.bytes_per_sector);
349
350                 return NT_STATUS_OK;
351
352         case SMB_QFS_OBJECTID_INFORMATION:
353                 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 64));
354
355                 TRANS2_CHECK(ndr_push_struct_blob(&guid_blob, mem_ctx, 
356                                                   &fsinfo->objectid_information.out.guid,
357                                                   (ndr_push_flags_fn_t)ndr_push_GUID));
358                 memcpy(blob->data, guid_blob.data, guid_blob.length);
359
360                 for (i=0;i<6;i++) {
361                         SBVAL(blob->data, 16 + 8*i, fsinfo->objectid_information.out.unknown[i]);
362                 }
363
364                 return NT_STATUS_OK;
365         }
366
367         return NT_STATUS_INVALID_LEVEL;
368 }
369
370 /*
371   trans2 qfsinfo implementation send
372 */
373 static NTSTATUS trans2_qfsinfo_send(struct trans_op *op)
374 {
375         struct smbsrv_request *req = op->req;
376         struct smb_trans2 *trans = op->trans;
377         union smb_fsinfo *fsinfo;
378
379         TRANS2_CHECK_ASYNC_STATUS(fsinfo, union smb_fsinfo);
380
381         TRANS2_CHECK(trans2_setup_reply(trans, 0, 0, 0));
382
383         TRANS2_CHECK(trans2_push_fsinfo(req->smb_conn, trans,
384                                         &trans->out.data, fsinfo,
385                                         TRANS2_REQ_DEFAULT_STR_FLAGS(req)));
386
387         return NT_STATUS_OK;
388 }
389
390 /*
391   trans2 qfsinfo implementation
392 */
393 static NTSTATUS trans2_qfsinfo(struct smbsrv_request *req, struct trans_op *op)
394 {
395         struct smb_trans2 *trans = op->trans;
396         union smb_fsinfo *fsinfo;
397         uint16_t level;
398
399         /* make sure we got enough parameters */
400         if (trans->in.params.length != 2) {
401                 return NT_STATUS_FOOBAR;
402         }
403
404         fsinfo = talloc(op, union smb_fsinfo);
405         NT_STATUS_HAVE_NO_MEMORY(fsinfo);
406
407         op->op_info = fsinfo;
408         op->send_fn = trans2_qfsinfo_send;
409
410         level = SVAL(trans->in.params.data, 0);
411
412         switch (level) {
413         case SMB_QFS_ALLOCATION:
414                 fsinfo->allocation.level = RAW_QFS_ALLOCATION;
415                 return ntvfs_fsinfo(req->ntvfs, fsinfo);
416
417         case SMB_QFS_VOLUME:
418                 fsinfo->volume.level = RAW_QFS_VOLUME;
419                 return ntvfs_fsinfo(req->ntvfs, fsinfo);
420
421         case SMB_QFS_VOLUME_INFO:
422         case SMB_QFS_VOLUME_INFORMATION:
423                 fsinfo->volume_info.level = RAW_QFS_VOLUME_INFO;
424                 return ntvfs_fsinfo(req->ntvfs, fsinfo);
425
426         case SMB_QFS_SIZE_INFO:
427         case SMB_QFS_SIZE_INFORMATION:
428                 fsinfo->size_info.level = RAW_QFS_SIZE_INFO;
429                 return ntvfs_fsinfo(req->ntvfs, fsinfo);
430
431         case SMB_QFS_DEVICE_INFO:
432         case SMB_QFS_DEVICE_INFORMATION:
433                 fsinfo->device_info.level = RAW_QFS_DEVICE_INFO;
434                 return ntvfs_fsinfo(req->ntvfs, fsinfo);
435
436         case SMB_QFS_ATTRIBUTE_INFO:
437         case SMB_QFS_ATTRIBUTE_INFORMATION:
438                 fsinfo->attribute_info.level = RAW_QFS_ATTRIBUTE_INFO;
439                 return ntvfs_fsinfo(req->ntvfs, fsinfo);
440
441         case SMB_QFS_QUOTA_INFORMATION:
442                 fsinfo->quota_information.level = RAW_QFS_QUOTA_INFORMATION;
443                 return ntvfs_fsinfo(req->ntvfs, fsinfo);
444
445         case SMB_QFS_FULL_SIZE_INFORMATION:
446                 fsinfo->full_size_information.level = RAW_QFS_FULL_SIZE_INFORMATION;
447                 return ntvfs_fsinfo(req->ntvfs, fsinfo);
448
449         case SMB_QFS_OBJECTID_INFORMATION:
450                 fsinfo->objectid_information.level = RAW_QFS_OBJECTID_INFORMATION;
451                 return ntvfs_fsinfo(req->ntvfs, fsinfo);
452         }
453
454         return NT_STATUS_INVALID_LEVEL;
455 }
456
457
458 /*
459   trans2 open implementation send
460 */
461 static NTSTATUS trans2_open_send(struct trans_op *op)
462 {
463         struct smbsrv_request *req = op->req;
464         struct smb_trans2 *trans = op->trans;
465         union smb_open *io;
466
467         TRANS2_CHECK_ASYNC_STATUS(io, union smb_open);
468
469         TRANS2_CHECK(trans2_setup_reply(trans, 30, 0, 0));
470
471         smbsrv_push_fnum(trans->out.params.data, VWV(0), io->t2open.out.file.ntvfs);
472         SSVAL(trans->out.params.data, VWV(1), io->t2open.out.attrib);
473         srv_push_dos_date3(req->smb_conn, trans->out.params.data, 
474                            VWV(2), io->t2open.out.write_time);
475         SIVAL(trans->out.params.data, VWV(4), io->t2open.out.size);
476         SSVAL(trans->out.params.data, VWV(6), io->t2open.out.access);
477         SSVAL(trans->out.params.data, VWV(7), io->t2open.out.ftype);
478         SSVAL(trans->out.params.data, VWV(8), io->t2open.out.devstate);
479         SSVAL(trans->out.params.data, VWV(9), io->t2open.out.action);
480         SIVAL(trans->out.params.data, VWV(10), 0); /* reserved */
481         SSVAL(trans->out.params.data, VWV(12), 0); /* EaErrorOffset */
482         SIVAL(trans->out.params.data, VWV(13), 0); /* EaLength */
483
484         return NT_STATUS_OK;
485 }
486
487 /*
488   trans2 open implementation
489 */
490 static NTSTATUS trans2_open(struct smbsrv_request *req, struct trans_op *op)
491 {
492         struct smb_trans2 *trans = op->trans;
493         union smb_open *io;
494
495         /* make sure we got enough parameters */
496         if (trans->in.params.length < 29) {
497                 return NT_STATUS_FOOBAR;
498         }
499
500         io = talloc(op, union smb_open);
501         NT_STATUS_HAVE_NO_MEMORY(io);
502
503         io->t2open.level           = RAW_OPEN_T2OPEN;
504         io->t2open.in.flags        = SVAL(trans->in.params.data, VWV(0));
505         io->t2open.in.open_mode    = SVAL(trans->in.params.data, VWV(1));
506         io->t2open.in.search_attrs = SVAL(trans->in.params.data, VWV(2));
507         io->t2open.in.file_attrs   = SVAL(trans->in.params.data, VWV(3));
508         io->t2open.in.write_time   = srv_pull_dos_date(req->smb_conn, 
509                                                     trans->in.params.data + VWV(4));;
510         io->t2open.in.open_func    = SVAL(trans->in.params.data, VWV(6));
511         io->t2open.in.size         = IVAL(trans->in.params.data, VWV(7));
512         io->t2open.in.timeout      = IVAL(trans->in.params.data, VWV(9));
513         io->t2open.in.num_eas      = 0;
514         io->t2open.in.eas          = NULL;
515
516         trans2_pull_blob_string(req, &trans->in.params, 28, &io->t2open.in.fname, 0);
517         if (io->t2open.in.fname == NULL) {
518                 return NT_STATUS_FOOBAR;
519         }
520
521         TRANS2_CHECK(ea_pull_list(&trans->in.data, io, &io->t2open.in.num_eas, &io->t2open.in.eas));
522
523         op->op_info = io;
524         op->send_fn = trans2_open_send;
525
526         return ntvfs_open(req->ntvfs, io);
527 }
528
529
530 /*
531   trans2 simple send
532 */
533 static NTSTATUS trans2_simple_send(struct trans_op *op)
534 {
535         struct smbsrv_request *req = op->req;
536         struct smb_trans2 *trans = op->trans;
537
538         TRANS2_CHECK_ASYNC_STATUS_SIMPLE;
539
540         TRANS2_CHECK(trans2_setup_reply(trans, 2, 0, 0));
541
542         SSVAL(trans->out.params.data, VWV(0), 0);
543
544         return NT_STATUS_OK;
545 }
546
547 /*
548   trans2 mkdir implementation
549 */
550 static NTSTATUS trans2_mkdir(struct smbsrv_request *req, struct trans_op *op)
551 {
552         struct smb_trans2 *trans = op->trans;
553         union smb_mkdir *io;
554
555         /* make sure we got enough parameters */
556         if (trans->in.params.length < 5) {
557                 return NT_STATUS_FOOBAR;
558         }
559
560         io = talloc(op, union smb_mkdir);
561         NT_STATUS_HAVE_NO_MEMORY(io);
562
563         io->t2mkdir.level = RAW_MKDIR_T2MKDIR;
564         trans2_pull_blob_string(req, &trans->in.params, 4, &io->t2mkdir.in.path, 0);
565         if (io->t2mkdir.in.path == NULL) {
566                 return NT_STATUS_FOOBAR;
567         }
568
569         TRANS2_CHECK(ea_pull_list(&trans->in.data, io, 
570                                   &io->t2mkdir.in.num_eas, 
571                                   &io->t2mkdir.in.eas));
572
573         op->op_info = io;
574         op->send_fn = trans2_simple_send;
575
576         return ntvfs_mkdir(req->ntvfs, io);
577 }
578
579 static NTSTATUS trans2_push_passthru_fileinfo(TALLOC_CTX *mem_ctx,
580                                               DATA_BLOB *blob,
581                                               enum smb_fileinfo_level level,
582                                               union smb_fileinfo *st,
583                                               int default_str_flags)
584 {
585         uint_t i;
586         size_t list_size;
587
588         switch (level) {
589         case RAW_FILEINFO_BASIC_INFORMATION:
590                 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 40));
591
592                 push_nttime(blob->data,  0, st->basic_info.out.create_time);
593                 push_nttime(blob->data,  8, st->basic_info.out.access_time);
594                 push_nttime(blob->data, 16, st->basic_info.out.write_time);
595                 push_nttime(blob->data, 24, st->basic_info.out.change_time);
596                 SIVAL(blob->data,       32, st->basic_info.out.attrib);
597                 SIVAL(blob->data,       36, 0); /* padding */
598                 return NT_STATUS_OK;
599
600         case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
601                 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 56));
602
603                 push_nttime(blob->data,  0, st->network_open_information.out.create_time);
604                 push_nttime(blob->data,  8, st->network_open_information.out.access_time);
605                 push_nttime(blob->data, 16, st->network_open_information.out.write_time);
606                 push_nttime(blob->data, 24, st->network_open_information.out.change_time);
607                 SBVAL(blob->data,       32, st->network_open_information.out.alloc_size);
608                 SBVAL(blob->data,       40, st->network_open_information.out.size);
609                 SIVAL(blob->data,       48, st->network_open_information.out.attrib);
610                 SIVAL(blob->data,       52, 0); /* padding */
611                 return NT_STATUS_OK;
612
613         case RAW_FILEINFO_STANDARD_INFORMATION:
614                 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 24));
615
616                 SBVAL(blob->data,  0, st->standard_info.out.alloc_size);
617                 SBVAL(blob->data,  8, st->standard_info.out.size);
618                 SIVAL(blob->data, 16, st->standard_info.out.nlink);
619                 SCVAL(blob->data, 20, st->standard_info.out.delete_pending);
620                 SCVAL(blob->data, 21, st->standard_info.out.directory);
621                 SSVAL(blob->data, 22, 0); /* padding */
622                 return NT_STATUS_OK;
623
624         case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
625                 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 8));
626
627                 SIVAL(blob->data,  0, st->attribute_tag_information.out.attrib);
628                 SIVAL(blob->data,  4, st->attribute_tag_information.out.reparse_tag);
629                 return NT_STATUS_OK;
630
631         case RAW_FILEINFO_EA_INFORMATION:
632                 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 4));
633
634                 SIVAL(blob->data,  0, st->ea_info.out.ea_size);
635                 return NT_STATUS_OK;
636
637         case RAW_FILEINFO_MODE_INFORMATION:
638                 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 4));
639
640                 SIVAL(blob->data,  0, st->mode_information.out.mode);
641                 return NT_STATUS_OK;
642
643         case RAW_FILEINFO_ALIGNMENT_INFORMATION:
644                 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 4));
645
646                 SIVAL(blob->data,  0, 
647                       st->alignment_information.out.alignment_requirement);
648                 return NT_STATUS_OK;
649
650         case RAW_FILEINFO_ACCESS_INFORMATION:
651                 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 4));
652
653                 SIVAL(blob->data,  0, st->access_information.out.access_flags);
654                 return NT_STATUS_OK;
655
656         case RAW_FILEINFO_POSITION_INFORMATION:
657                 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 8));
658
659                 SBVAL(blob->data,  0, st->position_information.out.position);
660                 return NT_STATUS_OK;
661
662         case RAW_FILEINFO_COMPRESSION_INFORMATION:
663                 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 16));
664
665                 SBVAL(blob->data,  0, st->compression_info.out.compressed_size);
666                 SSVAL(blob->data,  8, st->compression_info.out.format);
667                 SCVAL(blob->data, 10, st->compression_info.out.unit_shift);
668                 SCVAL(blob->data, 11, st->compression_info.out.chunk_shift);
669                 SCVAL(blob->data, 12, st->compression_info.out.cluster_shift);
670                 SSVAL(blob->data, 13, 0); /* 3 bytes padding */
671                 SCVAL(blob->data, 15, 0);
672                 return NT_STATUS_OK;
673
674         case RAW_FILEINFO_INTERNAL_INFORMATION:
675                 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 8));
676
677                 SBVAL(blob->data,  0, st->internal_information.out.file_id);
678                 return NT_STATUS_OK;
679
680         case RAW_FILEINFO_ALL_INFORMATION:
681                 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 72));
682
683                 push_nttime(blob->data,  0, st->all_info.out.create_time);
684                 push_nttime(blob->data,  8, st->all_info.out.access_time);
685                 push_nttime(blob->data, 16, st->all_info.out.write_time);
686                 push_nttime(blob->data, 24, st->all_info.out.change_time);
687                 SIVAL(blob->data,       32, st->all_info.out.attrib);
688                 SIVAL(blob->data,       36, 0); /* padding */
689                 SBVAL(blob->data,       40, st->all_info.out.alloc_size);
690                 SBVAL(blob->data,       48, st->all_info.out.size);
691                 SIVAL(blob->data,       56, st->all_info.out.nlink);
692                 SCVAL(blob->data,       60, st->all_info.out.delete_pending);
693                 SCVAL(blob->data,       61, st->all_info.out.directory);
694                 SSVAL(blob->data,       62, 0); /* padding */
695                 SIVAL(blob->data,       64, st->all_info.out.ea_size);
696                 TRANS2_CHECK(trans2_append_data_string(mem_ctx, blob,
697                                                        st->all_info.out.fname.s,
698                                                        68, default_str_flags,
699                                                        STR_UNICODE));
700                 return NT_STATUS_OK;
701
702         case RAW_FILEINFO_NAME_INFORMATION:
703                 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 4));
704
705                 TRANS2_CHECK(trans2_append_data_string(mem_ctx, blob,
706                                                        st->name_info.out.fname.s,
707                                                        0, default_str_flags,
708                                                        STR_UNICODE));
709                 return NT_STATUS_OK;
710
711         case RAW_FILEINFO_ALT_NAME_INFORMATION:
712                 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 4));
713
714                 TRANS2_CHECK(trans2_append_data_string(mem_ctx, blob, 
715                                                        st->alt_name_info.out.fname.s,
716                                                        0, default_str_flags,
717                                                        STR_UNICODE));
718                 return NT_STATUS_OK;
719
720         case RAW_FILEINFO_STREAM_INFORMATION:
721                 for (i=0;i<st->stream_info.out.num_streams;i++) {
722                         uint32_t data_size = blob->length;
723                         uint8_t *data;
724
725                         TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, data_size + 24));
726                         data = blob->data + data_size;
727                         SBVAL(data,  8, st->stream_info.out.streams[i].size);
728                         SBVAL(data, 16, st->stream_info.out.streams[i].alloc_size);
729                         TRANS2_CHECK(trans2_append_data_string(mem_ctx, blob,
730                                                                st->stream_info.out.streams[i].stream_name.s,
731                                                                data_size + 4, default_str_flags,
732                                                                STR_UNICODE));
733                         if (i == st->stream_info.out.num_streams - 1) {
734                                 SIVAL(blob->data, data_size, 0);
735                         } else {
736                                 TRANS2_CHECK(trans2_grow_data_fill(mem_ctx, blob, (blob->length+7)&~7));
737                                 SIVAL(blob->data, data_size, 
738                                       blob->length - data_size);
739                         }
740                 }
741                 return NT_STATUS_OK;
742
743         case RAW_FILEINFO_SMB2_ALL_EAS:
744                 list_size = ea_list_size_chained(st->all_eas.out.num_eas,
745                                                  st->all_eas.out.eas);
746                 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, list_size));
747
748                 ea_put_list_chained(blob->data,
749                                     st->all_eas.out.num_eas,
750                                     st->all_eas.out.eas);
751                 return NT_STATUS_OK;
752
753         case RAW_FILEINFO_SMB2_ALL_INFORMATION:
754                 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 0x64));
755
756                 push_nttime(blob->data, 0x00, st->all_info2.out.create_time);
757                 push_nttime(blob->data, 0x08, st->all_info2.out.access_time);
758                 push_nttime(blob->data, 0x10, st->all_info2.out.write_time);
759                 push_nttime(blob->data, 0x18, st->all_info2.out.change_time);
760                 SIVAL(blob->data,       0x20, st->all_info2.out.attrib);
761                 SIVAL(blob->data,       0x24, st->all_info2.out.unknown1);
762                 SBVAL(blob->data,       0x28, st->all_info2.out.alloc_size);
763                 SBVAL(blob->data,       0x30, st->all_info2.out.size);
764                 SIVAL(blob->data,       0x38, st->all_info2.out.nlink);
765                 SCVAL(blob->data,       0x3C, st->all_info2.out.delete_pending);
766                 SCVAL(blob->data,       0x3D, st->all_info2.out.directory);
767                 SBVAL(blob->data,       0x40, st->all_info2.out.file_id);
768                 SIVAL(blob->data,       0x48, st->all_info2.out.ea_size);
769                 SIVAL(blob->data,       0x4C, st->all_info2.out.access_mask);
770                 SBVAL(blob->data,       0x50, st->all_info2.out.position);
771                 SBVAL(blob->data,       0x58, st->all_info2.out.mode);
772                 TRANS2_CHECK(trans2_append_data_string(mem_ctx, blob,
773                                                        st->all_info.out.fname.s,
774                                                        0x60, default_str_flags,
775                                                        STR_UNICODE));
776                 return NT_STATUS_OK;
777
778         default:
779                 return NT_STATUS_INVALID_LEVEL;
780         }
781
782         return NT_STATUS_INVALID_LEVEL;
783 }
784
785 static NTSTATUS trans2_push_fileinfo(struct smbsrv_connection *smb_conn,
786                                      TALLOC_CTX *mem_ctx,
787                                      DATA_BLOB *blob,
788                                      union smb_fileinfo *st,
789                                      int default_str_flags)
790 {
791         uint32_t list_size;
792         enum smb_fileinfo_level passthru_level;
793
794         switch (st->generic.level) {
795         case RAW_FILEINFO_GENERIC:
796         case RAW_FILEINFO_GETATTR:
797         case RAW_FILEINFO_GETATTRE:
798         case RAW_FILEINFO_SEC_DESC:
799         case RAW_FILEINFO_SMB2_ALL_EAS:
800         case RAW_FILEINFO_SMB2_ALL_INFORMATION:
801                 /* handled elsewhere */
802                 return NT_STATUS_INVALID_LEVEL;
803
804         case RAW_FILEINFO_UNIX_BASIC:
805         case RAW_FILEINFO_UNIX_LINK:
806                 /* not implemented yet */
807                 return NT_STATUS_INVALID_LEVEL;
808
809         case RAW_FILEINFO_STANDARD:
810                 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 22));
811
812                 srv_push_dos_date2(smb_conn, blob->data, 0, st->standard.out.create_time);
813                 srv_push_dos_date2(smb_conn, blob->data, 4, st->standard.out.access_time);
814                 srv_push_dos_date2(smb_conn, blob->data, 8, st->standard.out.write_time);
815                 SIVAL(blob->data,        12, st->standard.out.size);
816                 SIVAL(blob->data,        16, st->standard.out.alloc_size);
817                 SSVAL(blob->data,        20, st->standard.out.attrib);
818                 return NT_STATUS_OK;
819
820         case RAW_FILEINFO_EA_SIZE:
821                 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, 26));
822
823                 srv_push_dos_date2(smb_conn, blob->data, 0, st->ea_size.out.create_time);
824                 srv_push_dos_date2(smb_conn, blob->data, 4, st->ea_size.out.access_time);
825                 srv_push_dos_date2(smb_conn, blob->data, 8, st->ea_size.out.write_time);
826                 SIVAL(blob->data,        12, st->ea_size.out.size);
827                 SIVAL(blob->data,        16, st->ea_size.out.alloc_size);
828                 SSVAL(blob->data,        20, st->ea_size.out.attrib);
829                 SIVAL(blob->data,        22, st->ea_size.out.ea_size);
830                 return NT_STATUS_OK;
831
832         case RAW_FILEINFO_EA_LIST:
833                 list_size = ea_list_size(st->ea_list.out.num_eas,
834                                          st->ea_list.out.eas);
835                 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, list_size));
836
837                 ea_put_list(blob->data, 
838                             st->ea_list.out.num_eas, st->ea_list.out.eas);
839                 return NT_STATUS_OK;
840
841         case RAW_FILEINFO_ALL_EAS:
842                 list_size = ea_list_size(st->all_eas.out.num_eas,
843                                                   st->all_eas.out.eas);
844                 TRANS2_CHECK(trans2_grow_data(mem_ctx, blob, list_size));
845
846                 ea_put_list(blob->data, 
847                             st->all_eas.out.num_eas, st->all_eas.out.eas);
848                 return NT_STATUS_OK;
849
850         case RAW_FILEINFO_IS_NAME_VALID:
851                 return NT_STATUS_OK;
852
853         case RAW_FILEINFO_BASIC_INFO:
854                 passthru_level = RAW_FILEINFO_BASIC_INFORMATION;
855                 break;
856
857         case RAW_FILEINFO_STANDARD_INFO:
858                 passthru_level = RAW_FILEINFO_STANDARD_INFORMATION;
859                 break;
860
861         case RAW_FILEINFO_EA_INFO:
862                 passthru_level = RAW_FILEINFO_EA_INFORMATION;
863                 break;
864
865         case RAW_FILEINFO_COMPRESSION_INFO:
866                 passthru_level = RAW_FILEINFO_COMPRESSION_INFORMATION;
867                 break;
868
869         case RAW_FILEINFO_ALL_INFO:
870                 passthru_level = RAW_FILEINFO_ALL_INFORMATION;
871                 break;
872
873         case RAW_FILEINFO_NAME_INFO:
874                 passthru_level = RAW_FILEINFO_NAME_INFORMATION;
875                 break;
876
877         case RAW_FILEINFO_ALT_NAME_INFO:
878                 passthru_level = RAW_FILEINFO_ALT_NAME_INFORMATION;
879                 break;
880
881         case RAW_FILEINFO_STREAM_INFO:
882                 passthru_level = RAW_FILEINFO_STREAM_INFORMATION;
883                 break;
884
885         default:
886                 passthru_level = st->generic.level;
887                 break;
888         }
889
890         return trans2_push_passthru_fileinfo(mem_ctx, blob,
891                                              passthru_level, st,
892                                              default_str_flags);
893 }
894
895 /*
896   fill in the reply from a qpathinfo or qfileinfo call
897 */
898 static NTSTATUS trans2_fileinfo_send(struct trans_op *op)
899 {
900         struct smbsrv_request *req = op->req;
901         struct smb_trans2 *trans = op->trans;
902         union smb_fileinfo *st;
903
904         TRANS2_CHECK_ASYNC_STATUS(st, union smb_fileinfo);
905
906         TRANS2_CHECK(trans2_setup_reply(trans, 2, 0, 0));
907         SSVAL(trans->out.params.data, 0, 0);
908
909         TRANS2_CHECK(trans2_push_fileinfo(req->smb_conn, trans,
910                                           &trans->out.data, st,
911                                           TRANS2_REQ_DEFAULT_STR_FLAGS(req)));
912
913         return NT_STATUS_OK;
914 }
915
916 /*
917   trans2 qpathinfo implementation
918 */
919 static NTSTATUS trans2_qpathinfo(struct smbsrv_request *req, struct trans_op *op)
920 {
921         struct smb_trans2 *trans = op->trans;
922         union smb_fileinfo *st;
923         uint16_t level;
924
925         /* make sure we got enough parameters */
926         if (trans->in.params.length < 2) {
927                 return NT_STATUS_FOOBAR;
928         }
929
930         st = talloc(op, union smb_fileinfo);
931         NT_STATUS_HAVE_NO_MEMORY(st);
932
933         level = SVAL(trans->in.params.data, 0);
934
935         trans2_pull_blob_string(req, &trans->in.params, 6, &st->generic.in.file.path, 0);
936         if (st->generic.in.file.path == NULL) {
937                 return NT_STATUS_FOOBAR;
938         }
939
940         /* work out the backend level - we make it 1-1 in the header */
941         st->generic.level = (enum smb_fileinfo_level)level;
942         if (st->generic.level >= RAW_FILEINFO_GENERIC) {
943                 return NT_STATUS_INVALID_LEVEL;
944         }
945
946         if (st->generic.level == RAW_FILEINFO_EA_LIST) {
947                 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req, 
948                                                &st->ea_list.in.num_names,
949                                                &st->ea_list.in.ea_names));
950         }
951
952         op->op_info = st;
953         op->send_fn = trans2_fileinfo_send;
954
955         return ntvfs_qpathinfo(req->ntvfs, st);
956 }
957
958
959 /*
960   trans2 qpathinfo implementation
961 */
962 static NTSTATUS trans2_qfileinfo(struct smbsrv_request *req, struct trans_op *op)
963 {
964         struct smb_trans2 *trans = op->trans;
965         union smb_fileinfo *st;
966         uint16_t level;
967         struct ntvfs_handle *h;
968
969         /* make sure we got enough parameters */
970         if (trans->in.params.length < 4) {
971                 return NT_STATUS_FOOBAR;
972         }
973
974         st = talloc(op, union smb_fileinfo);
975         NT_STATUS_HAVE_NO_MEMORY(st);
976
977         h     = smbsrv_pull_fnum(req, trans->in.params.data, 0);
978         level = SVAL(trans->in.params.data, 2);
979
980         st->generic.in.file.ntvfs = h;
981         /* work out the backend level - we make it 1-1 in the header */
982         st->generic.level = (enum smb_fileinfo_level)level;
983         if (st->generic.level >= RAW_FILEINFO_GENERIC) {
984                 return NT_STATUS_INVALID_LEVEL;
985         }
986
987         if (st->generic.level == RAW_FILEINFO_EA_LIST) {
988                 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req, 
989                                                &st->ea_list.in.num_names,
990                                                &st->ea_list.in.ea_names));
991         }
992
993         op->op_info = st;
994         op->send_fn = trans2_fileinfo_send;
995
996         SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st->generic.in.file.ntvfs);
997         return ntvfs_qfileinfo(req->ntvfs, st);
998 }
999
1000
1001 /*
1002   parse a trans2 setfileinfo/setpathinfo data blob
1003 */
1004 static NTSTATUS trans2_parse_sfileinfo(struct smbsrv_request *req,
1005                                        union smb_setfileinfo *st,
1006                                        const DATA_BLOB *blob)
1007 {
1008         uint32_t len;
1009         DATA_BLOB str_blob;
1010
1011         switch (st->generic.level) {
1012         case RAW_SFILEINFO_GENERIC:
1013         case RAW_SFILEINFO_SETATTR:
1014         case RAW_SFILEINFO_SETATTRE:
1015         case RAW_SFILEINFO_SEC_DESC:
1016                 /* handled elsewhere */
1017                 return NT_STATUS_INVALID_LEVEL;
1018
1019         case RAW_SFILEINFO_STANDARD:
1020                 CHECK_MIN_BLOB_SIZE(blob, 12);
1021
1022                 st->standard.in.create_time = srv_pull_dos_date2(req->smb_conn, blob->data + 0);
1023                 st->standard.in.access_time = srv_pull_dos_date2(req->smb_conn, blob->data + 4);
1024                 st->standard.in.write_time  = srv_pull_dos_date2(req->smb_conn, blob->data + 8);
1025
1026                 return NT_STATUS_OK;
1027
1028         case RAW_SFILEINFO_EA_SET:
1029                 return ea_pull_list(blob, req, 
1030                                     &st->ea_set.in.num_eas, 
1031                                     &st->ea_set.in.eas);
1032
1033         case SMB_SFILEINFO_BASIC_INFO:
1034         case SMB_SFILEINFO_BASIC_INFORMATION:
1035                 CHECK_MIN_BLOB_SIZE(blob, 36);
1036
1037                 st->basic_info.in.create_time = pull_nttime(blob->data,  0);
1038                 st->basic_info.in.access_time = pull_nttime(blob->data,  8);
1039                 st->basic_info.in.write_time =  pull_nttime(blob->data, 16);
1040                 st->basic_info.in.change_time = pull_nttime(blob->data, 24);
1041                 st->basic_info.in.attrib =      IVAL(blob->data,        32);
1042
1043                 return NT_STATUS_OK;
1044
1045         case SMB_SFILEINFO_DISPOSITION_INFO:
1046         case SMB_SFILEINFO_DISPOSITION_INFORMATION:
1047                 CHECK_MIN_BLOB_SIZE(blob, 1);
1048
1049                 st->disposition_info.in.delete_on_close = CVAL(blob->data, 0);
1050
1051                 return NT_STATUS_OK;
1052
1053         case SMB_SFILEINFO_ALLOCATION_INFO:
1054         case SMB_SFILEINFO_ALLOCATION_INFORMATION:
1055                 CHECK_MIN_BLOB_SIZE(blob, 8);
1056
1057                 st->allocation_info.in.alloc_size = BVAL(blob->data, 0);
1058
1059                 return NT_STATUS_OK;                            
1060
1061         case RAW_SFILEINFO_END_OF_FILE_INFO:
1062         case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
1063                 CHECK_MIN_BLOB_SIZE(blob, 8);
1064
1065                 st->end_of_file_info.in.size = BVAL(blob->data, 0);
1066
1067                 return NT_STATUS_OK;
1068
1069         case RAW_SFILEINFO_RENAME_INFORMATION:
1070                 CHECK_MIN_BLOB_SIZE(blob, 12);
1071
1072                 st->rename_information.in.overwrite = CVAL(blob->data, 0);
1073                 st->rename_information.in.root_fid  = IVAL(blob->data, 4);
1074                 len                                 = IVAL(blob->data, 8);
1075                 str_blob.data = blob->data+12;
1076                 str_blob.length = MIN(blob->length, len);
1077                 trans2_pull_blob_string(req, &str_blob, 0,
1078                                         &st->rename_information.in.new_name,
1079                                         STR_UNICODE);
1080                 if (st->rename_information.in.new_name == NULL) {
1081                         return NT_STATUS_FOOBAR;
1082                 }
1083
1084                 return NT_STATUS_OK;
1085
1086         case RAW_SFILEINFO_POSITION_INFORMATION:
1087                 CHECK_MIN_BLOB_SIZE(blob, 8);
1088
1089                 st->position_information.in.position = BVAL(blob->data, 0);
1090
1091                 return NT_STATUS_OK;
1092
1093         case RAW_SFILEINFO_MODE_INFORMATION:
1094                 CHECK_MIN_BLOB_SIZE(blob, 4);
1095
1096                 st->mode_information.in.mode = IVAL(blob->data, 0);
1097
1098                 return NT_STATUS_OK;
1099
1100         case RAW_SFILEINFO_UNIX_BASIC:
1101         case RAW_SFILEINFO_UNIX_LINK:
1102         case RAW_SFILEINFO_UNIX_HLINK:
1103         case RAW_SFILEINFO_1023:
1104         case RAW_SFILEINFO_1025:
1105         case RAW_SFILEINFO_1029:
1106         case RAW_SFILEINFO_1032:
1107         case RAW_SFILEINFO_1039:
1108         case RAW_SFILEINFO_1040:
1109                 return NT_STATUS_INVALID_LEVEL;
1110         }
1111
1112         return NT_STATUS_INVALID_LEVEL;
1113 }
1114
1115 /*
1116   trans2 setfileinfo implementation
1117 */
1118 static NTSTATUS trans2_setfileinfo(struct smbsrv_request *req, struct trans_op *op)
1119 {
1120         struct smb_trans2 *trans = op->trans;
1121         union smb_setfileinfo *st;
1122         uint16_t level;
1123         struct ntvfs_handle *h;
1124
1125         /* make sure we got enough parameters */
1126         if (trans->in.params.length < 4) {
1127                 return NT_STATUS_FOOBAR;
1128         }
1129
1130         st = talloc(op, union smb_setfileinfo);
1131         NT_STATUS_HAVE_NO_MEMORY(st);
1132
1133         h     = smbsrv_pull_fnum(req, trans->in.params.data, 0);
1134         level = SVAL(trans->in.params.data, 2);
1135
1136         st->generic.in.file.ntvfs = h;
1137         /* work out the backend level - we make it 1-1 in the header */
1138         st->generic.level = (enum smb_setfileinfo_level)level;
1139         if (st->generic.level >= RAW_SFILEINFO_GENERIC) {
1140                 return NT_STATUS_INVALID_LEVEL;
1141         }
1142
1143         TRANS2_CHECK(trans2_parse_sfileinfo(req, st, &trans->in.data));
1144
1145         op->op_info = st;
1146         op->send_fn = trans2_simple_send;
1147
1148         SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st->generic.in.file.ntvfs);
1149         return ntvfs_setfileinfo(req->ntvfs, st);
1150 }
1151
1152 /*
1153   trans2 setpathinfo implementation
1154 */
1155 static NTSTATUS trans2_setpathinfo(struct smbsrv_request *req, struct trans_op *op)
1156 {
1157         struct smb_trans2 *trans = op->trans;
1158         union smb_setfileinfo *st;
1159         uint16_t level;
1160
1161         /* make sure we got enough parameters */
1162         if (trans->in.params.length < 4) {
1163                 return NT_STATUS_FOOBAR;
1164         }
1165
1166         st = talloc(op, union smb_setfileinfo);
1167         NT_STATUS_HAVE_NO_MEMORY(st);
1168
1169         level = SVAL(trans->in.params.data, 0);
1170
1171         trans2_pull_blob_string(req, &trans->in.params, 6, &st->generic.in.file.path, 0);
1172         if (st->generic.in.file.path == NULL) {
1173                 return NT_STATUS_FOOBAR;
1174         }
1175
1176         /* work out the backend level - we make it 1-1 in the header */
1177         st->generic.level = (enum smb_setfileinfo_level)level;
1178         if (st->generic.level >= RAW_SFILEINFO_GENERIC) {
1179                 return NT_STATUS_INVALID_LEVEL;
1180         }
1181
1182         TRANS2_CHECK(trans2_parse_sfileinfo(req, st, &trans->in.data));
1183
1184         op->op_info = st;
1185         op->send_fn = trans2_simple_send;
1186
1187         return ntvfs_setpathinfo(req->ntvfs, st);
1188 }
1189
1190
1191 /* a structure to encapsulate the state information about an in-progress ffirst/fnext operation */
1192 struct find_state {
1193         struct trans_op *op;
1194         void *search;
1195         enum smb_search_level level;
1196         uint16_t last_entry_offset;
1197         uint16_t flags;
1198 };
1199
1200 /*
1201   fill a single entry in a trans2 find reply 
1202 */
1203 static BOOL find_fill_info(struct find_state *state,
1204                            union smb_search_data *file)
1205 {
1206         struct smbsrv_request *req = state->op->req;
1207         struct smb_trans2 *trans = state->op->trans;
1208         uint8_t *data;
1209         uint_t ofs = trans->out.data.length;
1210         uint32_t ea_size;
1211
1212         switch (state->level) {
1213         case RAW_SEARCH_SEARCH:
1214         case RAW_SEARCH_FFIRST:
1215         case RAW_SEARCH_FUNIQUE:
1216         case RAW_SEARCH_GENERIC:
1217         case RAW_SEARCH_SMB2:
1218                 /* handled elsewhere */
1219                 return False;
1220
1221         case RAW_SEARCH_STANDARD:
1222                 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
1223                         trans2_grow_data(trans, &trans->out.data, ofs + 27);
1224                         SIVAL(trans->out.data.data, ofs, file->standard.resume_key);
1225                         ofs += 4;
1226                 } else {
1227                         trans2_grow_data(trans, &trans->out.data, ofs + 23);
1228                 }
1229                 data = trans->out.data.data + ofs;
1230                 srv_push_dos_date2(req->smb_conn, data, 0, file->standard.create_time);
1231                 srv_push_dos_date2(req->smb_conn, data, 4, file->standard.access_time);
1232                 srv_push_dos_date2(req->smb_conn, data, 8, file->standard.write_time);
1233                 SIVAL(data, 12, file->standard.size);
1234                 SIVAL(data, 16, file->standard.alloc_size);
1235                 SSVAL(data, 20, file->standard.attrib);
1236                 trans2_append_data_string(trans, &trans->out.data, file->standard.name.s, 
1237                                           ofs + 22, TRANS2_REQ_DEFAULT_STR_FLAGS(req),
1238                                           STR_LEN8BIT | STR_TERMINATE | STR_LEN_NOTERM);
1239                 break;
1240
1241         case RAW_SEARCH_EA_SIZE:
1242                 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
1243                         trans2_grow_data(trans, &trans->out.data, ofs + 31);
1244                         SIVAL(trans->out.data.data, ofs, file->ea_size.resume_key);
1245                         ofs += 4;
1246                 } else {
1247                         trans2_grow_data(trans, &trans->out.data, ofs + 27);
1248                 }
1249                 data = trans->out.data.data + ofs;
1250                 srv_push_dos_date2(req->smb_conn, data, 0, file->ea_size.create_time);
1251                 srv_push_dos_date2(req->smb_conn, data, 4, file->ea_size.access_time);
1252                 srv_push_dos_date2(req->smb_conn, data, 8, file->ea_size.write_time);
1253                 SIVAL(data, 12, file->ea_size.size);
1254                 SIVAL(data, 16, file->ea_size.alloc_size);
1255                 SSVAL(data, 20, file->ea_size.attrib);
1256                 SIVAL(data, 22, file->ea_size.ea_size);
1257                 trans2_append_data_string(trans, &trans->out.data, file->ea_size.name.s, 
1258                                           ofs + 26, TRANS2_REQ_DEFAULT_STR_FLAGS(req),
1259                                           STR_LEN8BIT | STR_NOALIGN);
1260                 trans2_grow_data(trans, &trans->out.data, trans->out.data.length + 1);
1261                 trans->out.data.data[trans->out.data.length-1] = 0;
1262                 break;
1263
1264         case RAW_SEARCH_EA_LIST:
1265                 ea_size = ea_list_size(file->ea_list.eas.num_eas, file->ea_list.eas.eas);
1266                 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
1267                         if (!NT_STATUS_IS_OK(trans2_grow_data(trans, &trans->out.data, ofs + 27 + ea_size))) {
1268                                 return False;
1269                         }
1270                         SIVAL(trans->out.data.data, ofs, file->ea_list.resume_key);
1271                         ofs += 4;
1272                 } else {
1273                         if (!NT_STATUS_IS_OK(trans2_grow_data(trans, &trans->out.data, ofs + 23 + ea_size))) {
1274                                 return False;
1275                         }
1276                 }
1277                 data = trans->out.data.data + ofs;
1278                 srv_push_dos_date2(req->smb_conn, data, 0, file->ea_list.create_time);
1279                 srv_push_dos_date2(req->smb_conn, data, 4, file->ea_list.access_time);
1280                 srv_push_dos_date2(req->smb_conn, data, 8, file->ea_list.write_time);
1281                 SIVAL(data, 12, file->ea_list.size);
1282                 SIVAL(data, 16, file->ea_list.alloc_size);
1283                 SSVAL(data, 20, file->ea_list.attrib);
1284                 ea_put_list(data+22, file->ea_list.eas.num_eas, file->ea_list.eas.eas);
1285                 trans2_append_data_string(trans, &trans->out.data, file->ea_list.name.s, 
1286                                           ofs + 22 + ea_size, TRANS2_REQ_DEFAULT_STR_FLAGS(req),
1287                                           STR_LEN8BIT | STR_NOALIGN);
1288                 trans2_grow_data(trans, &trans->out.data, trans->out.data.length + 1);
1289                 trans->out.data.data[trans->out.data.length-1] = 0;
1290                 break;
1291
1292         case RAW_SEARCH_DIRECTORY_INFO:
1293                 trans2_grow_data(trans, &trans->out.data, ofs + 64);
1294                 data = trans->out.data.data + ofs;
1295                 SIVAL(data,          4, file->directory_info.file_index);
1296                 push_nttime(data,    8, file->directory_info.create_time);
1297                 push_nttime(data,   16, file->directory_info.access_time);
1298                 push_nttime(data,   24, file->directory_info.write_time);
1299                 push_nttime(data,   32, file->directory_info.change_time);
1300                 SBVAL(data,         40, file->directory_info.size);
1301                 SBVAL(data,         48, file->directory_info.alloc_size);
1302                 SIVAL(data,         56, file->directory_info.attrib);
1303                 trans2_append_data_string(trans, &trans->out.data, file->directory_info.name.s, 
1304                                           ofs + 60, TRANS2_REQ_DEFAULT_STR_FLAGS(req),
1305                                           STR_TERMINATE_ASCII);
1306                 data = trans->out.data.data + ofs;
1307                 SIVAL(data,          0, trans->out.data.length - ofs);
1308                 break;
1309
1310         case RAW_SEARCH_FULL_DIRECTORY_INFO:
1311                 trans2_grow_data(trans, &trans->out.data, ofs + 68);
1312                 data = trans->out.data.data + ofs;
1313                 SIVAL(data,          4, file->full_directory_info.file_index);
1314                 push_nttime(data,    8, file->full_directory_info.create_time);
1315                 push_nttime(data,   16, file->full_directory_info.access_time);
1316                 push_nttime(data,   24, file->full_directory_info.write_time);
1317                 push_nttime(data,   32, file->full_directory_info.change_time);
1318                 SBVAL(data,         40, file->full_directory_info.size);
1319                 SBVAL(data,         48, file->full_directory_info.alloc_size);
1320                 SIVAL(data,         56, file->full_directory_info.attrib);
1321                 SIVAL(data,         64, file->full_directory_info.ea_size);
1322                 trans2_append_data_string(trans, &trans->out.data, file->full_directory_info.name.s, 
1323                                           ofs + 60, TRANS2_REQ_DEFAULT_STR_FLAGS(req),
1324                                           STR_TERMINATE_ASCII);
1325                 data = trans->out.data.data + ofs;
1326                 SIVAL(data,          0, trans->out.data.length - ofs);
1327                 break;
1328
1329         case RAW_SEARCH_NAME_INFO:
1330                 trans2_grow_data(trans, &trans->out.data, ofs + 12);
1331                 data = trans->out.data.data + ofs;
1332                 SIVAL(data,          4, file->name_info.file_index);
1333                 trans2_append_data_string(trans, &trans->out.data, file->name_info.name.s, 
1334                                           ofs + 8, TRANS2_REQ_DEFAULT_STR_FLAGS(req),
1335                                           STR_TERMINATE_ASCII);
1336                 data = trans->out.data.data + ofs;
1337                 SIVAL(data,          0, trans->out.data.length - ofs);
1338                 break;
1339
1340         case RAW_SEARCH_BOTH_DIRECTORY_INFO:
1341                 trans2_grow_data(trans, &trans->out.data, ofs + 94);
1342                 data = trans->out.data.data + ofs;
1343                 SIVAL(data,          4, file->both_directory_info.file_index);
1344                 push_nttime(data,    8, file->both_directory_info.create_time);
1345                 push_nttime(data,   16, file->both_directory_info.access_time);
1346                 push_nttime(data,   24, file->both_directory_info.write_time);
1347                 push_nttime(data,   32, file->both_directory_info.change_time);
1348                 SBVAL(data,         40, file->both_directory_info.size);
1349                 SBVAL(data,         48, file->both_directory_info.alloc_size);
1350                 SIVAL(data,         56, file->both_directory_info.attrib);
1351                 SIVAL(data,         64, file->both_directory_info.ea_size);
1352                 SCVAL(data,         69, 0); /* reserved */
1353                 memset(data+70,0,24);
1354                 trans2_push_data_string(trans, &trans->out.data, 
1355                                         68 + ofs, 70 + ofs, 
1356                                         file->both_directory_info.short_name.s, 
1357                                         24, TRANS2_REQ_DEFAULT_STR_FLAGS(req),
1358                                         STR_UNICODE | STR_LEN8BIT);
1359                 trans2_append_data_string(trans, &trans->out.data, file->both_directory_info.name.s, 
1360                                           ofs + 60, TRANS2_REQ_DEFAULT_STR_FLAGS(req),
1361                                           STR_TERMINATE_ASCII);
1362                 trans2_align_data(trans);
1363                 data = trans->out.data.data + ofs;
1364                 SIVAL(data,          0, trans->out.data.length - ofs);
1365                 break;
1366
1367         case RAW_SEARCH_ID_FULL_DIRECTORY_INFO:
1368                 trans2_grow_data(trans, &trans->out.data, ofs + 80);
1369                 data = trans->out.data.data + ofs;
1370                 SIVAL(data,          4, file->id_full_directory_info.file_index);
1371                 push_nttime(data,    8, file->id_full_directory_info.create_time);
1372                 push_nttime(data,   16, file->id_full_directory_info.access_time);
1373                 push_nttime(data,   24, file->id_full_directory_info.write_time);
1374                 push_nttime(data,   32, file->id_full_directory_info.change_time);
1375                 SBVAL(data,         40, file->id_full_directory_info.size);
1376                 SBVAL(data,         48, file->id_full_directory_info.alloc_size);
1377                 SIVAL(data,         56, file->id_full_directory_info.attrib);
1378                 SIVAL(data,         64, file->id_full_directory_info.ea_size);
1379                 SIVAL(data,         68, 0); /* padding */
1380                 SBVAL(data,         72, file->id_full_directory_info.file_id);
1381                 trans2_append_data_string(trans, &trans->out.data, file->id_full_directory_info.name.s, 
1382                                           ofs + 60, TRANS2_REQ_DEFAULT_STR_FLAGS(req),
1383                                           STR_TERMINATE_ASCII);
1384                 data = trans->out.data.data + ofs;
1385                 SIVAL(data,          0, trans->out.data.length - ofs);
1386                 break;
1387
1388         case RAW_SEARCH_ID_BOTH_DIRECTORY_INFO:
1389                 trans2_grow_data(trans, &trans->out.data, ofs + 104);
1390                 data = trans->out.data.data + ofs;
1391                 SIVAL(data,          4, file->id_both_directory_info.file_index);
1392                 push_nttime(data,    8, file->id_both_directory_info.create_time);
1393                 push_nttime(data,   16, file->id_both_directory_info.access_time);
1394                 push_nttime(data,   24, file->id_both_directory_info.write_time);
1395                 push_nttime(data,   32, file->id_both_directory_info.change_time);
1396                 SBVAL(data,         40, file->id_both_directory_info.size);
1397                 SBVAL(data,         48, file->id_both_directory_info.alloc_size);
1398                 SIVAL(data,         56, file->id_both_directory_info.attrib);
1399                 SIVAL(data,         64, file->id_both_directory_info.ea_size);
1400                 SCVAL(data,         69, 0); /* reserved */
1401                 memset(data+70,0,26);
1402                 trans2_push_data_string(trans, &trans->out.data, 
1403                                         68 + ofs, 70 + ofs, 
1404                                         file->id_both_directory_info.short_name.s, 
1405                                         24, TRANS2_REQ_DEFAULT_STR_FLAGS(req),
1406                                         STR_UNICODE | STR_LEN8BIT);
1407                 SBVAL(data,         96, file->id_both_directory_info.file_id);
1408                 trans2_append_data_string(trans, &trans->out.data, file->id_both_directory_info.name.s, 
1409                                           ofs + 60, TRANS2_REQ_DEFAULT_STR_FLAGS(req),
1410                                           STR_TERMINATE_ASCII);
1411                 data = trans->out.data.data + ofs;
1412                 SIVAL(data,          0, trans->out.data.length - ofs);
1413                 break;
1414         }
1415
1416         return True;
1417 }
1418
1419 /* callback function for trans2 findfirst/findnext */
1420 static BOOL find_callback(void *private, union smb_search_data *file)
1421 {
1422         struct find_state *state = talloc_get_type(private, struct find_state);
1423         struct smb_trans2 *trans = state->op->trans;
1424         uint_t old_length;
1425
1426         old_length = trans->out.data.length;
1427
1428         if (!find_fill_info(state, file) ||
1429             trans->out.data.length > trans->in.max_data) {
1430                 /* restore the old length and tell the backend to stop */
1431                 trans2_grow_data(trans, &trans->out.data, old_length);
1432                 return False;
1433         }
1434
1435         state->last_entry_offset = old_length;  
1436         return True;
1437 }
1438
1439 /*
1440   trans2 findfirst send
1441  */
1442 static NTSTATUS trans2_findfirst_send(struct trans_op *op)
1443 {
1444         struct smbsrv_request *req = op->req;
1445         struct smb_trans2 *trans = op->trans;
1446         union smb_search_first *search;
1447         struct find_state *state;
1448         uint8_t *param;
1449
1450         TRANS2_CHECK_ASYNC_STATUS(state, struct find_state);
1451         search = talloc_get_type(state->search, union smb_search_first);
1452
1453         /* fill in the findfirst reply header */
1454         param = trans->out.params.data;
1455         SSVAL(param, VWV(0), search->t2ffirst.out.handle);
1456         SSVAL(param, VWV(1), search->t2ffirst.out.count);
1457         SSVAL(param, VWV(2), search->t2ffirst.out.end_of_search);
1458         SSVAL(param, VWV(3), 0);
1459         SSVAL(param, VWV(4), state->last_entry_offset);
1460
1461         return NT_STATUS_OK;
1462 }
1463
1464
1465 /*
1466   trans2 findfirst implementation
1467 */
1468 static NTSTATUS trans2_findfirst(struct smbsrv_request *req, struct trans_op *op)
1469 {
1470         struct smb_trans2 *trans = op->trans;
1471         union smb_search_first *search;
1472         uint16_t level;
1473         struct find_state *state;
1474
1475         /* make sure we got all the parameters */
1476         if (trans->in.params.length < 14) {
1477                 return NT_STATUS_FOOBAR;
1478         }
1479
1480         search = talloc(op, union smb_search_first);
1481         NT_STATUS_HAVE_NO_MEMORY(search);
1482
1483         search->t2ffirst.in.search_attrib = SVAL(trans->in.params.data, 0);
1484         search->t2ffirst.in.max_count     = SVAL(trans->in.params.data, 2);
1485         search->t2ffirst.in.flags         = SVAL(trans->in.params.data, 4);
1486         level                             = SVAL(trans->in.params.data, 6);
1487         search->t2ffirst.in.storage_type  = IVAL(trans->in.params.data, 8);
1488
1489         trans2_pull_blob_string(req, &trans->in.params, 12, &search->t2ffirst.in.pattern, 0);
1490         if (search->t2ffirst.in.pattern == NULL) {
1491                 return NT_STATUS_FOOBAR;
1492         }
1493
1494         search->t2ffirst.level = (enum smb_search_level)level;
1495         if (search->t2ffirst.level >= RAW_SEARCH_GENERIC) {
1496                 return NT_STATUS_INVALID_LEVEL;
1497         }
1498
1499         if (search->t2ffirst.level == RAW_SEARCH_EA_LIST) {
1500                 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
1501                                                &search->t2ffirst.in.num_names, 
1502                                                &search->t2ffirst.in.ea_names));
1503         }
1504
1505         /* setup the private state structure that the backend will
1506            give us in the callback */
1507         state = talloc(op, struct find_state);
1508         NT_STATUS_HAVE_NO_MEMORY(state);
1509         state->op               = op;
1510         state->search           = search;
1511         state->level            = search->t2ffirst.level;
1512         state->last_entry_offset= 0;
1513         state->flags            = search->t2ffirst.in.flags;
1514
1515         /* setup for just a header in the reply */
1516         TRANS2_CHECK(trans2_setup_reply(trans, 10, 0, 0));
1517
1518         op->op_info = state;
1519         op->send_fn = trans2_findfirst_send;
1520
1521         return ntvfs_search_first(req->ntvfs, search, state, find_callback);
1522 }
1523
1524
1525 /*
1526   trans2 findnext send
1527 */
1528 static NTSTATUS trans2_findnext_send(struct trans_op *op)
1529 {
1530         struct smbsrv_request *req = op->req;
1531         struct smb_trans2 *trans = op->trans;
1532         union smb_search_next *search;
1533         struct find_state *state;
1534         uint8_t *param;
1535
1536         TRANS2_CHECK_ASYNC_STATUS(state, struct find_state);
1537         search = talloc_get_type(state->search, union smb_search_next);
1538
1539         /* fill in the findfirst reply header */
1540         param = trans->out.params.data;
1541         SSVAL(param, VWV(0), search->t2fnext.out.count);
1542         SSVAL(param, VWV(1), search->t2fnext.out.end_of_search);
1543         SSVAL(param, VWV(2), 0);
1544         SSVAL(param, VWV(3), state->last_entry_offset);
1545         
1546         return NT_STATUS_OK;
1547 }
1548
1549
1550 /*
1551   trans2 findnext implementation
1552 */
1553 static NTSTATUS trans2_findnext(struct smbsrv_request *req, struct trans_op *op)
1554 {
1555         struct smb_trans2 *trans = op->trans;
1556         union smb_search_next *search;
1557         uint16_t level;
1558         struct find_state *state;
1559
1560         /* make sure we got all the parameters */
1561         if (trans->in.params.length < 12) {
1562                 return NT_STATUS_FOOBAR;
1563         }
1564
1565         search = talloc(op, union smb_search_next);
1566         NT_STATUS_HAVE_NO_MEMORY(search);
1567
1568         search->t2fnext.in.handle        = SVAL(trans->in.params.data, 0);
1569         search->t2fnext.in.max_count     = SVAL(trans->in.params.data, 2);
1570         level                            = SVAL(trans->in.params.data, 4);
1571         search->t2fnext.in.resume_key    = IVAL(trans->in.params.data, 6);
1572         search->t2fnext.in.flags         = SVAL(trans->in.params.data, 10);
1573
1574         trans2_pull_blob_string(req, &trans->in.params, 12, &search->t2fnext.in.last_name, 0);
1575         if (search->t2fnext.in.last_name == NULL) {
1576                 return NT_STATUS_FOOBAR;
1577         }
1578
1579         search->t2fnext.level = (enum smb_search_level)level;
1580         if (search->t2fnext.level >= RAW_SEARCH_GENERIC) {
1581                 return NT_STATUS_INVALID_LEVEL;
1582         }
1583
1584         if (search->t2fnext.level == RAW_SEARCH_EA_LIST) {
1585                 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
1586                                                &search->t2fnext.in.num_names, 
1587                                                &search->t2fnext.in.ea_names));
1588         }
1589
1590         /* setup the private state structure that the backend will give us in the callback */
1591         state = talloc(op, struct find_state);
1592         NT_STATUS_HAVE_NO_MEMORY(state);
1593         state->op               = op;
1594         state->search           = search;
1595         state->level            = search->t2fnext.level;
1596         state->last_entry_offset= 0;
1597         state->flags            = search->t2fnext.in.flags;
1598
1599         /* setup for just a header in the reply */
1600         TRANS2_CHECK(trans2_setup_reply(trans, 8, 0, 0));
1601
1602         op->op_info = state;
1603         op->send_fn = trans2_findnext_send;
1604
1605         return ntvfs_search_next(req->ntvfs, search, state, find_callback);
1606 }
1607
1608
1609 /*
1610   backend for trans2 requests
1611 */
1612 static NTSTATUS trans2_backend(struct smbsrv_request *req, struct trans_op *op)
1613 {
1614         struct smb_trans2 *trans = op->trans;
1615         NTSTATUS status;
1616
1617         /* direct trans2 pass thru */
1618         status = ntvfs_trans2(req->ntvfs, trans);
1619         if (!NT_STATUS_EQUAL(NT_STATUS_NOT_IMPLEMENTED, status)) {
1620                 return status;
1621         }
1622
1623         /* must have at least one setup word */
1624         if (trans->in.setup_count < 1) {
1625                 return NT_STATUS_FOOBAR;
1626         }
1627
1628         /* the trans2 command is in setup[0] */
1629         switch (trans->in.setup[0]) {
1630         case TRANSACT2_FINDFIRST:
1631                 return trans2_findfirst(req, op);
1632         case TRANSACT2_FINDNEXT:
1633                 return trans2_findnext(req, op);
1634         case TRANSACT2_QPATHINFO:
1635                 return trans2_qpathinfo(req, op);
1636         case TRANSACT2_QFILEINFO:
1637                 return trans2_qfileinfo(req, op);
1638         case TRANSACT2_SETFILEINFO:
1639                 return trans2_setfileinfo(req, op);
1640         case TRANSACT2_SETPATHINFO:
1641                 return trans2_setpathinfo(req, op);
1642         case TRANSACT2_QFSINFO:
1643                 return trans2_qfsinfo(req, op);
1644         case TRANSACT2_OPEN:
1645                 return trans2_open(req, op);
1646         case TRANSACT2_MKDIR:
1647                 return trans2_mkdir(req, op);
1648         }
1649
1650         /* an unknown trans2 command */
1651         return NT_STATUS_FOOBAR;
1652 }
1653
1654
1655 /*
1656   send a continue request
1657 */
1658 static void reply_trans_continue(struct smbsrv_request *req, uint8_t command,
1659                                  struct smb_trans2 *trans)
1660 {
1661         struct smbsrv_trans_partial *tp;
1662         int count;
1663
1664         /* make sure they don't flood us */
1665         for (count=0,tp=req->smb_conn->trans_partial;tp;tp=tp->next) count++;
1666         if (count > 100) {
1667                 smbsrv_send_error(req, NT_STATUS_INSUFFICIENT_RESOURCES);
1668                 return;
1669         }
1670
1671         tp = talloc(req, struct smbsrv_trans_partial);
1672
1673         tp->req = talloc_reference(tp, req);
1674         tp->trans = trans;
1675         tp->command = command;
1676
1677         DLIST_ADD(req->smb_conn->trans_partial, tp);
1678
1679         /* send a 'please continue' reply */
1680         smbsrv_setup_reply(req, 0, 0);
1681         smbsrv_send_reply(req);
1682 }
1683
1684
1685 /*
1686   answer a reconstructed trans request
1687 */
1688 static void reply_trans_send(struct ntvfs_request *ntvfs)
1689 {
1690         struct smbsrv_request *req;
1691         struct trans_op *op;
1692         struct smb_trans2 *trans;
1693         uint16_t params_left, data_left;
1694         uint8_t *params, *data;
1695         int i;
1696
1697         SMBSRV_CHECK_ASYNC_STATUS_ERR(op, struct trans_op);
1698         trans = op->trans;
1699
1700         /* if this function needs work to form the nttrans reply buffer, then
1701            call that now */
1702         if (op->send_fn != NULL) {
1703                 NTSTATUS status;
1704                 status = op->send_fn(op);
1705                 if (!NT_STATUS_IS_OK(status)) {
1706                         smbsrv_send_error(req, status);
1707                         return;
1708                 }
1709         }
1710
1711         params_left = trans->out.params.length;
1712         data_left   = trans->out.data.length;
1713         params      = trans->out.params.data;
1714         data        = trans->out.data.data;
1715
1716         smbsrv_setup_reply(req, 10 + trans->out.setup_count, 0);
1717
1718         if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) {
1719                 smbsrv_setup_error(req, req->ntvfs->async_states->status);
1720         }
1721
1722         /* we need to divide up the reply into chunks that fit into
1723            the negotiated buffer size */
1724         do {
1725                 uint16_t this_data, this_param, max_bytes;
1726                 uint_t align1 = 1, align2 = (params_left ? 2 : 0);
1727                 struct smbsrv_request *this_req;
1728
1729                 max_bytes = req_max_data(req) - (align1 + align2);
1730
1731                 this_param = params_left;
1732                 if (this_param > max_bytes) {
1733                         this_param = max_bytes;
1734                 }
1735                 max_bytes -= this_param;
1736
1737                 this_data = data_left;
1738                 if (this_data > max_bytes) {
1739                         this_data = max_bytes;
1740                 }
1741
1742                 /* don't destroy unless this is the last chunk */
1743                 if (params_left - this_param != 0 || 
1744                     data_left - this_data != 0) {
1745                         this_req = smbsrv_setup_secondary_request(req);
1746                 } else {
1747                         this_req = req;
1748                 }
1749
1750                 req_grow_data(this_req, this_param + this_data + (align1 + align2));
1751
1752                 SSVAL(this_req->out.vwv, VWV(0), trans->out.params.length);
1753                 SSVAL(this_req->out.vwv, VWV(1), trans->out.data.length);
1754                 SSVAL(this_req->out.vwv, VWV(2), 0);
1755
1756                 SSVAL(this_req->out.vwv, VWV(3), this_param);
1757                 SSVAL(this_req->out.vwv, VWV(4), align1 + PTR_DIFF(this_req->out.data, this_req->out.hdr));
1758                 SSVAL(this_req->out.vwv, VWV(5), PTR_DIFF(params, trans->out.params.data));
1759
1760                 SSVAL(this_req->out.vwv, VWV(6), this_data);
1761                 SSVAL(this_req->out.vwv, VWV(7), align1 + align2 + 
1762                       PTR_DIFF(this_req->out.data + this_param, this_req->out.hdr));
1763                 SSVAL(this_req->out.vwv, VWV(8), PTR_DIFF(data, trans->out.data.data));
1764
1765                 SSVAL(this_req->out.vwv, VWV(9), trans->out.setup_count);
1766                 for (i=0;i<trans->out.setup_count;i++) {
1767                         SSVAL(this_req->out.vwv, VWV(10+i), trans->out.setup[i]);
1768                 }
1769
1770                 memset(this_req->out.data, 0, align1);
1771                 if (this_param != 0) {
1772                         memcpy(this_req->out.data + align1, params, this_param);
1773                 }
1774                 memset(this_req->out.data+this_param+align1, 0, align2);
1775                 if (this_data != 0) {
1776                         memcpy(this_req->out.data+this_param+align1+align2, data, this_data);
1777                 }
1778
1779                 params_left -= this_param;
1780                 data_left -= this_data;
1781                 params += this_param;
1782                 data += this_data;
1783
1784                 smbsrv_send_reply(this_req);
1785         } while (params_left != 0 || data_left != 0);
1786 }
1787
1788
1789 /*
1790   answer a reconstructed trans request
1791 */
1792 static void reply_trans_complete(struct smbsrv_request *req, uint8_t command,
1793                                  struct smb_trans2 *trans)
1794 {
1795         struct trans_op *op;
1796
1797         SMBSRV_TALLOC_IO_PTR(op, struct trans_op);
1798         SMBSRV_SETUP_NTVFS_REQUEST(reply_trans_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1799
1800         op->req         = req;
1801         op->trans       = trans;
1802         op->command     = command;
1803         op->op_info     = NULL;
1804         op->send_fn     = NULL;
1805
1806         /* its a full request, give it to the backend */
1807         if (command == SMBtrans) {
1808                 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_trans(req->ntvfs, trans));
1809                 return;
1810         } else {
1811                 SMBSRV_CALL_NTVFS_BACKEND(trans2_backend(req, op));
1812                 return;
1813         }
1814 }
1815
1816 /*
1817   Reply to an SMBtrans or SMBtrans2 request
1818 */
1819 static void reply_trans_generic(struct smbsrv_request *req, uint8_t command)
1820 {
1821         struct smb_trans2 *trans;
1822         int i;
1823         uint16_t param_ofs, data_ofs;
1824         uint16_t param_count, data_count;
1825         uint16_t param_total, data_total;
1826
1827         /* parse request */
1828         if (req->in.wct < 14) {
1829                 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1830                 return;
1831         }
1832
1833         trans = talloc(req, struct smb_trans2);
1834         if (trans == NULL) {
1835                 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
1836                 return;
1837         }
1838
1839         param_total           = SVAL(req->in.vwv, VWV(0));
1840         data_total            = SVAL(req->in.vwv, VWV(1));
1841         trans->in.max_param   = SVAL(req->in.vwv, VWV(2));
1842         trans->in.max_data    = SVAL(req->in.vwv, VWV(3));
1843         trans->in.max_setup   = CVAL(req->in.vwv, VWV(4));
1844         trans->in.flags       = SVAL(req->in.vwv, VWV(5));
1845         trans->in.timeout     = IVAL(req->in.vwv, VWV(6));
1846         param_count           = SVAL(req->in.vwv, VWV(9));
1847         param_ofs             = SVAL(req->in.vwv, VWV(10));
1848         data_count            = SVAL(req->in.vwv, VWV(11));
1849         data_ofs              = SVAL(req->in.vwv, VWV(12));
1850         trans->in.setup_count = CVAL(req->in.vwv, VWV(13));
1851
1852         if (req->in.wct != 14 + trans->in.setup_count) {
1853                 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
1854                 return;
1855         }
1856
1857         /* parse out the setup words */
1858         trans->in.setup = talloc_array(trans, uint16_t, trans->in.setup_count);
1859         if (trans->in.setup_count && !trans->in.setup) {
1860                 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
1861                 return;
1862         }
1863         for (i=0;i<trans->in.setup_count;i++) {
1864                 trans->in.setup[i] = SVAL(req->in.vwv, VWV(14+i));
1865         }
1866
1867         if (command == SMBtrans) {
1868                 req_pull_string(req, &trans->in.trans_name, req->in.data, -1, STR_TERMINATE);
1869         }
1870
1871         if (!req_pull_blob(req, req->in.hdr + param_ofs, param_count, &trans->in.params) ||
1872             !req_pull_blob(req, req->in.hdr + data_ofs, data_count, &trans->in.data)) {
1873                 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1874                 return;
1875         }
1876
1877         /* is it a partial request? if so, then send a 'send more' message */
1878         if (param_total > param_count || data_total > data_count) {
1879                 reply_trans_continue(req, command, trans);
1880                 return;
1881         }
1882
1883         reply_trans_complete(req, command, trans);
1884 }
1885
1886
1887 /*
1888   Reply to an SMBtranss2 request
1889 */
1890 static void reply_transs_generic(struct smbsrv_request *req, uint8_t command)
1891 {
1892         struct smbsrv_trans_partial *tp;
1893         struct smb_trans2 *trans = NULL;
1894         uint16_t param_ofs, data_ofs;
1895         uint16_t param_count, data_count;
1896         uint16_t param_disp, data_disp;
1897         uint16_t param_total, data_total;
1898         DATA_BLOB params, data;
1899
1900         /* parse request */
1901         if (req->in.wct < 8) {
1902                 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1903                 return;
1904         }
1905
1906         for (tp=req->smb_conn->trans_partial;tp;tp=tp->next) {
1907                 if (tp->command == command &&
1908                     SVAL(tp->req->in.hdr, HDR_MID) == SVAL(req->in.hdr, HDR_MID)) {
1909 /* TODO: check the VUID, PID and TID too? */
1910                         break;
1911                 }
1912         }
1913
1914         if (tp == NULL) {
1915                 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1916                 return;
1917         }
1918
1919         trans = tp->trans;
1920
1921         param_total           = SVAL(req->in.vwv, VWV(0));
1922         data_total            = SVAL(req->in.vwv, VWV(1));
1923         param_count           = SVAL(req->in.vwv, VWV(2));
1924         param_ofs             = SVAL(req->in.vwv, VWV(3));
1925         param_disp            = SVAL(req->in.vwv, VWV(4));
1926         data_count            = SVAL(req->in.vwv, VWV(5));
1927         data_ofs              = SVAL(req->in.vwv, VWV(6));
1928         data_disp             = SVAL(req->in.vwv, VWV(7));
1929
1930         if (!req_pull_blob(req, req->in.hdr + param_ofs, param_count, &params) ||
1931             !req_pull_blob(req, req->in.hdr + data_ofs, data_count, &data)) {
1932                 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1933                 return;
1934         }
1935
1936         /* only allow contiguous requests */
1937         if ((param_count != 0 &&
1938              param_disp != trans->in.params.length) ||
1939             (data_count != 0 && 
1940              data_disp != trans->in.data.length)) {
1941                 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1942                 return;         
1943         }
1944
1945         /* add to the existing request */
1946         if (param_count != 0) {
1947                 trans->in.params.data = talloc_realloc(trans, 
1948                                                          trans->in.params.data, 
1949                                                          uint8_t, 
1950                                                          param_disp + param_count);
1951                 if (trans->in.params.data == NULL) {
1952                         goto failed;
1953                 }
1954                 trans->in.params.length = param_disp + param_count;
1955         }
1956
1957         if (data_count != 0) {
1958                 trans->in.data.data = talloc_realloc(trans, 
1959                                                        trans->in.data.data, 
1960                                                        uint8_t, 
1961                                                        data_disp + data_count);
1962                 if (trans->in.data.data == NULL) {
1963                         goto failed;
1964                 }
1965                 trans->in.data.length = data_disp + data_count;
1966         }
1967
1968         memcpy(trans->in.params.data + param_disp, params.data, params.length);
1969         memcpy(trans->in.data.data + data_disp, data.data, data.length);
1970
1971         /* the sequence number of the reply is taken from the last secondary
1972            response */
1973         tp->req->seq_num = req->seq_num;
1974
1975         /* we don't reply to Transs2 requests */
1976         talloc_free(req);
1977
1978         if (trans->in.params.length == param_total &&
1979             trans->in.data.length == data_total) {
1980                 /* its now complete */
1981                 DLIST_REMOVE(tp->req->smb_conn->trans_partial, tp);
1982                 reply_trans_complete(tp->req, command, trans);
1983         }
1984         return;
1985
1986 failed: 
1987         smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
1988         DLIST_REMOVE(req->smb_conn->trans_partial, tp);
1989         talloc_free(req);
1990         talloc_free(tp);
1991 }
1992
1993
1994 /*
1995   Reply to an SMBtrans2
1996 */
1997 void smbsrv_reply_trans2(struct smbsrv_request *req)
1998 {
1999         reply_trans_generic(req, SMBtrans2);
2000 }
2001
2002 /*
2003   Reply to an SMBtrans
2004 */
2005 void smbsrv_reply_trans(struct smbsrv_request *req)
2006 {
2007         reply_trans_generic(req, SMBtrans);
2008 }
2009
2010 /*
2011   Reply to an SMBtranss request
2012 */
2013 void smbsrv_reply_transs(struct smbsrv_request *req)
2014 {
2015         reply_transs_generic(req, SMBtrans);
2016 }
2017
2018 /*
2019   Reply to an SMBtranss2 request
2020 */
2021 void smbsrv_reply_transs2(struct smbsrv_request *req)
2022 {
2023         reply_transs_generic(req, SMBtrans2);
2024 }