1/*
2   Unix SMB/CIFS implementation.
3
4   NTVFS generic level mapping code
5
6   Copyright (C) Andrew Tridgell 2003-2004
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 3 of the License, or
11   (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program.  If not, see <http://www.gnu.org/licenses/>.
20*/
21/*
22  this implements mappings between info levels for NTVFS backend calls
23
24  the idea is that each of these functions implements one of the NTVFS
25  backend calls in terms of the 'generic' call. All backends that use
26  these functions must supply the generic call, but can if it wants to
27  also implement other levels if the need arises
28
29  this allows backend writers to only implement one variant of each
30  call unless they need fine grained control of the calls.
31*/
32
33#include "includes.h"
34#include "ntvfs/ntvfs.h"
35#include "libcli/smb2/smb2.h"
36#include "libcli/smb2/smb2_calls.h"
37
38/* a second stage function converts from the out parameters of the generic
39   call onto the out parameters of the specific call made */
40typedef NTSTATUS (*second_stage_t)(struct ntvfs_module_context *,
41				   struct ntvfs_request *,
42				   void *, void *, NTSTATUS);
43
44/*
45   this structure holds the async state for pending mapped async calls
46*/
47struct ntvfs_map_async {
48	struct ntvfs_module_context *ntvfs;
49	void *io, *io2;
50	second_stage_t fn;
51};
52
53/*
54  this is a async wrapper, called from the backend when it has completed
55  a function that it has decided to reply to in an async fashion
56*/
57static void ntvfs_map_async_send(struct ntvfs_request *req)
58{
59	struct ntvfs_map_async *m = talloc_get_type(req->async_states->private_data,
60				    struct ntvfs_map_async);
61
62	ntvfs_async_state_pop(req);
63
64	/* call the _finish function setup in ntvfs_map_async_setup() */
65	req->async_states->status = m->fn(m->ntvfs, req, m->io, m->io2, req->async_states->status);
66
67	/* call the send function from the next module up */
68	req->async_states->send_fn(req);
69}
70
71/*
72  prepare for calling a ntvfs backend with async support
73  io is the original call structure
74  io2 is the new call structure for the mapped call
75  fn is a second stage function for processing the out arguments
76*/
77static NTSTATUS ntvfs_map_async_setup(struct ntvfs_module_context *ntvfs,
78				      struct ntvfs_request *req,
79				      void *io, void *io2,
80				      second_stage_t fn)
81{
82	struct ntvfs_map_async *m;
83	m = talloc(req, struct ntvfs_map_async);
84	if (m == NULL) {
85		return NT_STATUS_NO_MEMORY;
86	}
87	m->ntvfs = ntvfs;
88	m->io = io;
89	m->io2 = io2;
90	m->fn = fn;
91	return ntvfs_async_state_push(ntvfs, req, m, ntvfs_map_async_send);
92}
93
94/*
95  called when first stage processing is complete.
96*/
97static NTSTATUS ntvfs_map_async_finish(struct ntvfs_request *req, NTSTATUS status)
98{
99	struct ntvfs_map_async *m;
100
101	/* if the backend has decided to reply in an async fashion then
102	   we don't need to do any work here */
103	if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
104		return status;
105	}
106
107	/* the backend is replying immediately. call the 2nd stage function after popping our local
108	   async state */
109	m = talloc_get_type(req->async_states->private_data,
110			    struct ntvfs_map_async);
111
112	ntvfs_async_state_pop(req);
113
114	return m->fn(m->ntvfs, req, m->io, m->io2, status);
115}
116
117/*
118  see if a filename ends in EXE COM DLL or SYM. This is needed for the
119  DENY_DOS mapping for OpenX
120*/
121bool is_exe_filename(const char *fname)
122{
123	char *p;
124	p = strrchr(fname, '.');
125	if (!p) {
126		return false;
127	}
128	p++;
129	if (strcasecmp(p, "EXE") == 0 ||
130	    strcasecmp(p, "COM") == 0 ||
131	    strcasecmp(p, "DLL") == 0 ||
132	    strcasecmp(p, "SYM") == 0) {
133		return true;
134	}
135	return false;
136}
137
138
139/*
140   NTVFS openx to ntcreatex mapper
141*/
142static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs,
143				      struct ntvfs_request *req,
144				      union smb_open *io,
145				      union smb_open *io2,
146				      NTSTATUS status)
147{
148	time_t write_time = 0;
149	uint32_t set_size = 0;
150	union smb_setfileinfo *sf;
151	uint_t state;
152
153	if (!NT_STATUS_IS_OK(status)) {
154		return status;
155	}
156
157	switch (io->generic.level) {
158	case RAW_OPEN_OPEN:
159		io->openold.out.file.ntvfs = io2->generic.out.file.ntvfs;
160		io->openold.out.attrib     = io2->generic.out.attrib;
161		io->openold.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
162		io->openold.out.size       = io2->generic.out.size;
163		io->openold.out.rmode      = io->openold.in.open_mode;
164		break;
165
166	case RAW_OPEN_OPENX:
167		io->openx.out.file.ntvfs  = io2->generic.out.file.ntvfs;
168		io->openx.out.attrib      = io2->generic.out.attrib;
169		io->openx.out.write_time  = nt_time_to_unix(io2->generic.out.write_time);
170		io->openx.out.size        = io2->generic.out.size;
171		io->openx.out.access      = (io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK);
172		io->openx.out.ftype       = 0;
173		io->openx.out.devstate    = 0;
174		io->openx.out.action      = io2->generic.out.create_action;
175		io->openx.out.unique_fid  = 0;
176		io->openx.out.access_mask = SEC_STD_ALL;
177		io->openx.out.unknown     = 0;
178
179		/* we need to extend the file to the requested size if
180		   it was newly created */
181		if (io2->generic.out.create_action == NTCREATEX_ACTION_CREATED) {
182			set_size = io->openx.in.size;
183		}
184		break;
185
186	case RAW_OPEN_T2OPEN:
187		io->t2open.out.file.ntvfs  = io2->generic.out.file.ntvfs;
188		io->t2open.out.attrib      = io2->generic.out.attrib;
189		io->t2open.out.write_time  = nt_time_to_unix(io2->generic.out.write_time);
190		io->t2open.out.size        = io2->generic.out.size;
191		io->t2open.out.access      = io->t2open.in.open_mode;
192		io->t2open.out.ftype       = 0;
193		io->t2open.out.devstate    = 0;
194		io->t2open.out.action      = io2->generic.out.create_action;
195		io->t2open.out.file_id      = 0;
196		break;
197
198	case RAW_OPEN_MKNEW:
199	case RAW_OPEN_CREATE:
200		io->mknew.out.file.ntvfs= io2->generic.out.file.ntvfs;
201		write_time		= io->mknew.in.write_time;
202		break;
203
204	case RAW_OPEN_CTEMP:
205		io->ctemp.out.file.ntvfs= io2->generic.out.file.ntvfs;
206		io->ctemp.out.name 	= talloc_strdup(req, io2->generic.in.fname +
207							strlen(io->ctemp.in.directory) + 1);
208		NT_STATUS_HAVE_NO_MEMORY(io->ctemp.out.name);
209		break;
210
211	case RAW_OPEN_SMB2:
212		ZERO_STRUCT(io->smb2.out);
213		io->smb2.out.file.ntvfs		= io2->generic.out.file.ntvfs;
214		switch (io2->generic.out.oplock_level) {
215		case BATCH_OPLOCK_RETURN:
216			io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
217			break;
218		case EXCLUSIVE_OPLOCK_RETURN:
219			io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
220			break;
221		case LEVEL_II_OPLOCK_RETURN:
222			io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_II;
223			break;
224		default:
225			io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
226			break;
227		}
228		io->smb2.out.reserved		= 0;
229		io->smb2.out.create_action	= io2->generic.out.create_action;
230		io->smb2.out.create_time	= io2->generic.out.create_time;
231		io->smb2.out.access_time	= io2->generic.out.access_time;
232		io->smb2.out.write_time		= io2->generic.out.write_time;
233		io->smb2.out.change_time	= io2->generic.out.change_time;
234		io->smb2.out.alloc_size		= io2->generic.out.alloc_size;
235		io->smb2.out.size		= io2->generic.out.size;
236		io->smb2.out.file_attr		= io2->generic.out.attrib;
237		io->smb2.out.reserved2		= 0;
238		io->smb2.out.maximal_access     = io2->generic.out.maximal_access;
239		break;
240
241	default:
242		return NT_STATUS_INVALID_LEVEL;
243	}
244
245	/* doing a secondary request async is more trouble than its
246	   worth */
247	state = req->async_states->state;
248	req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
249
250	if (write_time != 0) {
251		sf = talloc(req, union smb_setfileinfo);
252		NT_STATUS_HAVE_NO_MEMORY(sf);
253		sf->generic.level           = RAW_SFILEINFO_STANDARD;
254		sf->generic.in.file.ntvfs   = io2->generic.out.file.ntvfs;
255		sf->standard.in.create_time = 0;
256		sf->standard.in.write_time  = write_time;
257		sf->standard.in.access_time = 0;
258		status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
259	}
260
261	if (set_size != 0) {
262		sf = talloc(req, union smb_setfileinfo);
263		NT_STATUS_HAVE_NO_MEMORY(sf);
264		sf->generic.level            = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
265		sf->generic.in.file.ntvfs    = io2->generic.out.file.ntvfs;
266		sf->end_of_file_info.in.size = set_size;
267		status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
268		if (NT_STATUS_IS_OK(status)) {
269			io->openx.out.size = io->openx.in.size;
270		}
271	}
272
273	req->async_states->state = state;
274
275	return NT_STATUS_OK;
276}
277
278/*
279  the core of the mapping between openx style parameters and ntcreatex
280  parameters
281*/
282static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
283			       uint16_t open_func, const char *fname,
284			       union smb_open *io2)
285{
286	io2->generic.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
287
288	if (flags & OPENX_FLAGS_REQUEST_OPLOCK) {
289		io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
290	}
291	if (flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
292		io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
293	}
294
295	switch (open_mode & OPENX_MODE_ACCESS_MASK) {
296	case OPENX_MODE_ACCESS_READ:
297	case OPENX_MODE_ACCESS_EXEC:
298		io2->generic.in.access_mask = SEC_RIGHTS_FILE_READ;
299		break;
300	case OPENX_MODE_ACCESS_WRITE:
301		io2->generic.in.access_mask = SEC_RIGHTS_FILE_WRITE;
302		break;
303	case OPENX_MODE_ACCESS_RDWR:
304	case OPENX_MODE_ACCESS_FCB:
305		io2->generic.in.access_mask =
306			SEC_RIGHTS_FILE_READ |
307			SEC_RIGHTS_FILE_WRITE;
308		break;
309	default:
310		return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
311	}
312
313	switch (open_mode & OPENX_MODE_DENY_MASK) {
314	case OPENX_MODE_DENY_READ:
315		io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
316		break;
317	case OPENX_MODE_DENY_WRITE:
318		io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
319		break;
320	case OPENX_MODE_DENY_ALL:
321		io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
322		break;
323	case OPENX_MODE_DENY_NONE:
324		io2->generic.in.share_access =
325			NTCREATEX_SHARE_ACCESS_READ |
326			NTCREATEX_SHARE_ACCESS_WRITE;
327		break;
328	case OPENX_MODE_DENY_DOS:
329		/* DENY_DOS is quite strange - it depends on the filename! */
330		io2->generic.in.create_options |=
331			NTCREATEX_OPTIONS_PRIVATE_DENY_DOS;
332		if (is_exe_filename(fname)) {
333			io2->generic.in.share_access =
334				NTCREATEX_SHARE_ACCESS_READ |
335				NTCREATEX_SHARE_ACCESS_WRITE;
336		} else {
337			if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_READ) {
338				io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
339			} else {
340				io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
341			}
342		}
343		break;
344	case OPENX_MODE_DENY_FCB:
345		io2->generic.in.create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB;
346		io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
347		break;
348	default:
349		return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
350	}
351
352	switch (open_func) {
353	case (OPENX_OPEN_FUNC_OPEN):
354		io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
355		break;
356	case (OPENX_OPEN_FUNC_TRUNC):
357		io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
358		break;
359	case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
360		io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
361		break;
362	case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
363		io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
364		break;
365	case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
366		io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
367		break;
368	default:
369		/* this one is very strange */
370		if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_EXEC) {
371			io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
372			break;
373		}
374		return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
375	}
376
377	return NT_STATUS_OK;
378}
379
380/*
381   NTVFS open generic to any mapper
382*/
383NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
384				 struct ntvfs_request *req,
385				 union smb_open *io)
386{
387	NTSTATUS status;
388	union smb_open *io2;
389
390	io2 = talloc_zero(req, union smb_open);
391	if (io2 == NULL) {
392		return NT_STATUS_NO_MEMORY;
393	}
394
395	status = ntvfs_map_async_setup(ntvfs, req,
396				       io, io2,
397				       (second_stage_t)ntvfs_map_open_finish);
398	if (!NT_STATUS_IS_OK(status)) {
399		return status;
400	}
401
402	io2->generic.level = RAW_OPEN_GENERIC;
403
404	switch (io->generic.level) {
405	case RAW_OPEN_OPENX:
406		status = map_openx_open(io->openx.in.flags,
407					io->openx.in.open_mode,
408					io->openx.in.open_func,
409					io->openx.in.fname,
410					io2);
411		if (!NT_STATUS_IS_OK(status)) {
412			goto done;
413		}
414
415		io2->generic.in.file_attr = io->openx.in.file_attrs;
416		io2->generic.in.fname = io->openx.in.fname;
417
418		status = ntvfs->ops->open(ntvfs, req, io2);
419		break;
420
421
422	case RAW_OPEN_OPEN:
423		status = map_openx_open(0,
424					io->openold.in.open_mode,
425					OPENX_OPEN_FUNC_OPEN,
426					io->openold.in.fname,
427					io2);
428		if (!NT_STATUS_IS_OK(status)) {
429			goto done;
430		}
431
432		io2->generic.in.file_attr = io->openold.in.search_attrs;
433		io2->generic.in.fname = io->openold.in.fname;
434
435		status = ntvfs->ops->open(ntvfs, req, io2);
436		break;
437
438	case RAW_OPEN_T2OPEN:
439		io2->generic.level         = RAW_OPEN_NTTRANS_CREATE;
440
441		if (io->t2open.in.open_func == 0) {
442			status = NT_STATUS_OBJECT_NAME_COLLISION;
443			goto done;
444		}
445
446		status = map_openx_open(io->t2open.in.flags,
447					io->t2open.in.open_mode,
448					io->t2open.in.open_func,
449					io->t2open.in.fname,
450					io2);
451		if (!NT_STATUS_IS_OK(status)) {
452			goto done;
453		}
454
455		io2->generic.in.file_attr        = io->t2open.in.file_attrs;
456		io2->generic.in.fname            = io->t2open.in.fname;
457		io2->generic.in.ea_list          = talloc(io2, struct smb_ea_list);
458		io2->generic.in.ea_list->num_eas = io->t2open.in.num_eas;
459		io2->generic.in.ea_list->eas     = io->t2open.in.eas;
460
461		status = ntvfs->ops->open(ntvfs, req, io2);
462		break;
463
464	case RAW_OPEN_MKNEW:
465		io2->generic.in.file_attr = io->mknew.in.attrib;
466		io2->generic.in.fname = io->mknew.in.fname;
467		io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
468		io2->generic.in.access_mask =
469			SEC_RIGHTS_FILE_READ |
470			SEC_RIGHTS_FILE_WRITE;
471		io2->generic.in.share_access =
472			NTCREATEX_SHARE_ACCESS_READ |
473			NTCREATEX_SHARE_ACCESS_WRITE;
474		status = ntvfs->ops->open(ntvfs, req, io2);
475		break;
476
477	case RAW_OPEN_CREATE:
478		io2->generic.in.file_attr = io->mknew.in.attrib;
479		io2->generic.in.fname = io->mknew.in.fname;
480		io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
481		io2->generic.in.access_mask =
482			SEC_RIGHTS_FILE_READ |
483			SEC_RIGHTS_FILE_WRITE;
484		io2->generic.in.share_access =
485			NTCREATEX_SHARE_ACCESS_READ |
486			NTCREATEX_SHARE_ACCESS_WRITE;
487		status = ntvfs->ops->open(ntvfs, req, io2);
488		break;
489
490	case RAW_OPEN_CTEMP:
491		io2->generic.in.file_attr = io->ctemp.in.attrib;
492		io2->generic.in.fname =
493			talloc_asprintf(io2, "%s\\SRV%s",
494					io->ctemp.in.directory,
495					generate_random_str_list(io2, 5, "0123456789"));
496		io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
497		io2->generic.in.access_mask =
498			SEC_RIGHTS_FILE_READ |
499			SEC_RIGHTS_FILE_WRITE;
500		io2->generic.in.share_access =
501			NTCREATEX_SHARE_ACCESS_READ |
502			NTCREATEX_SHARE_ACCESS_WRITE;
503		status = ntvfs->ops->open(ntvfs, req, io2);
504		break;
505	case RAW_OPEN_SMB2:
506		switch (io->smb2.in.oplock_level) {
507		case SMB2_OPLOCK_LEVEL_BATCH:
508			io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK |
509						NTCREATEX_FLAGS_REQUEST_OPLOCK;
510			break;
511		case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
512			io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_OPLOCK;
513			break;
514		default:
515			io2->generic.in.flags = 0;
516			break;
517		}
518		io2->generic.in.root_fid	= 0;
519		io2->generic.in.access_mask	= io->smb2.in.desired_access;
520		io2->generic.in.alloc_size	= io->smb2.in.alloc_size;
521		io2->generic.in.file_attr	= io->smb2.in.file_attributes;
522		io2->generic.in.share_access	= io->smb2.in.share_access;
523		io2->generic.in.open_disposition= io->smb2.in.create_disposition;
524		io2->generic.in.create_options	= io->smb2.in.create_options;
525		io2->generic.in.impersonation	= io->smb2.in.impersonation_level;
526		io2->generic.in.security_flags	= 0;
527		io2->generic.in.fname		= io->smb2.in.fname;
528		io2->generic.in.sec_desc	= io->smb2.in.sec_desc;
529		io2->generic.in.ea_list		= &io->smb2.in.eas;
530		io2->generic.in.query_maximal_access = io->smb2.in.query_maximal_access;
531
532		/* we don't support timewarp yet */
533		if (io->smb2.in.timewarp != 0) {
534			status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
535			break;
536		}
537
538		/* we need to check these bits before we check the private mask */
539		if (io2->generic.in.create_options & SMB2_CREATE_OPTIONS_NOT_SUPPORTED_MASK) {
540			DEBUG(2,(__location__ " create_options 0x%x not supported\n",
541				 io2->generic.in.create_options));
542			status = NT_STATUS_NOT_SUPPORTED;
543			break;
544		}
545
546		/* TODO: find out why only SMB2 ignores these */
547		io2->generic.in.create_options &= ~NTCREATEX_OPTIONS_SYNC_ALERT;
548		io2->generic.in.create_options &= ~NTCREATEX_OPTIONS_ASYNC_ALERT;
549
550		status = ntvfs->ops->open(ntvfs, req, io2);
551		break;
552
553	default:
554		status = NT_STATUS_INVALID_LEVEL;
555		break;
556	}
557done:
558	return ntvfs_map_async_finish(req, status);
559}
560
561
562/*
563   NTVFS any to fsinfo mapper
564*/
565static NTSTATUS ntvfs_map_fsinfo_finish(struct ntvfs_module_context *ntvfs,
566				      struct ntvfs_request *req,
567				      union smb_fsinfo *fs,
568				      union smb_fsinfo *fs2,
569				      NTSTATUS status)
570{
571	if (!NT_STATUS_IS_OK(status)) {
572		return status;
573	}
574
575	/* and convert it to the required level */
576	switch (fs->generic.level) {
577	case RAW_QFS_GENERIC:
578		return NT_STATUS_INVALID_LEVEL;
579
580	case RAW_QFS_DSKATTR: {
581		/* map from generic to DSKATTR */
582		uint_t bpunit = 64;
583
584		/* we need to scale the sizes to fit */
585		for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
586			if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
587				break;
588			}
589		}
590
591		fs->dskattr.out.blocks_per_unit = bpunit;
592		fs->dskattr.out.block_size = 512;
593		fs->dskattr.out.units_total =
594			(fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
595		fs->dskattr.out.units_free  =
596			(fs2->generic.out.blocks_free  * (double)fs2->generic.out.block_size) / (bpunit * 512);
597
598		/* we must return a maximum of 2G to old DOS systems, or they get very confused */
599		if (bpunit > 64 && req->ctx->protocol <= PROTOCOL_LANMAN2) {
600			fs->dskattr.out.blocks_per_unit = 64;
601			fs->dskattr.out.units_total = 0xFFFF;
602			fs->dskattr.out.units_free = 0xFFFF;
603		}
604		return NT_STATUS_OK;
605	}
606
607	case RAW_QFS_ALLOCATION:
608		fs->allocation.out.fs_id = fs2->generic.out.fs_id;
609		fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
610		fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
611		fs->allocation.out.sectors_per_unit = 1;
612		fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
613		return NT_STATUS_OK;
614
615	case RAW_QFS_VOLUME:
616		fs->volume.out.serial_number = fs2->generic.out.serial_number;
617		fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
618		return NT_STATUS_OK;
619
620	case RAW_QFS_VOLUME_INFO:
621	case RAW_QFS_VOLUME_INFORMATION:
622		fs->volume_info.out.create_time = fs2->generic.out.create_time;
623		fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
624		fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
625		return NT_STATUS_OK;
626
627	case RAW_QFS_SIZE_INFO:
628	case RAW_QFS_SIZE_INFORMATION:
629		fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
630		fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
631		fs->size_info.out.sectors_per_unit = 1;
632		fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
633		return NT_STATUS_OK;
634
635	case RAW_QFS_DEVICE_INFO:
636	case RAW_QFS_DEVICE_INFORMATION:
637		fs->device_info.out.device_type = fs2->generic.out.device_type;
638		fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
639		return NT_STATUS_OK;
640
641	case RAW_QFS_ATTRIBUTE_INFO:
642	case RAW_QFS_ATTRIBUTE_INFORMATION:
643		fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
644		fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
645		fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
646		return NT_STATUS_OK;
647
648	case RAW_QFS_QUOTA_INFORMATION:
649		ZERO_STRUCT(fs->quota_information.out.unknown);
650		fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
651		fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
652		fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
653		return NT_STATUS_OK;
654
655	case RAW_QFS_FULL_SIZE_INFORMATION:
656		fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
657		fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
658		fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
659		fs->full_size_information.out.sectors_per_unit = 1;
660		fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
661		return NT_STATUS_OK;
662
663	case RAW_QFS_OBJECTID_INFORMATION:
664		fs->objectid_information.out.guid = fs2->generic.out.guid;
665		ZERO_STRUCT(fs->objectid_information.out.unknown);
666		return NT_STATUS_OK;
667	}
668
669
670	return NT_STATUS_INVALID_LEVEL;
671}
672
673/*
674   NTVFS fsinfo any to generic mapper
675*/
676NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
677			  struct ntvfs_request *req,
678			  union smb_fsinfo *fs)
679{
680	NTSTATUS status;
681	union smb_fsinfo *fs2;
682
683	fs2 = talloc(req, union smb_fsinfo);
684	if (fs2 == NULL) {
685		return NT_STATUS_NO_MEMORY;
686	}
687
688	if (fs->generic.level == RAW_QFS_GENERIC) {
689		return NT_STATUS_INVALID_LEVEL;
690	}
691
692	status = ntvfs_map_async_setup(ntvfs, req, fs, fs2,
693				       (second_stage_t)ntvfs_map_fsinfo_finish);
694	if (!NT_STATUS_IS_OK(status)) {
695		return status;
696	}
697
698	/* ask the backend for the generic info */
699	fs2->generic.level = RAW_QFS_GENERIC;
700
701	status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
702	return ntvfs_map_async_finish(req, status);
703}
704
705
706/*
707   NTVFS fileinfo generic to any mapper
708*/
709NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
710				     union smb_fileinfo *info,
711				     union smb_fileinfo *info2)
712{
713	int i;
714	/* and convert it to the required level using results in info2 */
715	switch (info->generic.level) {
716		case RAW_FILEINFO_GENERIC:
717		return NT_STATUS_INVALID_LEVEL;
718	case RAW_FILEINFO_GETATTR:
719		info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
720		info->getattr.out.size = info2->generic.out.size;
721		info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
722		return NT_STATUS_OK;
723
724	case RAW_FILEINFO_GETATTRE:
725		info->getattre.out.attrib = info2->generic.out.attrib;
726		info->getattre.out.size = info2->generic.out.size;
727		info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
728		info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
729		info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
730		info->getattre.out.alloc_size = info2->generic.out.alloc_size;
731		return NT_STATUS_OK;
732
733	case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
734		info->network_open_information.out.create_time = info2->generic.out.create_time;
735		info->network_open_information.out.access_time = info2->generic.out.access_time;
736		info->network_open_information.out.write_time =  info2->generic.out.write_time;
737		info->network_open_information.out.change_time = info2->generic.out.change_time;
738		info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
739		info->network_open_information.out.size = info2->generic.out.size;
740		info->network_open_information.out.attrib = info2->generic.out.attrib;
741		return NT_STATUS_OK;
742
743	case RAW_FILEINFO_ALL_INFO:
744	case RAW_FILEINFO_ALL_INFORMATION:
745		info->all_info.out.create_time = info2->generic.out.create_time;
746		info->all_info.out.access_time = info2->generic.out.access_time;
747		info->all_info.out.write_time =  info2->generic.out.write_time;
748		info->all_info.out.change_time = info2->generic.out.change_time;
749		info->all_info.out.attrib = info2->generic.out.attrib;
750		info->all_info.out.alloc_size = info2->generic.out.alloc_size;
751		info->all_info.out.size = info2->generic.out.size;
752		info->all_info.out.nlink = info2->generic.out.nlink;
753		info->all_info.out.delete_pending = info2->generic.out.delete_pending;
754		info->all_info.out.directory = info2->generic.out.directory;
755		info->all_info.out.ea_size = info2->generic.out.ea_size;
756		info->all_info.out.fname.s = info2->generic.out.fname.s;
757		info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
758		return NT_STATUS_OK;
759
760	case RAW_FILEINFO_BASIC_INFO:
761	case RAW_FILEINFO_BASIC_INFORMATION:
762		info->basic_info.out.create_time = info2->generic.out.create_time;
763		info->basic_info.out.access_time = info2->generic.out.access_time;
764		info->basic_info.out.write_time = info2->generic.out.write_time;
765		info->basic_info.out.change_time = info2->generic.out.change_time;
766		info->basic_info.out.attrib = info2->generic.out.attrib;
767		return NT_STATUS_OK;
768
769	case RAW_FILEINFO_STANDARD:
770		info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
771		info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
772		info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
773		info->standard.out.size = info2->generic.out.size;
774		info->standard.out.alloc_size = info2->generic.out.alloc_size;
775		info->standard.out.attrib = info2->generic.out.attrib;
776		return NT_STATUS_OK;
777
778	case RAW_FILEINFO_EA_SIZE:
779		info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
780		info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
781		info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
782		info->ea_size.out.size = info2->generic.out.size;
783		info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
784		info->ea_size.out.attrib = info2->generic.out.attrib;
785		info->ea_size.out.ea_size = info2->generic.out.ea_size;
786		return NT_STATUS_OK;
787
788	case RAW_FILEINFO_STANDARD_INFO:
789	case RAW_FILEINFO_STANDARD_INFORMATION:
790		info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
791		info->standard_info.out.size = info2->generic.out.size;
792		info->standard_info.out.nlink = info2->generic.out.nlink;
793		info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
794		info->standard_info.out.directory = info2->generic.out.directory;
795		return NT_STATUS_OK;
796
797	case RAW_FILEINFO_INTERNAL_INFORMATION:
798		info->internal_information.out.file_id = info2->generic.out.file_id;
799		return NT_STATUS_OK;
800
801	case RAW_FILEINFO_EA_INFO:
802	case RAW_FILEINFO_EA_INFORMATION:
803		info->ea_info.out.ea_size = info2->generic.out.ea_size;
804		return NT_STATUS_OK;
805
806	case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
807		info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
808		info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
809		return NT_STATUS_OK;
810
811	case RAW_FILEINFO_STREAM_INFO:
812	case RAW_FILEINFO_STREAM_INFORMATION:
813		info->stream_info.out.num_streams = info2->generic.out.num_streams;
814		if (info->stream_info.out.num_streams > 0) {
815			info->stream_info.out.streams =
816				talloc_array(mem_ctx,
817					       struct stream_struct,
818					       info->stream_info.out.num_streams);
819			if (!info->stream_info.out.streams) {
820				DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
821					info->stream_info.out.num_streams));
822				return NT_STATUS_NO_MEMORY;
823			}
824			for (i=0; i < info->stream_info.out.num_streams; i++) {
825				info->stream_info.out.streams[i] = info2->generic.out.streams[i];
826				info->stream_info.out.streams[i].stream_name.s =
827					talloc_strdup(info->stream_info.out.streams,
828						      info2->generic.out.streams[i].stream_name.s);
829				if (!info->stream_info.out.streams[i].stream_name.s) {
830					DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
831					return NT_STATUS_NO_MEMORY;
832				}
833			}
834		}
835		return NT_STATUS_OK;
836
837	case RAW_FILEINFO_NAME_INFO:
838	case RAW_FILEINFO_NAME_INFORMATION:
839		info->name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.fname.s);
840		NT_STATUS_HAVE_NO_MEMORY(info->name_info.out.fname.s);
841		info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
842		return NT_STATUS_OK;
843
844	case RAW_FILEINFO_ALT_NAME_INFO:
845	case RAW_FILEINFO_ALT_NAME_INFORMATION:
846		info->alt_name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.alt_fname.s);
847		NT_STATUS_HAVE_NO_MEMORY(info->alt_name_info.out.fname.s);
848		info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
849		return NT_STATUS_OK;
850
851	case RAW_FILEINFO_POSITION_INFORMATION:
852		info->position_information.out.position = info2->generic.out.position;
853		return NT_STATUS_OK;
854
855	case RAW_FILEINFO_ALL_EAS:
856		info->all_eas.out.num_eas = info2->generic.out.num_eas;
857		if (info->all_eas.out.num_eas > 0) {
858			info->all_eas.out.eas = talloc_array(mem_ctx,
859							       struct ea_struct,
860							       info->all_eas.out.num_eas);
861			if (!info->all_eas.out.eas) {
862				DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
863					info->all_eas.out.num_eas));
864				return NT_STATUS_NO_MEMORY;
865			}
866			for (i = 0; i < info->all_eas.out.num_eas; i++) {
867				info->all_eas.out.eas[i] = info2->generic.out.eas[i];
868				info->all_eas.out.eas[i].name.s =
869					talloc_strdup(info->all_eas.out.eas,
870						      info2->generic.out.eas[i].name.s);
871				if (!info->all_eas.out.eas[i].name.s) {
872					DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
873					return NT_STATUS_NO_MEMORY;
874				}
875				info->all_eas.out.eas[i].value.data =
876					(uint8_t *)talloc_memdup(info->all_eas.out.eas,
877						info2->generic.out.eas[i].value.data,
878						info2->generic.out.eas[i].value.length);
879				if (!info->all_eas.out.eas[i].value.data) {
880					DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
881					return NT_STATUS_NO_MEMORY;
882				}
883			}
884		}
885		return NT_STATUS_OK;
886
887	case RAW_FILEINFO_IS_NAME_VALID:
888		return NT_STATUS_OK;
889
890	case RAW_FILEINFO_COMPRESSION_INFO:
891	case RAW_FILEINFO_COMPRESSION_INFORMATION:
892		info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
893		info->compression_info.out.format = info2->generic.out.format;
894		info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
895		info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
896		info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
897		return NT_STATUS_OK;
898
899	case RAW_FILEINFO_ACCESS_INFORMATION:
900		info->access_information.out.access_flags = info2->generic.out.access_flags;
901		return NT_STATUS_OK;
902
903	case RAW_FILEINFO_MODE_INFORMATION:
904		info->mode_information.out.mode = info2->generic.out.mode;
905		return NT_STATUS_OK;
906
907	case RAW_FILEINFO_ALIGNMENT_INFORMATION:
908		info->alignment_information.out.alignment_requirement =
909			info2->generic.out.alignment_requirement;
910		return NT_STATUS_OK;
911#if 0
912	case RAW_FILEINFO_UNIX_BASIC:
913		info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
914		info->unix_basic_info.out.num_bytes = info2->generic.out.size;
915		info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
916		info->unix_basic_info.out.access_time = info2->generic.out.access_time;
917		info->unix_basic_info.out.change_time = info2->generic.out.change_time;
918		info->unix_basic_info.out.uid = info2->generic.out.uid;
919		info->unix_basic_info.out.gid = info2->generic.out.gid;
920		info->unix_basic_info.out.file_type = info2->generic.out.file_type;
921		info->unix_basic_info.out.dev_major = info2->generic.out.device;
922		info->unix_basic_info.out.dev_minor = info2->generic.out.device;
923		info->unix_basic_info.out.unique_id = info2->generic.out.inode;
924		info->unix_basic_info.out.permissions = info2->generic.out.permissions;
925		info->unix_basic_info.out.nlink = info2->generic.out.nlink;
926		return NT_STATUS_OK;
927
928	case RAW_FILEINFO_UNIX_LINK:
929		info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
930		return NT_STATUS_OK;
931#endif
932	}
933
934	return NT_STATUS_INVALID_LEVEL;
935}
936
937/*
938   NTVFS any to fileinfo mapper
939*/
940static NTSTATUS ntvfs_map_qfileinfo_finish(struct ntvfs_module_context *ntvfs,
941				      struct ntvfs_request *req,
942				      union smb_fileinfo *info,
943				      union smb_fileinfo *info2,
944				      NTSTATUS status)
945{
946	if (!NT_STATUS_IS_OK(status)) {
947		return status;
948	}
949
950	return ntvfs_map_fileinfo(req, info, info2);
951}
952
953/*
954   NTVFS fileinfo generic to any mapper
955*/
956NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
957				      struct ntvfs_request *req,
958				      union smb_fileinfo *info)
959{
960	NTSTATUS status;
961	union smb_fileinfo *info2;
962
963	info2 = talloc(req, union smb_fileinfo);
964	if (info2 == NULL) {
965		return NT_STATUS_NO_MEMORY;
966	}
967
968	if (info->generic.level == RAW_FILEINFO_GENERIC) {
969		return NT_STATUS_INVALID_LEVEL;
970	}
971
972	status = ntvfs_map_async_setup(ntvfs, req, info, info2,
973				       (second_stage_t)ntvfs_map_qfileinfo_finish);
974	if (!NT_STATUS_IS_OK(status)) {
975		return status;
976	}
977
978	/* ask the backend for the generic info */
979	info2->generic.level = RAW_FILEINFO_GENERIC;
980	info2->generic.in.file.ntvfs= info->generic.in.file.ntvfs;
981
982	status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
983	return ntvfs_map_async_finish(req, status);
984}
985
986/*
987   NTVFS any to fileinfo mapper
988*/
989static NTSTATUS ntvfs_map_qpathinfo_finish(struct ntvfs_module_context *ntvfs,
990				      struct ntvfs_request *req,
991				      union smb_fileinfo *info,
992				      union smb_fileinfo *info2,
993				      NTSTATUS status)
994{
995	if (!NT_STATUS_IS_OK(status)) {
996		return status;
997	}
998
999	return ntvfs_map_fileinfo(req, info, info2);
1000}
1001
1002/*
1003   NTVFS pathinfo generic to any mapper
1004*/
1005NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
1006				      struct ntvfs_request *req,
1007				      union smb_fileinfo *info)
1008{
1009	NTSTATUS status;
1010	union smb_fileinfo *info2;
1011
1012	info2 = talloc(req, union smb_fileinfo);
1013	if (info2 == NULL) {
1014		return NT_STATUS_NO_MEMORY;
1015	}
1016
1017	if (info->generic.level == RAW_FILEINFO_GENERIC) {
1018		return NT_STATUS_INVALID_LEVEL;
1019	}
1020
1021	status = ntvfs_map_async_setup(ntvfs, req, info, info2,
1022				       (second_stage_t)ntvfs_map_qpathinfo_finish);
1023	if (!NT_STATUS_IS_OK(status)) {
1024		return status;
1025	}
1026
1027	/* ask the backend for the generic info */
1028	info2->generic.level		= RAW_FILEINFO_GENERIC;
1029	info2->generic.in.file.path	= info->generic.in.file.path;
1030
1031	status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
1032	return ntvfs_map_async_finish(req, status);
1033}
1034
1035
1036/*
1037   NTVFS lock generic to any mapper
1038*/
1039NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
1040			struct ntvfs_request *req,
1041			union smb_lock *lck)
1042{
1043	union smb_lock *lck2;
1044	struct smb_lock_entry *locks;
1045
1046	lck2 = talloc(req, union smb_lock);
1047	if (lck2 == NULL) {
1048		return NT_STATUS_NO_MEMORY;
1049	}
1050
1051	locks = talloc_array(lck2, struct smb_lock_entry, 1);
1052	if (locks == NULL) {
1053		return NT_STATUS_NO_MEMORY;
1054	}
1055
1056	switch (lck->generic.level) {
1057	case RAW_LOCK_LOCKX:
1058		return NT_STATUS_INVALID_LEVEL;
1059
1060	case RAW_LOCK_LOCK:
1061		lck2->generic.level = RAW_LOCK_GENERIC;
1062		lck2->generic.in.file.ntvfs= lck->lock.in.file.ntvfs;
1063		lck2->generic.in.mode = 0;
1064		lck2->generic.in.timeout = 0;
1065		lck2->generic.in.ulock_cnt = 0;
1066		lck2->generic.in.lock_cnt = 1;
1067		lck2->generic.in.locks = locks;
1068		locks->pid = req->smbpid;
1069		locks->offset = lck->lock.in.offset;
1070		locks->count = lck->lock.in.count;
1071		break;
1072
1073	case RAW_LOCK_UNLOCK:
1074		lck2->generic.level = RAW_LOCK_GENERIC;
1075		lck2->generic.in.file.ntvfs= lck->unlock.in.file.ntvfs;
1076		lck2->generic.in.mode = 0;
1077		lck2->generic.in.timeout = 0;
1078		lck2->generic.in.ulock_cnt = 1;
1079		lck2->generic.in.lock_cnt = 0;
1080		lck2->generic.in.locks = locks;
1081		locks->pid = req->smbpid;
1082		locks->offset = lck->unlock.in.offset;
1083		locks->count = lck->unlock.in.count;
1084		break;
1085
1086	case RAW_LOCK_SMB2: {
1087		/* this is only approximate! We need to change the
1088		   generic structure to fix this properly */
1089		int i;
1090		bool isunlock;
1091		if (lck->smb2.in.lock_count < 1) {
1092			return NT_STATUS_INVALID_PARAMETER;
1093		}
1094
1095		lck2->generic.level = RAW_LOCK_GENERIC;
1096		lck2->generic.in.file.ntvfs= lck->smb2.in.file.ntvfs;
1097		lck2->generic.in.timeout = UINT32_MAX;
1098		lck2->generic.in.mode = 0;
1099		lck2->generic.in.lock_cnt = 0;
1100		lck2->generic.in.ulock_cnt = 0;
1101		lck2->generic.in.locks = talloc_zero_array(lck2, struct smb_lock_entry,
1102							   lck->smb2.in.lock_count);
1103		if (lck2->generic.in.locks == NULL) {
1104			return NT_STATUS_NO_MEMORY;
1105		}
1106		/* only the first lock gives the UNLOCK bit - see
1107		   MS-SMB2 3.3.5.14 */
1108		if (lck->smb2.in.locks[0].flags & SMB2_LOCK_FLAG_UNLOCK) {
1109			lck2->generic.in.ulock_cnt = lck->smb2.in.lock_count;
1110			isunlock = true;
1111		} else {
1112			lck2->generic.in.lock_cnt = lck->smb2.in.lock_count;
1113			isunlock = false;
1114		}
1115		for (i=0;i<lck->smb2.in.lock_count;i++) {
1116			if (isunlock &&
1117			    (lck->smb2.in.locks[i].flags &
1118			     (SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_EXCLUSIVE))) {
1119				return NT_STATUS_INVALID_PARAMETER;
1120			}
1121			if (!isunlock &&
1122			    (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK)) {
1123				return NT_STATUS_INVALID_PARAMETER;
1124			}
1125			lck2->generic.in.locks[i].pid    = req->smbpid;
1126			lck2->generic.in.locks[i].offset = lck->smb2.in.locks[i].offset;
1127			lck2->generic.in.locks[i].count  = lck->smb2.in.locks[i].length;
1128			if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_EXCLUSIVE)) {
1129				lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK;
1130			}
1131			if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_FAIL_IMMEDIATELY) {
1132				lck2->generic.in.timeout = 0;
1133			}
1134		}
1135		/* initialize output value */
1136		lck->smb2.out.reserved = 0;
1137		break;
1138	}
1139
1140	case RAW_LOCK_SMB2_BREAK:
1141		lck2->generic.level		= RAW_LOCK_GENERIC;
1142		lck2->generic.in.file.ntvfs	= lck->smb2_break.in.file.ntvfs;
1143		lck2->generic.in.mode		= LOCKING_ANDX_OPLOCK_RELEASE |
1144						  ((lck->smb2_break.in.oplock_level << 8) & 0xFF00);
1145		lck2->generic.in.timeout	= 0;
1146		lck2->generic.in.ulock_cnt	= 0;
1147		lck2->generic.in.lock_cnt	= 0;
1148		lck2->generic.in.locks		= NULL;
1149
1150		/* initialize output value */
1151		lck->smb2_break.out.oplock_level= lck->smb2_break.in.oplock_level;
1152		lck->smb2_break.out.reserved	= lck->smb2_break.in.reserved;
1153		lck->smb2_break.out.reserved2	= lck->smb2_break.in.reserved2;
1154		lck->smb2_break.out.file	= lck->smb2_break.in.file;
1155		break;
1156	}
1157
1158	/*
1159	 * we don't need to call ntvfs_map_async_setup() here,
1160	 * as lock() doesn't have any output fields
1161	 */
1162
1163	return ntvfs->ops->lock(ntvfs, req, lck2);
1164}
1165
1166
1167/*
1168   NTVFS write generic to any mapper
1169*/
1170static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
1171				       struct ntvfs_request *req,
1172				       union smb_write *wr,
1173				       union smb_write *wr2,
1174				       NTSTATUS status)
1175{
1176	union smb_lock *lck;
1177	union smb_close *cl;
1178	uint_t state;
1179
1180	if (NT_STATUS_IS_ERR(status)) {
1181		return status;
1182	}
1183
1184	switch (wr->generic.level) {
1185	case RAW_WRITE_WRITE:
1186		wr->write.out.nwritten    = wr2->generic.out.nwritten;
1187		break;
1188
1189	case RAW_WRITE_WRITEUNLOCK:
1190		wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
1191
1192		lck = talloc(wr2, union smb_lock);
1193		if (lck == NULL) {
1194			return NT_STATUS_NO_MEMORY;
1195		}
1196
1197		lck->unlock.level		= RAW_LOCK_UNLOCK;
1198		lck->unlock.in.file.ntvfs	= wr->writeunlock.in.file.ntvfs;
1199		lck->unlock.in.count		= wr->writeunlock.in.count;
1200		lck->unlock.in.offset		= wr->writeunlock.in.offset;
1201
1202		if (lck->unlock.in.count != 0) {
1203			/* do the lock sync for now */
1204			state = req->async_states->state;
1205			req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1206			status = ntvfs->ops->lock(ntvfs, req, lck);
1207			req->async_states->state = state;
1208		}
1209		break;
1210
1211	case RAW_WRITE_WRITECLOSE:
1212		wr->writeclose.out.nwritten    = wr2->generic.out.nwritten;
1213
1214		cl = talloc(wr2, union smb_close);
1215		if (cl == NULL) {
1216			return NT_STATUS_NO_MEMORY;
1217		}
1218
1219		cl->close.level		= RAW_CLOSE_CLOSE;
1220		cl->close.in.file.ntvfs	= wr->writeclose.in.file.ntvfs;
1221		cl->close.in.write_time	= wr->writeclose.in.mtime;
1222
1223		if (wr2->generic.in.count != 0) {
1224			/* do the close sync for now */
1225			state = req->async_states->state;
1226			req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1227			status = ntvfs->ops->close(ntvfs, req, cl);
1228			req->async_states->state = state;
1229		}
1230		break;
1231
1232	case RAW_WRITE_SPLWRITE:
1233		break;
1234
1235	case RAW_WRITE_SMB2:
1236		wr->smb2.out._pad	= 0;
1237		wr->smb2.out.nwritten	= wr2->generic.out.nwritten;
1238		wr->smb2.out.unknown1	= 0;
1239		break;
1240
1241	default:
1242		return NT_STATUS_INVALID_LEVEL;
1243	}
1244
1245	return status;
1246}
1247
1248
1249/*
1250   NTVFS write generic to any mapper
1251*/
1252NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
1253				  struct ntvfs_request *req,
1254				  union smb_write *wr)
1255{
1256	union smb_write *wr2;
1257	NTSTATUS status;
1258
1259	wr2 = talloc(req, union smb_write);
1260	if (wr2 == NULL) {
1261		return NT_STATUS_NO_MEMORY;
1262	}
1263
1264	status = ntvfs_map_async_setup(ntvfs, req, wr, wr2,
1265				       (second_stage_t)ntvfs_map_write_finish);
1266	if (!NT_STATUS_IS_OK(status)) {
1267		return status;
1268	}
1269
1270	wr2->writex.level = RAW_WRITE_GENERIC;
1271
1272	switch (wr->generic.level) {
1273	case RAW_WRITE_WRITEX:
1274		status = NT_STATUS_INVALID_LEVEL;
1275		break;
1276
1277	case RAW_WRITE_WRITE:
1278		wr2->writex.in.file.ntvfs= wr->write.in.file.ntvfs;
1279		wr2->writex.in.offset    = wr->write.in.offset;
1280		wr2->writex.in.wmode     = 0;
1281		wr2->writex.in.remaining = wr->write.in.remaining;
1282		wr2->writex.in.count     = wr->write.in.count;
1283		wr2->writex.in.data      = wr->write.in.data;
1284		status = ntvfs->ops->write(ntvfs, req, wr2);
1285		break;
1286
1287	case RAW_WRITE_WRITEUNLOCK:
1288		wr2->writex.in.file.ntvfs= wr->writeunlock.in.file.ntvfs;
1289		wr2->writex.in.offset    = wr->writeunlock.in.offset;
1290		wr2->writex.in.wmode     = 0;
1291		wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1292		wr2->writex.in.count     = wr->writeunlock.in.count;
1293		wr2->writex.in.data      = wr->writeunlock.in.data;
1294		status = ntvfs->ops->write(ntvfs, req, wr2);
1295		break;
1296
1297	case RAW_WRITE_WRITECLOSE:
1298		wr2->writex.in.file.ntvfs= wr->writeclose.in.file.ntvfs;
1299		wr2->writex.in.offset    = wr->writeclose.in.offset;
1300		wr2->writex.in.wmode     = 0;
1301		wr2->writex.in.remaining = 0;
1302		wr2->writex.in.count     = wr->writeclose.in.count;
1303		wr2->writex.in.data      = wr->writeclose.in.data;
1304		status = ntvfs->ops->write(ntvfs, req, wr2);
1305		break;
1306
1307	case RAW_WRITE_SPLWRITE:
1308		wr2->writex.in.file.ntvfs= wr->splwrite.in.file.ntvfs;
1309		wr2->writex.in.offset    = 0;
1310		wr2->writex.in.wmode     = 0;
1311		wr2->writex.in.remaining = 0;
1312		wr2->writex.in.count     = wr->splwrite.in.count;
1313		wr2->writex.in.data      = wr->splwrite.in.data;
1314		status = ntvfs->ops->write(ntvfs, req, wr2);
1315		break;
1316
1317	case RAW_WRITE_SMB2:
1318		wr2->writex.in.file.ntvfs= wr->smb2.in.file.ntvfs;
1319		wr2->writex.in.offset    = wr->smb2.in.offset;
1320		wr2->writex.in.wmode     = 0;
1321		wr2->writex.in.remaining = 0;
1322		wr2->writex.in.count     = wr->smb2.in.data.length;
1323		wr2->writex.in.data      = wr->smb2.in.data.data;
1324		status = ntvfs->ops->write(ntvfs, req, wr2);
1325	}
1326
1327	return ntvfs_map_async_finish(req, status);
1328}
1329
1330
1331/*
1332   NTVFS read generic to any mapper - finish the out mapping
1333*/
1334static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
1335				      struct ntvfs_request *req,
1336				      union smb_read *rd,
1337				      union smb_read *rd2,
1338				      NTSTATUS status)
1339{
1340	switch (rd->generic.level) {
1341	case RAW_READ_READ:
1342		rd->read.out.nread	= rd2->generic.out.nread;
1343		break;
1344	case RAW_READ_READBRAW:
1345		rd->readbraw.out.nread	= rd2->generic.out.nread;
1346		break;
1347	case RAW_READ_LOCKREAD:
1348		rd->lockread.out.nread	= rd2->generic.out.nread;
1349		break;
1350	case RAW_READ_SMB2:
1351		rd->smb2.out.data.length= rd2->generic.out.nread;
1352		rd->smb2.out.remaining	= 0;
1353		rd->smb2.out.reserved	= 0;
1354		break;
1355	default:
1356		return NT_STATUS_INVALID_LEVEL;
1357	}
1358
1359	return status;
1360}
1361
1362/*
1363   NTVFS read* to readx mapper
1364*/
1365NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
1366				 struct ntvfs_request *req,
1367				 union smb_read *rd)
1368{
1369	union smb_read *rd2;
1370	union smb_lock *lck;
1371	NTSTATUS status;
1372	uint_t state;
1373
1374	rd2 = talloc(req, union smb_read);
1375	if (rd2 == NULL) {
1376		return NT_STATUS_NO_MEMORY;
1377	}
1378
1379	status = ntvfs_map_async_setup(ntvfs, req, rd, rd2,
1380				       (second_stage_t)ntvfs_map_read_finish);
1381	if (!NT_STATUS_IS_OK(status)) {
1382		return status;
1383	}
1384
1385	rd2->readx.level = RAW_READ_READX;
1386	rd2->readx.in.read_for_execute = false;
1387
1388	switch (rd->generic.level) {
1389	case RAW_READ_READX:
1390		status = NT_STATUS_INVALID_LEVEL;
1391		break;
1392
1393	case RAW_READ_READ:
1394		rd2->readx.in.file.ntvfs= rd->read.in.file.ntvfs;
1395		rd2->readx.in.offset    = rd->read.in.offset;
1396		rd2->readx.in.mincnt    = rd->read.in.count;
1397		rd2->readx.in.maxcnt    = rd->read.in.count;
1398		rd2->readx.in.remaining = rd->read.in.remaining;
1399		rd2->readx.out.data     = rd->read.out.data;
1400		status = ntvfs->ops->read(ntvfs, req, rd2);
1401		break;
1402
1403	case RAW_READ_READBRAW:
1404		rd2->readx.in.file.ntvfs= rd->readbraw.in.file.ntvfs;
1405		rd2->readx.in.offset    = rd->readbraw.in.offset;
1406		rd2->readx.in.mincnt    = rd->readbraw.in.mincnt;
1407		rd2->readx.in.maxcnt    = rd->readbraw.in.maxcnt;
1408		rd2->readx.in.remaining = 0;
1409		rd2->readx.out.data     = rd->readbraw.out.data;
1410		status = ntvfs->ops->read(ntvfs, req, rd2);
1411		break;
1412
1413	case RAW_READ_LOCKREAD:
1414		/* do the initial lock sync for now */
1415		state = req->async_states->state;
1416		req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1417
1418		lck = talloc(rd2, union smb_lock);
1419		if (lck == NULL) {
1420			status = NT_STATUS_NO_MEMORY;
1421			goto done;
1422		}
1423		lck->lock.level		= RAW_LOCK_LOCK;
1424		lck->lock.in.file.ntvfs	= rd->lockread.in.file.ntvfs;
1425		lck->lock.in.count	= rd->lockread.in.count;
1426		lck->lock.in.offset	= rd->lockread.in.offset;
1427		status = ntvfs->ops->lock(ntvfs, req, lck);
1428		req->async_states->state = state;
1429
1430		rd2->readx.in.file.ntvfs= rd->lockread.in.file.ntvfs;
1431		rd2->readx.in.offset    = rd->lockread.in.offset;
1432		rd2->readx.in.mincnt    = rd->lockread.in.count;
1433		rd2->readx.in.maxcnt    = rd->lockread.in.count;
1434		rd2->readx.in.remaining = rd->lockread.in.remaining;
1435		rd2->readx.out.data     = rd->lockread.out.data;
1436
1437		if (NT_STATUS_IS_OK(status)) {
1438			status = ntvfs->ops->read(ntvfs, req, rd2);
1439		}
1440		break;
1441
1442	case RAW_READ_SMB2:
1443		rd2->readx.in.file.ntvfs= rd->smb2.in.file.ntvfs;
1444		rd2->readx.in.offset    = rd->smb2.in.offset;
1445		rd2->readx.in.mincnt    = rd->smb2.in.min_count;
1446		rd2->readx.in.maxcnt    = rd->smb2.in.length;
1447		rd2->readx.in.remaining = 0;
1448		rd2->readx.out.data     = rd->smb2.out.data.data;
1449		status = ntvfs->ops->read(ntvfs, req, rd2);
1450		break;
1451	}
1452
1453done:
1454	return ntvfs_map_async_finish(req, status);
1455}
1456
1457
1458/*
1459   NTVFS close generic to any mapper
1460*/
1461static NTSTATUS ntvfs_map_close_finish(struct ntvfs_module_context *ntvfs,
1462					struct ntvfs_request *req,
1463					union smb_close *cl,
1464					union smb_close *cl2,
1465					NTSTATUS status)
1466{
1467	NT_STATUS_NOT_OK_RETURN(status);
1468
1469	switch (cl->generic.level) {
1470	case RAW_CLOSE_SMB2:
1471		cl->smb2.out.flags        = cl2->generic.out.flags;
1472		cl->smb2.out._pad         = 0;
1473		cl->smb2.out.create_time  = cl2->generic.out.create_time;
1474		cl->smb2.out.access_time  = cl2->generic.out.access_time;
1475		cl->smb2.out.write_time   = cl2->generic.out.write_time;
1476		cl->smb2.out.change_time  = cl2->generic.out.change_time;
1477		cl->smb2.out.alloc_size   = cl2->generic.out.alloc_size;
1478		cl->smb2.out.size         = cl2->generic.out.size;
1479		cl->smb2.out.file_attr    = cl2->generic.out.file_attr;
1480		break;
1481	default:
1482		break;
1483	}
1484
1485	return status;
1486}
1487
1488/*
1489   NTVFS close generic to any mapper
1490*/
1491NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
1492				  struct ntvfs_request *req,
1493				  union smb_close *cl)
1494{
1495	union smb_close *cl2;
1496	NTSTATUS status;
1497
1498	cl2 = talloc(req, union smb_close);
1499	if (cl2 == NULL) {
1500		return NT_STATUS_NO_MEMORY;
1501	}
1502
1503	switch (cl->generic.level) {
1504	case RAW_CLOSE_GENERIC:
1505		return NT_STATUS_INVALID_LEVEL;
1506
1507	case RAW_CLOSE_CLOSE:
1508		cl2->generic.level		= RAW_CLOSE_GENERIC;
1509		cl2->generic.in.file		= cl->close.in.file;
1510		cl2->generic.in.write_time	= cl->close.in.write_time;
1511		cl2->generic.in.flags		= 0;
1512		break;
1513
1514	case RAW_CLOSE_SPLCLOSE:
1515		cl2->generic.level		= RAW_CLOSE_GENERIC;
1516		cl2->generic.in.file		= cl->splclose.in.file;
1517		cl2->generic.in.write_time	= 0;
1518		cl2->generic.in.flags		= 0;
1519		break;
1520
1521	case RAW_CLOSE_SMB2:
1522		cl2->generic.level		= RAW_CLOSE_GENERIC;
1523		cl2->generic.in.file		= cl->smb2.in.file;
1524		cl2->generic.in.write_time	= 0;
1525		cl2->generic.in.flags		= cl->smb2.in.flags;
1526		break;
1527	}
1528
1529	status = ntvfs_map_async_setup(ntvfs, req, cl, cl2,
1530				       (second_stage_t)ntvfs_map_close_finish);
1531	NT_STATUS_NOT_OK_RETURN(status);
1532
1533	status = ntvfs->ops->close(ntvfs, req, cl2);
1534
1535	return ntvfs_map_async_finish(req, status);
1536}
1537
1538/*
1539   NTVFS notify generic to any mapper
1540*/
1541static NTSTATUS ntvfs_map_notify_finish(struct ntvfs_module_context *ntvfs,
1542					struct ntvfs_request *req,
1543					union smb_notify *nt,
1544					union smb_notify *nt2,
1545					NTSTATUS status)
1546{
1547	NT_STATUS_NOT_OK_RETURN(status);
1548
1549	switch (nt->nttrans.level) {
1550	case RAW_NOTIFY_SMB2:
1551		if (nt2->nttrans.out.num_changes == 0) {
1552			return STATUS_NOTIFY_ENUM_DIR;
1553		}
1554		nt->smb2.out.num_changes	= nt2->nttrans.out.num_changes;
1555		nt->smb2.out.changes		= talloc_steal(req, nt2->nttrans.out.changes);
1556		break;
1557
1558	default:
1559		return NT_STATUS_INVALID_LEVEL;
1560	}
1561
1562	return status;
1563}
1564
1565
1566/*
1567   NTVFS notify generic to any mapper
1568*/
1569NTSTATUS ntvfs_map_notify(struct ntvfs_module_context *ntvfs,
1570				   struct ntvfs_request *req,
1571				   union smb_notify *nt)
1572{
1573	union smb_notify *nt2;
1574	NTSTATUS status;
1575
1576	nt2 = talloc(req, union smb_notify);
1577	NT_STATUS_HAVE_NO_MEMORY(nt2);
1578
1579	status = ntvfs_map_async_setup(ntvfs, req, nt, nt2,
1580				       (second_stage_t)ntvfs_map_notify_finish);
1581	NT_STATUS_NOT_OK_RETURN(status);
1582
1583	nt2->nttrans.level = RAW_NOTIFY_NTTRANS;
1584
1585	switch (nt->nttrans.level) {
1586	case RAW_NOTIFY_NTTRANS:
1587		status = NT_STATUS_INVALID_LEVEL;
1588		break;
1589
1590	case RAW_NOTIFY_SMB2:
1591		nt2->nttrans.in.file.ntvfs		= nt->smb2.in.file.ntvfs;
1592		nt2->nttrans.in.buffer_size		= nt->smb2.in.buffer_size;
1593		nt2->nttrans.in.completion_filter	= nt->smb2.in.completion_filter;
1594		nt2->nttrans.in.recursive		= nt->smb2.in.recursive;
1595		status = ntvfs->ops->notify(ntvfs, req, nt2);
1596		break;
1597	}
1598
1599	return ntvfs_map_async_finish(req, status);
1600}
1601