X-Git-Url: http://git.samba.org/samba.git/?p=jelmer%2Fsamba4-debian.git;a=blobdiff_plain;f=source%2Fntvfs%2Fntvfs_generic.c;h=5092e732b42e4abec3d8dcbdd21a0eaa6c713542;hp=274d5caa8798228c27bf09bd4d98c6ba97693b00;hb=21772fa33d772a9df6ff04a0ed1b0d8f4f533295;hpb=730ae0600e6c75a7048f7aaf3995604e8cdbba39 diff --git a/source/ntvfs/ntvfs_generic.c b/source/ntvfs/ntvfs_generic.c index 274d5caa8..5092e732b 100644 --- a/source/ntvfs/ntvfs_generic.c +++ b/source/ntvfs/ntvfs_generic.c @@ -7,7 +7,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -16,8 +16,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + along with this program. If not, see . */ /* this implements mappings between info levels for NTVFS backend calls @@ -32,12 +31,14 @@ */ #include "includes.h" -#include "smb_server/smb_server.h" +#include "ntvfs/ntvfs.h" +#include "libcli/smb2/smb2.h" +#include "libcli/smb2/smb2_calls.h" /* a second stage function converts from the out parameters of the generic call onto the out parameters of the specific call made */ -typedef NTSTATUS (*second_stage_t)(struct smbsrv_request *, - struct ntvfs_module_context *, +typedef NTSTATUS (*second_stage_t)(struct ntvfs_module_context *, + struct ntvfs_request *, void *, void *, NTSTATUS); /* @@ -53,14 +54,14 @@ struct ntvfs_map_async { this is a async wrapper, called from the backend when it has completed a function that it has decided to reply to in an async fashion */ -static void ntvfs_map_async_send(struct smbsrv_request *req) +static void ntvfs_map_async_send(struct ntvfs_request *req) { struct ntvfs_map_async *m = req->async_states->private_data; ntvfs_async_state_pop(req); /* call the _finish function setup in ntvfs_map_async_setup() */ - req->async_states->status = m->fn(req, m->ntvfs, m->io, m->io2, req->async_states->status); + req->async_states->status = m->fn(m->ntvfs, req, m->io, m->io2, req->async_states->status); /* call the send function from the next module up */ req->async_states->send_fn(req); @@ -72,13 +73,13 @@ static void ntvfs_map_async_send(struct smbsrv_request *req) io2 is the new call structure for the mapped call fn is a second stage function for processing the out arguments */ -static NTSTATUS ntvfs_map_async_setup(struct smbsrv_request *req, - struct ntvfs_module_context *ntvfs, +static NTSTATUS ntvfs_map_async_setup(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, void *io, void *io2, second_stage_t fn) { struct ntvfs_map_async *m; - m = talloc_p(req, struct ntvfs_map_async); + m = talloc(req, struct ntvfs_map_async); if (m == NULL) { return NT_STATUS_NO_MEMORY; } @@ -86,14 +87,13 @@ static NTSTATUS ntvfs_map_async_setup(struct smbsrv_request *req, m->io = io; m->io2 = io2; m->fn = fn; - return ntvfs_async_state_push(req, m, ntvfs_map_async_send, ntvfs); + return ntvfs_async_state_push(ntvfs, req, m, ntvfs_map_async_send); } - /* called when first stage processing is complete. */ -static NTSTATUS ntvfs_map_async_finish(struct smbsrv_request *req, NTSTATUS status) +static NTSTATUS ntvfs_map_async_finish(struct ntvfs_request *req, NTSTATUS status) { struct ntvfs_map_async *m; @@ -109,92 +109,250 @@ static NTSTATUS ntvfs_map_async_finish(struct smbsrv_request *req, NTSTATUS stat ntvfs_async_state_pop(req); - return m->fn(req, m->ntvfs, m->io, m->io2, status); + return m->fn(m->ntvfs, req, m->io, m->io2, status); } - /* see if a filename ends in EXE COM DLL or SYM. This is needed for the DENY_DOS mapping for OpenX */ -static BOOL is_exe_file(const char *fname) +bool is_exe_filename(const char *fname) { char *p; p = strrchr(fname, '.'); if (!p) { - return False; + return false; } p++; if (strcasecmp(p, "EXE") == 0 || strcasecmp(p, "COM") == 0 || strcasecmp(p, "DLL") == 0 || strcasecmp(p, "SYM") == 0) { - return True; + return true; } - return False; + return false; } /* NTVFS openx to ntcreatex mapper */ -static NTSTATUS ntvfs_map_open_finish(struct smbsrv_request *req, - struct ntvfs_module_context *ntvfs, +static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, union smb_open *io, union smb_open *io2, NTSTATUS status) { + time_t write_time = 0; + uint32_t set_size = 0; + union smb_setfileinfo *sf; + uint_t state; + if (!NT_STATUS_IS_OK(status)) { return status; } switch (io->generic.level) { case RAW_OPEN_OPEN: - io->openold.out.fnum = io2->generic.out.fnum; + io->openold.out.file.ntvfs = io2->generic.out.file.ntvfs; io->openold.out.attrib = io2->generic.out.attrib; io->openold.out.write_time = nt_time_to_unix(io2->generic.out.write_time); io->openold.out.size = io2->generic.out.size; - io->openold.out.rmode = DOS_OPEN_RDWR; + io->openold.out.rmode = io->openold.in.open_mode; break; case RAW_OPEN_OPENX: - io->openx.out.fnum = io2->generic.out.fnum; + io->openx.out.file.ntvfs = io2->generic.out.file.ntvfs; io->openx.out.attrib = io2->generic.out.attrib; io->openx.out.write_time = nt_time_to_unix(io2->generic.out.write_time); io->openx.out.size = io2->generic.out.size; + io->openx.out.access = (io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK); io->openx.out.ftype = 0; io->openx.out.devstate = 0; io->openx.out.action = io2->generic.out.create_action; io->openx.out.unique_fid = 0; - io->openx.out.access_mask = io2->generic.in.access_mask; + io->openx.out.access_mask = SEC_STD_ALL; io->openx.out.unknown = 0; /* we need to extend the file to the requested size if it was newly created */ - if (io2->generic.out.create_action == NTCREATEX_ACTION_CREATED && - io->openx.in.size != 0) { - union smb_setfileinfo *sf; - uint_t state; + if (io2->generic.out.create_action == NTCREATEX_ACTION_CREATED) { + set_size = io->openx.in.size; + } + break; - /* doing this secondary request async is more - trouble than its worth */ - state = req->async_states->state; - req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC; + case RAW_OPEN_T2OPEN: + io->t2open.out.file.ntvfs = io2->generic.out.file.ntvfs; + io->t2open.out.attrib = io2->generic.out.attrib; + io->t2open.out.write_time = nt_time_to_unix(io2->generic.out.write_time); + io->t2open.out.size = io2->generic.out.size; + io->t2open.out.access = io->t2open.in.open_mode; + io->t2open.out.ftype = 0; + io->t2open.out.devstate = 0; + io->t2open.out.action = io2->generic.out.create_action; + io->t2open.out.file_id = 0; + break; + + case RAW_OPEN_MKNEW: + case RAW_OPEN_CREATE: + io->mknew.out.file.ntvfs= io2->generic.out.file.ntvfs; + write_time = io->mknew.in.write_time; + break; + + case RAW_OPEN_CTEMP: + io->ctemp.out.file.ntvfs= io2->generic.out.file.ntvfs; + io->ctemp.out.name = talloc_strdup(req, io2->generic.in.fname + + strlen(io->ctemp.in.directory) + 1); + NT_STATUS_HAVE_NO_MEMORY(io->ctemp.out.name); + break; + + case RAW_OPEN_SMB2: + io->smb2.out.file.ntvfs = io2->generic.out.file.ntvfs; + io->smb2.out.oplock_level = 0; + io->smb2.out.create_action = io2->generic.out.create_action; + io->smb2.out.create_time = io2->generic.out.create_time; + io->smb2.out.access_time = io2->generic.out.access_time; + io->smb2.out.write_time = io2->generic.out.write_time; + io->smb2.out.change_time = io2->generic.out.change_time; + io->smb2.out.alloc_size = io2->generic.out.alloc_size; + io->smb2.out.size = io2->generic.out.size; + io->smb2.out.file_attr = io2->generic.out.attrib; + io->smb2.out.reserved2 = 0; + io->smb2.out.blob = data_blob(NULL, 0); + break; + + default: + return NT_STATUS_INVALID_LEVEL; + } + + /* doing a secondary request async is more trouble than its + worth */ + state = req->async_states->state; + req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC; + + if (write_time != 0) { + sf = talloc(req, union smb_setfileinfo); + NT_STATUS_HAVE_NO_MEMORY(sf); + sf->generic.level = RAW_SFILEINFO_STANDARD; + sf->generic.in.file.ntvfs = io2->generic.out.file.ntvfs; + sf->standard.in.create_time = 0; + sf->standard.in.write_time = write_time; + sf->standard.in.access_time = 0; + status = ntvfs->ops->setfileinfo(ntvfs, req, sf); + } - sf = talloc_p(req, union smb_setfileinfo); - sf->generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION; - sf->generic.file.fnum = io2->generic.out.fnum; - sf->end_of_file_info.in.size = io->openx.in.size; - status = ntvfs->ops->setfileinfo(ntvfs, req, sf); - if (NT_STATUS_IS_OK(status)) { - io->openx.out.size = io->openx.in.size; + if (set_size != 0) { + sf = talloc(req, union smb_setfileinfo); + NT_STATUS_HAVE_NO_MEMORY(sf); + sf->generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION; + sf->generic.in.file.ntvfs = io2->generic.out.file.ntvfs; + sf->end_of_file_info.in.size = set_size; + status = ntvfs->ops->setfileinfo(ntvfs, req, sf); + if (NT_STATUS_IS_OK(status)) { + io->openx.out.size = io->openx.in.size; + } + } + + req->async_states->state = state; + + return NT_STATUS_OK; +} + +/* + the core of the mapping between openx style parameters and ntcreatex + parameters +*/ +static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode, + uint16_t open_func, const char *fname, + union smb_open *io2) +{ + if (flags & OPENX_FLAGS_REQUEST_OPLOCK) { + io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK; + } + if (flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) { + io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK; + } + + switch (open_mode & OPENX_MODE_ACCESS_MASK) { + case OPENX_MODE_ACCESS_READ: + case OPENX_MODE_ACCESS_EXEC: + io2->generic.in.access_mask = SEC_RIGHTS_FILE_READ; + break; + case OPENX_MODE_ACCESS_WRITE: + io2->generic.in.access_mask = SEC_RIGHTS_FILE_WRITE; + break; + case OPENX_MODE_ACCESS_RDWR: + case OPENX_MODE_ACCESS_FCB: + io2->generic.in.access_mask = + SEC_RIGHTS_FILE_READ | + SEC_RIGHTS_FILE_WRITE; + break; + default: + return NT_STATUS_DOS(ERRDOS, ERRbadaccess); + } + + switch (open_mode & OPENX_MODE_DENY_MASK) { + case OPENX_MODE_DENY_READ: + io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE; + break; + case OPENX_MODE_DENY_WRITE: + io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ; + break; + case OPENX_MODE_DENY_ALL: + io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; + break; + case OPENX_MODE_DENY_NONE: + io2->generic.in.share_access = + NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE; + break; + case OPENX_MODE_DENY_DOS: + /* DENY_DOS is quite strange - it depends on the filename! */ + io2->generic.in.create_options |= + NTCREATEX_OPTIONS_PRIVATE_DENY_DOS; + if (is_exe_filename(fname)) { + io2->generic.in.share_access = + NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE; + } else { + if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_READ) { + io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ; + } else { + io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; } - req->async_states->state = state; } break; + case OPENX_MODE_DENY_FCB: + io2->generic.in.create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB; + io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; + break; + default: + return NT_STATUS_DOS(ERRDOS, ERRbadaccess); + } + switch (open_func) { + case (OPENX_OPEN_FUNC_OPEN): + io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN; + break; + case (OPENX_OPEN_FUNC_TRUNC): + io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE; + break; + case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE): + io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE; + break; + case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE): + io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF; + break; + case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE): + io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF; + break; default: - return NT_STATUS_INVALID_LEVEL; + /* this one is very strange */ + if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_EXEC) { + io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE; + break; + } + return NT_STATUS_DOS(ERRDOS, ERRbadaccess); } return NT_STATUS_OK; @@ -203,18 +361,20 @@ static NTSTATUS ntvfs_map_open_finish(struct smbsrv_request *req, /* NTVFS open generic to any mapper */ -NTSTATUS ntvfs_map_open(struct smbsrv_request *req, union smb_open *io, - struct ntvfs_module_context *ntvfs) +_PUBLIC_ NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, + union smb_open *io) { NTSTATUS status; union smb_open *io2; - io2 = talloc_zero_p(req, union smb_open); + io2 = talloc_zero(req, union smb_open); if (io2 == NULL) { return NT_STATUS_NO_MEMORY; } - status = ntvfs_map_async_setup(req, ntvfs, io, io2, + status = ntvfs_map_async_setup(ntvfs, req, + io, io2, (second_stage_t)ntvfs_map_open_finish); if (!NT_STATUS_IS_OK(status)) { return status; @@ -224,173 +384,126 @@ NTSTATUS ntvfs_map_open(struct smbsrv_request *req, union smb_open *io, switch (io->generic.level) { case RAW_OPEN_OPENX: - if (io->openx.in.flags & OPENX_FLAGS_REQUEST_OPLOCK) { - io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK; - } - if (io->openx.in.flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) { - io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK; - } - - switch (io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK) { - case OPENX_MODE_ACCESS_READ: - io2->generic.in.access_mask = GENERIC_RIGHTS_FILE_READ; - io->openx.out.access = OPENX_MODE_ACCESS_READ; - break; - case OPENX_MODE_ACCESS_WRITE: - io2->generic.in.access_mask = GENERIC_RIGHTS_FILE_WRITE; - io->openx.out.access = OPENX_MODE_ACCESS_WRITE; - break; - case OPENX_MODE_ACCESS_RDWR: - case OPENX_MODE_ACCESS_FCB: - case OPENX_MODE_ACCESS_EXEC: - io2->generic.in.access_mask = GENERIC_RIGHTS_FILE_READ | GENERIC_RIGHTS_FILE_WRITE; - io->openx.out.access = OPENX_MODE_ACCESS_RDWR; - break; - default: - status = NT_STATUS_INVALID_LOCK_SEQUENCE; - goto done; - } - - switch (io->openx.in.open_mode & OPENX_MODE_DENY_MASK) { - case OPENX_MODE_DENY_READ: - io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE; - break; - case OPENX_MODE_DENY_WRITE: - io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ; - break; - case OPENX_MODE_DENY_ALL: - io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; - break; - case OPENX_MODE_DENY_NONE: - io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; - break; - case OPENX_MODE_DENY_DOS: - /* DENY_DOS is quite strange - it depends on the filename! */ - if (is_exe_file(io->openx.in.fname)) { - io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; - } else { - if ((io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK) == - OPENX_MODE_ACCESS_READ) { - io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ; - } else { - io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; - } - } - break; - case OPENX_MODE_DENY_FCB: - io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; - break; - default: - status = NT_STATUS_INVALID_LOCK_SEQUENCE; - goto done; - } - - switch (io->openx.in.open_func) { - case (OPENX_OPEN_FUNC_OPEN): - io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN; - break; - case (OPENX_OPEN_FUNC_TRUNC): - io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE; - break; - case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE): - io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE; - break; - case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE): - io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF; - break; - case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE): - io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF; - break; - default: - /* this one is very strange */ - if ((io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK) == - OPENX_MODE_ACCESS_EXEC) { - io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE; - break; - } - status = NT_STATUS_INVALID_LOCK_SEQUENCE; + status = map_openx_open(io->openx.in.flags, + io->openx.in.open_mode, + io->openx.in.open_func, + io->openx.in.fname, + io2); + if (!NT_STATUS_IS_OK(status)) { goto done; } - io2->generic.in.alloc_size = 0; io2->generic.in.file_attr = io->openx.in.file_attrs; io2->generic.in.fname = io->openx.in.fname; - status = ntvfs->ops->openfile(ntvfs, req, io2); + status = ntvfs->ops->open(ntvfs, req, io2); break; case RAW_OPEN_OPEN: + status = map_openx_open(0, + io->openold.in.open_mode, + OPENX_OPEN_FUNC_OPEN, + io->openold.in.fname, + io2); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + io2->generic.in.file_attr = io->openold.in.search_attrs; io2->generic.in.fname = io->openold.in.fname; - io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN; - switch (io->openold.in.flags & OPEN_FLAGS_MODE_MASK) { - case OPEN_FLAGS_OPEN_READ: - io2->generic.in.access_mask = GENERIC_RIGHTS_FILE_READ; - io->openold.out.rmode = DOS_OPEN_RDONLY; - break; - case OPEN_FLAGS_OPEN_WRITE: - io2->generic.in.access_mask = GENERIC_RIGHTS_FILE_WRITE; - io->openold.out.rmode = DOS_OPEN_WRONLY; - break; - case OPEN_FLAGS_OPEN_RDWR: - case 0xf: /* FCB mode */ - io2->generic.in.access_mask = GENERIC_RIGHTS_FILE_READ | - GENERIC_RIGHTS_FILE_WRITE; - io->openold.out.rmode = DOS_OPEN_RDWR; /* assume we got r/w */ - break; - default: - DEBUG(2,("ntvfs_map_open(OPEN): invalid mode 0x%x\n", - io->openold.in.flags & OPEN_FLAGS_MODE_MASK)); - status = NT_STATUS_INVALID_PARAMETER; + + status = ntvfs->ops->open(ntvfs, req, io2); + break; + + case RAW_OPEN_T2OPEN: + io2->generic.level = RAW_OPEN_NTTRANS_CREATE; + + if (io->t2open.in.open_func == 0) { + status = NT_STATUS_OBJECT_NAME_COLLISION; goto done; } - - switch (io->openold.in.flags & OPEN_FLAGS_DENY_MASK) { - case OPEN_FLAGS_DENY_DOS: - /* DENY_DOS is quite strange - it depends on the filename! */ - if (is_exe_file(io->openold.in.fname)) { - io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; - } else { - if ((io->openold.in.flags & OPEN_FLAGS_MODE_MASK) == - OPEN_FLAGS_OPEN_READ) { - io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ; - } else { - io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; - } - } - break; - case OPEN_FLAGS_DENY_ALL: - io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; - break; - case OPEN_FLAGS_DENY_WRITE: - io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ; - break; - case OPEN_FLAGS_DENY_READ: - io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE; - break; - case OPEN_FLAGS_DENY_NONE: - io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE | - NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_DELETE; - break; - case 0x70: /* FCB mode */ - io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; - break; - default: - DEBUG(2,("ntvfs_map_open(OPEN): invalid DENY 0x%x\n", - io->openold.in.flags & OPEN_FLAGS_DENY_MASK)); - status = NT_STATUS_INVALID_PARAMETER; + + status = map_openx_open(io->t2open.in.flags, + io->t2open.in.open_mode, + io->t2open.in.open_func, + io->t2open.in.fname, + io2); + if (!NT_STATUS_IS_OK(status)) { goto done; } - status = ntvfs->ops->openfile(ntvfs, req, io2); + io2->generic.in.file_attr = io->t2open.in.file_attrs; + io2->generic.in.fname = io->t2open.in.fname; + io2->generic.in.ea_list = talloc(io2, struct smb_ea_list); + io2->generic.in.ea_list->num_eas = io->t2open.in.num_eas; + io2->generic.in.ea_list->eas = io->t2open.in.eas; + + status = ntvfs->ops->open(ntvfs, req, io2); + break; + + case RAW_OPEN_MKNEW: + io2->generic.in.file_attr = io->mknew.in.attrib; + io2->generic.in.fname = io->mknew.in.fname; + io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE; + io2->generic.in.access_mask = + SEC_RIGHTS_FILE_READ | + SEC_RIGHTS_FILE_WRITE; + io2->generic.in.share_access = + NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE; + status = ntvfs->ops->open(ntvfs, req, io2); + break; + + case RAW_OPEN_CREATE: + io2->generic.in.file_attr = io->mknew.in.attrib; + io2->generic.in.fname = io->mknew.in.fname; + io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF; + io2->generic.in.access_mask = + SEC_RIGHTS_FILE_READ | + SEC_RIGHTS_FILE_WRITE; + io2->generic.in.share_access = + NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE; + status = ntvfs->ops->open(ntvfs, req, io2); + break; + + case RAW_OPEN_CTEMP: + io2->generic.in.file_attr = io->ctemp.in.attrib; + io2->generic.in.fname = + talloc_asprintf(io2, "%s\\SRV%s", + io->ctemp.in.directory, + generate_random_str_list(io2, 5, "0123456789")); + io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE; + io2->generic.in.access_mask = + SEC_RIGHTS_FILE_READ | + SEC_RIGHTS_FILE_WRITE; + io2->generic.in.share_access = + NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE; + status = ntvfs->ops->open(ntvfs, req, io2); + break; + case RAW_OPEN_SMB2: + io2->generic.in.flags = 0; + io2->generic.in.root_fid = 0; + io2->generic.in.access_mask = io->smb2.in.desired_access; + io2->generic.in.alloc_size = 0; + io2->generic.in.file_attr = io->smb2.in.file_attributes; + io2->generic.in.share_access = io->smb2.in.share_access; + io2->generic.in.open_disposition= io->smb2.in.create_disposition; + io2->generic.in.create_options = io->smb2.in.create_options; + io2->generic.in.impersonation = io->smb2.in.impersonation_level; + io2->generic.in.security_flags = 0; + io2->generic.in.fname = io->smb2.in.fname; + io2->generic.in.sec_desc = NULL; + io2->generic.in.ea_list = NULL; + status = ntvfs->ops->open(ntvfs, req, io2); break; default: status = NT_STATUS_INVALID_LEVEL; break; } - done: return ntvfs_map_async_finish(req, status); } @@ -399,13 +512,14 @@ done: /* NTVFS fsinfo generic to any mapper */ -NTSTATUS ntvfs_map_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs, - struct ntvfs_module_context *ntvfs) +_PUBLIC_ NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, + union smb_fsinfo *fs) { NTSTATUS status; union smb_fsinfo *fs2; - fs2 = talloc_p(req, union smb_fsinfo); + fs2 = talloc(req, union smb_fsinfo); if (fs2 == NULL) { return NT_STATUS_NO_MEMORY; } @@ -414,8 +528,7 @@ NTSTATUS ntvfs_map_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs, return NT_STATUS_INVALID_LEVEL; } - /* this map function is only used by the simple backend, which - doesn't do async */ + /* only used by the simple backend, which doesn't do async */ req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC; /* ask the backend for the generic info */ @@ -450,7 +563,7 @@ NTSTATUS ntvfs_map_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs, (fs2->generic.out.blocks_free * (double)fs2->generic.out.block_size) / (bpunit * 512); /* we must return a maximum of 2G to old DOS systems, or they get very confused */ - if (bpunit > 64 && req->smb_conn->negotiate.protocol <= PROTOCOL_LANMAN2) { + if (bpunit > 64 && req->ctx->protocol <= PROTOCOL_LANMAN2) { fs->dskattr.out.blocks_per_unit = 64; fs->dskattr.out.units_total = 0xFFFF; fs->dskattr.out.units_free = 0xFFFF; @@ -528,8 +641,9 @@ NTSTATUS ntvfs_map_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs, /* NTVFS fileinfo generic to any mapper */ -NTSTATUS ntvfs_map_fileinfo(struct smbsrv_request *req, union smb_fileinfo *info, - union smb_fileinfo *info2) +_PUBLIC_ NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx, + union smb_fileinfo *info, + union smb_fileinfo *info2) { int i; /* and convert it to the required level using results in info2 */ @@ -633,8 +747,10 @@ NTSTATUS ntvfs_map_fileinfo(struct smbsrv_request *req, union smb_fileinfo *info case RAW_FILEINFO_STREAM_INFORMATION: info->stream_info.out.num_streams = info2->generic.out.num_streams; if (info->stream_info.out.num_streams > 0) { - info->stream_info.out.streams = talloc(req, - info->stream_info.out.num_streams * sizeof(struct stream_struct)); + info->stream_info.out.streams = + talloc_array(mem_ctx, + struct stream_struct, + info->stream_info.out.num_streams); if (!info->stream_info.out.streams) { DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n", info->stream_info.out.num_streams)); @@ -643,7 +759,8 @@ NTSTATUS ntvfs_map_fileinfo(struct smbsrv_request *req, union smb_fileinfo *info for (i=0; i < info->stream_info.out.num_streams; i++) { info->stream_info.out.streams[i] = info2->generic.out.streams[i]; info->stream_info.out.streams[i].stream_name.s = - talloc_strdup(req, info2->generic.out.streams[i].stream_name.s); + talloc_strdup(info->stream_info.out.streams, + info2->generic.out.streams[i].stream_name.s); if (!info->stream_info.out.streams[i].stream_name.s) { DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n")); return NT_STATUS_NO_MEMORY; @@ -654,13 +771,15 @@ NTSTATUS ntvfs_map_fileinfo(struct smbsrv_request *req, union smb_fileinfo *info case RAW_FILEINFO_NAME_INFO: case RAW_FILEINFO_NAME_INFORMATION: - info->name_info.out.fname.s = talloc_strdup(req, info2->generic.out.fname.s); + info->name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.fname.s); + NT_STATUS_HAVE_NO_MEMORY(info->name_info.out.fname.s); info->name_info.out.fname.private_length = info2->generic.out.fname.private_length; return NT_STATUS_OK; case RAW_FILEINFO_ALT_NAME_INFO: case RAW_FILEINFO_ALT_NAME_INFORMATION: - info->alt_name_info.out.fname.s = talloc_strdup(req, info2->generic.out.alt_fname.s); + info->alt_name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.alt_fname.s); + NT_STATUS_HAVE_NO_MEMORY(info->alt_name_info.out.fname.s); info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length; return NT_STATUS_OK; @@ -671,8 +790,9 @@ NTSTATUS ntvfs_map_fileinfo(struct smbsrv_request *req, union smb_fileinfo *info case RAW_FILEINFO_ALL_EAS: info->all_eas.out.num_eas = info2->generic.out.num_eas; if (info->all_eas.out.num_eas > 0) { - info->all_eas.out.eas = talloc(req, - info->all_eas.out.num_eas * sizeof(struct ea_struct)); + info->all_eas.out.eas = talloc_array(mem_ctx, + struct ea_struct, + info->all_eas.out.num_eas); if (!info->all_eas.out.eas) { DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n", info->all_eas.out.num_eas)); @@ -681,13 +801,14 @@ NTSTATUS ntvfs_map_fileinfo(struct smbsrv_request *req, union smb_fileinfo *info for (i = 0; i < info->all_eas.out.num_eas; i++) { info->all_eas.out.eas[i] = info2->generic.out.eas[i]; info->all_eas.out.eas[i].name.s = - talloc_strdup(req, info2->generic.out.eas[i].name.s); + talloc_strdup(info->all_eas.out.eas, + info2->generic.out.eas[i].name.s); if (!info->all_eas.out.eas[i].name.s) { DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n")); return NT_STATUS_NO_MEMORY; } info->all_eas.out.eas[i].value.data = - talloc_memdup(req, + talloc_memdup(info->all_eas.out.eas, info2->generic.out.eas[i].value.data, info2->generic.out.eas[i].value.length); if (!info->all_eas.out.eas[i].value.data) { @@ -751,13 +872,14 @@ NTSTATUS ntvfs_map_fileinfo(struct smbsrv_request *req, union smb_fileinfo *info /* NTVFS fileinfo generic to any mapper */ -NTSTATUS ntvfs_map_qfileinfo(struct smbsrv_request *req, union smb_fileinfo *info, - struct ntvfs_module_context *ntvfs) +_PUBLIC_ NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, + union smb_fileinfo *info) { NTSTATUS status; union smb_fileinfo *info2; - info2 = talloc_p(req, union smb_fileinfo); + info2 = talloc(req, union smb_fileinfo); if (info2 == NULL) { return NT_STATUS_NO_MEMORY; } @@ -768,7 +890,10 @@ NTSTATUS ntvfs_map_qfileinfo(struct smbsrv_request *req, union smb_fileinfo *inf /* ask the backend for the generic info */ info2->generic.level = RAW_FILEINFO_GENERIC; - info2->generic.in.fnum = info->generic.in.fnum; + info2->generic.in.file.ntvfs= info->generic.in.file.ntvfs; + + /* only used by the simple backend, which doesn't do async */ + req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC; status = ntvfs->ops->qfileinfo(ntvfs, req, info2); if (!NT_STATUS_IS_OK(status)) { @@ -780,13 +905,14 @@ NTSTATUS ntvfs_map_qfileinfo(struct smbsrv_request *req, union smb_fileinfo *inf /* NTVFS pathinfo generic to any mapper */ -NTSTATUS ntvfs_map_qpathinfo(struct smbsrv_request *req, union smb_fileinfo *info, - struct ntvfs_module_context *ntvfs) +_PUBLIC_ NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, + union smb_fileinfo *info) { NTSTATUS status; union smb_fileinfo *info2; - info2 = talloc_p(req, union smb_fileinfo); + info2 = talloc(req, union smb_fileinfo); if (info2 == NULL) { return NT_STATUS_NO_MEMORY; } @@ -796,8 +922,8 @@ NTSTATUS ntvfs_map_qpathinfo(struct smbsrv_request *req, union smb_fileinfo *inf } /* ask the backend for the generic info */ - info2->generic.level = RAW_FILEINFO_GENERIC; - info2->generic.in.fname = info->generic.in.fname; + info2->generic.level = RAW_FILEINFO_GENERIC; + info2->generic.in.file.path = info->generic.in.file.path; /* only used by the simple backend, which doesn't do async */ req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC; @@ -813,18 +939,19 @@ NTSTATUS ntvfs_map_qpathinfo(struct smbsrv_request *req, union smb_fileinfo *inf /* NTVFS lock generic to any mapper */ -NTSTATUS ntvfs_map_lock(struct smbsrv_request *req, union smb_lock *lck, - struct ntvfs_module_context *ntvfs) +_PUBLIC_ NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, + union smb_lock *lck) { union smb_lock *lck2; struct smb_lock_entry *locks; - lck2 = talloc_p(req, union smb_lock); + lck2 = talloc(req, union smb_lock); if (lck2 == NULL) { return NT_STATUS_NO_MEMORY; } - locks = talloc_array_p(lck2, struct smb_lock_entry, 1); + locks = talloc_array(lck2, struct smb_lock_entry, 1); if (locks == NULL) { return NT_STATUS_NO_MEMORY; } @@ -834,24 +961,69 @@ NTSTATUS ntvfs_map_lock(struct smbsrv_request *req, union smb_lock *lck, return NT_STATUS_INVALID_LEVEL; case RAW_LOCK_LOCK: + lck2->generic.level = RAW_LOCK_GENERIC; + lck2->generic.in.file.ntvfs= lck->lock.in.file.ntvfs; + lck2->generic.in.mode = 0; + lck2->generic.in.timeout = 0; lck2->generic.in.ulock_cnt = 0; lck2->generic.in.lock_cnt = 1; + lck2->generic.in.locks = locks; + locks->pid = req->smbpid; + locks->offset = lck->lock.in.offset; + locks->count = lck->lock.in.count; break; case RAW_LOCK_UNLOCK: + lck2->generic.level = RAW_LOCK_GENERIC; + lck2->generic.in.file.ntvfs= lck->unlock.in.file.ntvfs; + lck2->generic.in.mode = 0; + lck2->generic.in.timeout = 0; lck2->generic.in.ulock_cnt = 1; lck2->generic.in.lock_cnt = 0; + lck2->generic.in.locks = locks; + locks->pid = req->smbpid; + locks->offset = lck->unlock.in.offset; + locks->count = lck->unlock.in.count; + break; + + case RAW_LOCK_SMB2: + if (lck->smb2.in.unknown1 != 1) { + return NT_STATUS_INVALID_PARAMETER; + } + + lck2->generic.level = RAW_LOCK_GENERIC; + lck2->generic.in.file.ntvfs= lck->smb2.in.file.ntvfs; + if (lck->smb2.in.flags & SMB2_LOCK_FLAG_EXCLUSIV) { + lck2->generic.in.mode = 0; + } else { + lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK; + } + if (lck->smb2.in.flags & SMB2_LOCK_FLAG_NO_PENDING) { + lck2->generic.in.timeout = 0; + } else { + lck2->generic.in.timeout = UINT32_MAX; + } + if (lck->smb2.in.flags & SMB2_LOCK_FLAG_UNLOCK) { + lck2->generic.in.ulock_cnt = 1; + lck2->generic.in.lock_cnt = 0; + } else { + lck2->generic.in.ulock_cnt = 0; + lck2->generic.in.lock_cnt = 1; + } + lck2->generic.in.locks = locks; + locks->pid = 0; + locks->offset = lck->smb2.in.offset; + locks->count = lck->smb2.in.count; + + /* initialize output value */ + lck->smb2.out.unknown1 = 0; break; } - lck2->generic.level = RAW_LOCK_GENERIC; - lck2->generic.in.fnum = lck->lock.in.fnum; - lck2->generic.in.mode = 0; - lck2->generic.in.timeout = 0; - lck2->generic.in.locks = locks; - locks->pid = req->smbpid; - locks->offset = lck->lock.in.offset; - locks->count = lck->lock.in.count; + /* + * we don't need to call ntvfs_map_async_setup() here, + * as lock() doesn't have any output fields + */ return ntvfs->ops->lock(ntvfs, req, lck2); } @@ -860,12 +1032,11 @@ NTSTATUS ntvfs_map_lock(struct smbsrv_request *req, union smb_lock *lck, /* NTVFS write generic to any mapper */ -static NTSTATUS ntvfs_map_write_finish(struct smbsrv_request *req, - struct ntvfs_module_context *ntvfs, +static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, union smb_write *wr, union smb_write *wr2, NTSTATUS status) - { union smb_lock *lck; union smb_close *cl; @@ -883,15 +1054,15 @@ static NTSTATUS ntvfs_map_write_finish(struct smbsrv_request *req, case RAW_WRITE_WRITEUNLOCK: wr->writeunlock.out.nwritten = wr2->generic.out.nwritten; - lck = talloc_p(wr2, union smb_lock); + lck = talloc(wr2, union smb_lock); if (lck == NULL) { return NT_STATUS_NO_MEMORY; } - lck->unlock.level = RAW_LOCK_UNLOCK; - lck->unlock.in.fnum = wr->writeunlock.in.fnum; - lck->unlock.in.count = wr->writeunlock.in.count; - lck->unlock.in.offset = wr->writeunlock.in.offset; + lck->unlock.level = RAW_LOCK_UNLOCK; + lck->unlock.in.file.ntvfs = wr->writeunlock.in.file.ntvfs; + lck->unlock.in.count = wr->writeunlock.in.count; + lck->unlock.in.offset = wr->writeunlock.in.offset; if (lck->unlock.in.count != 0) { /* do the lock sync for now */ @@ -905,14 +1076,14 @@ static NTSTATUS ntvfs_map_write_finish(struct smbsrv_request *req, case RAW_WRITE_WRITECLOSE: wr->writeclose.out.nwritten = wr2->generic.out.nwritten; - cl = talloc_p(wr2, union smb_close); + cl = talloc(wr2, union smb_close); if (cl == NULL) { return NT_STATUS_NO_MEMORY; } - cl->close.level = RAW_CLOSE_CLOSE; - cl->close.in.fnum = wr->writeclose.in.fnum; - cl->close.in.write_time = wr->writeclose.in.mtime; + cl->close.level = RAW_CLOSE_CLOSE; + cl->close.in.file.ntvfs = wr->writeclose.in.file.ntvfs; + cl->close.in.write_time = wr->writeclose.in.mtime; if (wr2->generic.in.count != 0) { /* do the close sync for now */ @@ -925,6 +1096,13 @@ static NTSTATUS ntvfs_map_write_finish(struct smbsrv_request *req, case RAW_WRITE_SPLWRITE: break; + + case RAW_WRITE_SMB2: + wr->smb2.out._pad = 0; + wr->smb2.out.nwritten = wr2->generic.out.nwritten; + wr->smb2.out.unknown1 = 0; + break; + default: return NT_STATUS_INVALID_LEVEL; } @@ -936,18 +1114,19 @@ static NTSTATUS ntvfs_map_write_finish(struct smbsrv_request *req, /* NTVFS write generic to any mapper */ -NTSTATUS ntvfs_map_write(struct smbsrv_request *req, union smb_write *wr, - struct ntvfs_module_context *ntvfs) +_PUBLIC_ NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, + union smb_write *wr) { union smb_write *wr2; NTSTATUS status; - wr2 = talloc_p(req, union smb_write); + wr2 = talloc(req, union smb_write); if (wr2 == NULL) { return NT_STATUS_NO_MEMORY; } - status = ntvfs_map_async_setup(req, ntvfs, wr, wr2, + status = ntvfs_map_async_setup(ntvfs, req, wr, wr2, (second_stage_t)ntvfs_map_write_finish); if (!NT_STATUS_IS_OK(status)) { return status; @@ -961,7 +1140,7 @@ NTSTATUS ntvfs_map_write(struct smbsrv_request *req, union smb_write *wr, break; case RAW_WRITE_WRITE: - wr2->writex.in.fnum = wr->write.in.fnum; + wr2->writex.in.file.ntvfs= wr->write.in.file.ntvfs; wr2->writex.in.offset = wr->write.in.offset; wr2->writex.in.wmode = 0; wr2->writex.in.remaining = wr->write.in.remaining; @@ -971,7 +1150,7 @@ NTSTATUS ntvfs_map_write(struct smbsrv_request *req, union smb_write *wr, break; case RAW_WRITE_WRITEUNLOCK: - wr2->writex.in.fnum = wr->writeunlock.in.fnum; + wr2->writex.in.file.ntvfs= wr->writeunlock.in.file.ntvfs; wr2->writex.in.offset = wr->writeunlock.in.offset; wr2->writex.in.wmode = 0; wr2->writex.in.remaining = wr->writeunlock.in.remaining; @@ -981,7 +1160,7 @@ NTSTATUS ntvfs_map_write(struct smbsrv_request *req, union smb_write *wr, break; case RAW_WRITE_WRITECLOSE: - wr2->writex.in.fnum = wr->writeclose.in.fnum; + wr2->writex.in.file.ntvfs= wr->writeclose.in.file.ntvfs; wr2->writex.in.offset = wr->writeclose.in.offset; wr2->writex.in.wmode = 0; wr2->writex.in.remaining = 0; @@ -991,7 +1170,7 @@ NTSTATUS ntvfs_map_write(struct smbsrv_request *req, union smb_write *wr, break; case RAW_WRITE_SPLWRITE: - wr2->writex.in.fnum = wr->splwrite.in.fnum; + wr2->writex.in.file.ntvfs= wr->splwrite.in.file.ntvfs; wr2->writex.in.offset = 0; wr2->writex.in.wmode = 0; wr2->writex.in.remaining = 0; @@ -999,6 +1178,15 @@ NTSTATUS ntvfs_map_write(struct smbsrv_request *req, union smb_write *wr, wr2->writex.in.data = wr->splwrite.in.data; status = ntvfs->ops->write(ntvfs, req, wr2); break; + + case RAW_WRITE_SMB2: + wr2->writex.in.file.ntvfs= wr->smb2.in.file.ntvfs; + wr2->writex.in.offset = wr->smb2.in.offset; + wr2->writex.in.wmode = 0; + wr2->writex.in.remaining = 0; + wr2->writex.in.count = wr->smb2.in.data.length; + wr2->writex.in.data = wr->smb2.in.data.data; + status = ntvfs->ops->write(ntvfs, req, wr2); } return ntvfs_map_async_finish(req, status); @@ -1008,21 +1196,25 @@ NTSTATUS ntvfs_map_write(struct smbsrv_request *req, union smb_write *wr, /* NTVFS read generic to any mapper - finish the out mapping */ -static NTSTATUS ntvfs_map_read_finish(struct smbsrv_request *req, - struct ntvfs_module_context *ntvfs, +static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, union smb_read *rd, union smb_read *rd2, NTSTATUS status) { switch (rd->generic.level) { case RAW_READ_READ: - rd->read.out.nread = rd2->generic.out.nread; + rd->read.out.nread = rd2->generic.out.nread; break; case RAW_READ_READBRAW: - rd->readbraw.out.nread = rd2->generic.out.nread; + rd->readbraw.out.nread = rd2->generic.out.nread; break; case RAW_READ_LOCKREAD: - rd->lockread.out.nread = rd2->generic.out.nread; + rd->lockread.out.nread = rd2->generic.out.nread; + break; + case RAW_READ_SMB2: + rd->smb2.out.data.length= rd2->generic.out.nread; + rd->smb2.out.unknown1 = 0; break; default: return NT_STATUS_INVALID_LEVEL; @@ -1034,26 +1226,28 @@ static NTSTATUS ntvfs_map_read_finish(struct smbsrv_request *req, /* NTVFS read* to readx mapper */ -NTSTATUS ntvfs_map_read(struct smbsrv_request *req, union smb_read *rd, - struct ntvfs_module_context *ntvfs) +_PUBLIC_ NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, + union smb_read *rd) { union smb_read *rd2; union smb_lock *lck; NTSTATUS status; uint_t state; - rd2 = talloc_p(req, union smb_read); + rd2 = talloc(req, union smb_read); if (rd2 == NULL) { return NT_STATUS_NO_MEMORY; } - status = ntvfs_map_async_setup(req, ntvfs, rd, rd2, + status = ntvfs_map_async_setup(ntvfs, req, rd, rd2, (second_stage_t)ntvfs_map_read_finish); if (!NT_STATUS_IS_OK(status)) { return status; } rd2->readx.level = RAW_READ_READX; + rd2->readx.in.read_for_execute = false; switch (rd->generic.level) { case RAW_READ_READX: @@ -1061,7 +1255,7 @@ NTSTATUS ntvfs_map_read(struct smbsrv_request *req, union smb_read *rd, break; case RAW_READ_READ: - rd2->readx.in.fnum = rd->read.in.fnum; + rd2->readx.in.file.ntvfs= rd->read.in.file.ntvfs; rd2->readx.in.offset = rd->read.in.offset; rd2->readx.in.mincnt = rd->read.in.count; rd2->readx.in.maxcnt = rd->read.in.count; @@ -1071,7 +1265,7 @@ NTSTATUS ntvfs_map_read(struct smbsrv_request *req, union smb_read *rd, break; case RAW_READ_READBRAW: - rd2->readx.in.fnum = rd->readbraw.in.fnum; + rd2->readx.in.file.ntvfs= rd->readbraw.in.file.ntvfs; rd2->readx.in.offset = rd->readbraw.in.offset; rd2->readx.in.mincnt = rd->readbraw.in.mincnt; rd2->readx.in.maxcnt = rd->readbraw.in.maxcnt; @@ -1085,19 +1279,19 @@ NTSTATUS ntvfs_map_read(struct smbsrv_request *req, union smb_read *rd, state = req->async_states->state; req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC; - lck = talloc_p(rd2, union smb_lock); + lck = talloc(rd2, union smb_lock); if (lck == NULL) { status = NT_STATUS_NO_MEMORY; goto done; } - lck->lock.level = RAW_LOCK_LOCK; - lck->lock.in.fnum = rd->lockread.in.fnum; - lck->lock.in.count = rd->lockread.in.count; - lck->lock.in.offset = rd->lockread.in.offset; + lck->lock.level = RAW_LOCK_LOCK; + lck->lock.in.file.ntvfs = rd->lockread.in.file.ntvfs; + lck->lock.in.count = rd->lockread.in.count; + lck->lock.in.offset = rd->lockread.in.offset; status = ntvfs->ops->lock(ntvfs, req, lck); req->async_states->state = state; - rd2->readx.in.fnum = rd->lockread.in.fnum; + rd2->readx.in.file.ntvfs= rd->lockread.in.file.ntvfs; rd2->readx.in.offset = rd->lockread.in.offset; rd2->readx.in.mincnt = rd->lockread.in.count; rd2->readx.in.maxcnt = rd->lockread.in.count; @@ -1108,6 +1302,16 @@ NTSTATUS ntvfs_map_read(struct smbsrv_request *req, union smb_read *rd, status = ntvfs->ops->read(ntvfs, req, rd2); } break; + + case RAW_READ_SMB2: + rd2->readx.in.file.ntvfs= rd->smb2.in.file.ntvfs; + rd2->readx.in.offset = rd->smb2.in.offset; + rd2->readx.in.mincnt = rd->smb2.in.length; + rd2->readx.in.maxcnt = rd->smb2.in.length; + rd2->readx.in.remaining = 0; + rd2->readx.out.data = rd->smb2.out.data.data; + status = ntvfs->ops->read(ntvfs, req, rd2); + break; } done: @@ -1118,12 +1322,13 @@ done: /* NTVFS close generic to any mapper */ -NTSTATUS ntvfs_map_close(struct smbsrv_request *req, union smb_close *cl, - struct ntvfs_module_context *ntvfs) +_PUBLIC_ NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, + union smb_close *cl) { union smb_close *cl2; - cl2 = talloc_p(req, union smb_close); + cl2 = talloc(req, union smb_close); if (cl2 == NULL) { return NT_STATUS_NO_MEMORY; } @@ -1133,10 +1338,88 @@ NTSTATUS ntvfs_map_close(struct smbsrv_request *req, union smb_close *cl, return NT_STATUS_INVALID_LEVEL; case RAW_CLOSE_SPLCLOSE: - cl2->close.level = RAW_CLOSE_CLOSE; - cl2->close.in.fnum = cl->splclose.in.fnum; + cl2->generic.level = RAW_CLOSE_CLOSE; + cl2->generic.in.file.ntvfs = cl->splclose.in.file.ntvfs; + cl2->generic.in.write_time = 0; + break; + + case RAW_CLOSE_SMB2: + cl2->generic.level = RAW_CLOSE_CLOSE; + cl2->generic.in.file.ntvfs = cl->smb2.in.file.ntvfs; + cl2->generic.in.write_time = 0; + /* SMB2 Close has output parameter, but we just zero them */ + ZERO_STRUCT(cl->smb2.out); break; } + /* + * we don't need to call ntvfs_map_async_setup() here, + * as close() doesn't have any output fields + */ + return ntvfs->ops->close(ntvfs, req, cl2); } + +/* + NTVFS notify generic to any mapper +*/ +static NTSTATUS ntvfs_map_notify_finish(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, + union smb_notify *nt, + union smb_notify *nt2, + NTSTATUS status) +{ + NT_STATUS_NOT_OK_RETURN(status); + + switch (nt->nttrans.level) { + case RAW_NOTIFY_SMB2: + if (nt2->nttrans.out.num_changes == 0) { + return STATUS_NOTIFY_ENUM_DIR; + } + nt->smb2.out.num_changes = nt2->nttrans.out.num_changes; + nt->smb2.out.changes = talloc_steal(req, nt2->nttrans.out.changes); + break; + + default: + return NT_STATUS_INVALID_LEVEL; + } + + return status; +} + + +/* + NTVFS notify generic to any mapper +*/ +_PUBLIC_ NTSTATUS ntvfs_map_notify(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, + union smb_notify *nt) +{ + union smb_notify *nt2; + NTSTATUS status; + + nt2 = talloc(req, union smb_notify); + NT_STATUS_HAVE_NO_MEMORY(nt2); + + status = ntvfs_map_async_setup(ntvfs, req, nt, nt2, + (second_stage_t)ntvfs_map_notify_finish); + NT_STATUS_NOT_OK_RETURN(status); + + nt2->nttrans.level = RAW_NOTIFY_NTTRANS; + + switch (nt->nttrans.level) { + case RAW_NOTIFY_NTTRANS: + status = NT_STATUS_INVALID_LEVEL; + break; + + case RAW_NOTIFY_SMB2: + nt2->nttrans.in.file.ntvfs = nt->smb2.in.file.ntvfs; + nt2->nttrans.in.buffer_size = nt->smb2.in.buffer_size; + nt2->nttrans.in.completion_filter = nt->smb2.in.completion_filter; + nt2->nttrans.in.recursive = nt->smb2.in.recursive; + status = ntvfs->ops->notify(ntvfs, req, nt2); + break; + } + + return ntvfs_map_async_finish(req, status); +}