📄 ntvfs_generic.c
字号:
/* Unix SMB/CIFS implementation. NTVFS generic level mapping code Copyright (C) Andrew Tridgell 2003-2004 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 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 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, see <http://www.gnu.org/licenses/>.*//* this implements mappings between info levels for NTVFS backend calls the idea is that each of these functions implements one of the NTVFS backend calls in terms of the 'generic' call. All backends that use these functions must supply the generic call, but can if it wants to also implement other levels if the need arises this allows backend writers to only implement one variant of each call unless they need fine grained control of the calls.*/#include "includes.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 ntvfs_module_context *, struct ntvfs_request *, void *, void *, NTSTATUS);/* this structure holds the async state for pending mapped async calls*/struct ntvfs_map_async { struct ntvfs_module_context *ntvfs; void *io, *io2; second_stage_t fn;};/* 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 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(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);}/* prepare for calling a ntvfs backend with async support io is the original call structure 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 ntvfs_module_context *ntvfs, struct ntvfs_request *req, void *io, void *io2, second_stage_t fn){ struct ntvfs_map_async *m; m = talloc(req, struct ntvfs_map_async); if (m == NULL) { return NT_STATUS_NO_MEMORY; } m->ntvfs = ntvfs; m->io = io; m->io2 = io2; m->fn = fn; 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 ntvfs_request *req, NTSTATUS status){ struct ntvfs_map_async *m; /* if the backend has decided to reply in an async fashion then we don't need to do any work here */ if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) { return status; } /* the backend is replying immediately. call the 2nd stage function after popping our local async state */ m = req->async_states->private_data; ntvfs_async_state_pop(req); 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*/bool is_exe_filename(const char *fname){ char *p; p = strrchr(fname, '.'); if (!p) { return false; } p++; if (strcasecmp(p, "EXE") == 0 || strcasecmp(p, "COM") == 0 || strcasecmp(p, "DLL") == 0 || strcasecmp(p, "SYM") == 0) { return true; } return false;}/* NTVFS openx to ntcreatex mapper*/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.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 = io->openold.in.open_mode; break; case RAW_OPEN_OPENX: 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 = 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) { set_size = io->openx.in.size; } break; 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: ZERO_STRUCT(io->smb2.out); io->smb2.out.file.ntvfs = io2->generic.out.file.ntvfs; switch (io2->generic.out.oplock_level) { case BATCH_OPLOCK_RETURN: io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_BATCH; break; case EXCLUSIVE_OPLOCK_RETURN: io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE; break; case LEVEL_II_OPLOCK_RETURN: io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_II; break; default: io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_NONE; break; } io->smb2.out.reserved = 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.maximal_access = io2->generic.out.maximal_access; 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); } 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; } } 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: /* 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;}/* NTVFS open generic to any mapper*/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(req, union smb_open); if (io2 == NULL) { return NT_STATUS_NO_MEMORY; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -