default IPC$ NTVFS backend
Copyright (C) Andrew Tridgell 2003
- Copyright (C) Stefan (metze) Metzmacher 2004
+ Copyright (C) Stefan (metze) Metzmacher 2004-2005
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,
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 <http://www.gnu.org/licenses/>.
*/
/*
this implements the IPC$ backend, called by the NTVFS subsystem to
#include "includes.h"
+#include "../lib/util/dlinklist.h"
+#include "ntvfs/ntvfs.h"
+#include "libcli/rap/rap.h"
+#include "ntvfs/ipc/proto.h"
+#include "libcli/raw/ioctl.h"
+#include "param/param.h"
+#include "../lib/tsocket/tsocket.h"
+#include "../libcli/named_pipe_auth/npa_tstream.h"
+#include "auth/auth.h"
+#include "auth/auth_sam_reply.h"
+#include "lib/socket/socket.h"
+#include "../lib/util/tevent_unix.h"
+#include "../lib/util/tevent_coroutine.h"
/* this is the private structure used to keep the state of an open
ipc$ connection. It needs to keep information about all open
pipes */
struct ipc_private {
-
- uint16_t next_fnum;
- uint16_t num_open;
+ struct ntvfs_module_context *ntvfs;
/* a list of open pipes */
struct pipe_state {
struct pipe_state *next, *prev;
- TALLOC_CTX *mem_ctx;
+ struct ipc_private *ipriv;
const char *pipe_name;
- uint16_t fnum;
- struct dcesrv_connection *dce_conn;
- uint16_t ipc_state;
+ struct ntvfs_handle *handle;
+ struct tstream_context *npipe;
+ uint16_t file_type;
+ uint16_t device_state;
+ uint64_t allocation_size;
+ struct tevent_queue *write_queue;
+ struct tevent_queue *read_queue;
} *pipe_list;
-
};
/*
- find the next fnum available on this connection
+ find a open pipe give a file handle
*/
-static uint16_t find_next_fnum(struct ipc_private *ipc)
+static struct pipe_state *pipe_state_find(struct ipc_private *ipriv, struct ntvfs_handle *handle)
{
- struct pipe_state *p;
- uint32_t ret;
-
- if (ipc->num_open == 0xFFFF) {
- return 0;
- }
+ struct pipe_state *s;
+ void *p;
-again:
- ret = ipc->next_fnum++;
+ p = ntvfs_handle_get_backend_data(handle, ipriv->ntvfs);
+ if (!p) return NULL;
- for (p=ipc->pipe_list; p; p=p->next) {
- if (p->fnum == ret) {
- goto again;
- }
- }
+ s = talloc_get_type(p, struct pipe_state);
+ if (!s) return NULL;
- return ret;
+ return s;
}
-
/*
- shutdown a single pipe. Called on a close or disconnect
+ find a open pipe give a wire fnum
*/
-static void pipe_shutdown(struct ipc_private *private, struct pipe_state *p)
+static struct pipe_state *pipe_state_find_key(struct ipc_private *ipriv, struct ntvfs_request *req, const DATA_BLOB *key)
{
- TALLOC_CTX *mem_ctx = private->pipe_list->mem_ctx;
- dcesrv_endpoint_disconnect(private->pipe_list->dce_conn);
- DLIST_REMOVE(private->pipe_list, private->pipe_list);
- talloc_destroy(mem_ctx);
-}
+ struct ntvfs_handle *h;
+ h = ntvfs_handle_search_by_wire_key(ipriv->ntvfs, req, key);
+ if (!h) return NULL;
-/*
- find a open pipe give a file descriptor
-*/
-static struct pipe_state *pipe_state_find(struct ipc_private *private, uint16_t fnum)
-{
- struct pipe_state *p;
-
- for (p=private->pipe_list; p; p=p->next) {
- if (p->fnum == fnum) {
- return p;
- }
- }
-
- return NULL;
+ return pipe_state_find(ipriv, h);
}
/*
connect to a share - always works
*/
-static NTSTATUS ipc_connect(struct smbsrv_request *req, const char *sharename)
+static NTSTATUS ipc_connect(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req, const char *sharename)
{
- struct smbsrv_tcon *tcon = req->tcon;
- struct ipc_private *private;
+ struct ipc_private *ipriv;
+
+ ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "IPC");
+ NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type);
- tcon->fs_type = talloc_strdup(tcon->mem_ctx, "IPC");
- tcon->dev_type = talloc_strdup(tcon->mem_ctx, "IPC");
+ ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "IPC");
+ NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type);
/* prepare the private state for this connection */
- private = talloc(tcon->mem_ctx, sizeof(struct ipc_private));
- if (!private) {
- return NT_STATUS_NO_MEMORY;
- }
- tcon->ntvfs_private = (void *)private;
+ ipriv = talloc(ntvfs, struct ipc_private);
+ NT_STATUS_HAVE_NO_MEMORY(ipriv);
- private->pipe_list = NULL;
- private->next_fnum = 1;
- private->num_open = 0;
+ ntvfs->private_data = ipriv;
+
+ ipriv->ntvfs = ntvfs;
+ ipriv->pipe_list = NULL;
return NT_STATUS_OK;
}
/*
disconnect from a share
*/
-static NTSTATUS ipc_disconnect(struct smbsrv_tcon *tcon)
+static NTSTATUS ipc_disconnect(struct ntvfs_module_context *ntvfs)
{
- struct ipc_private *private = tcon->ntvfs_private;
-
- /* close any pipes that are open. Discard any unread data */
- while (private->pipe_list) {
- pipe_shutdown(private, private->pipe_list);
- }
-
return NT_STATUS_OK;
}
/*
delete a file
*/
-static NTSTATUS ipc_unlink(struct smbsrv_request *req, struct smb_unlink *unl)
+static NTSTATUS ipc_unlink(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req,
+ union smb_unlink *unl)
{
return NT_STATUS_ACCESS_DENIED;
}
-
/*
- ioctl interface - we don't do any
+ check if a directory exists
*/
-static NTSTATUS ipc_ioctl(struct smbsrv_request *req, union smb_ioctl *io)
+static NTSTATUS ipc_chkpath(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req,
+ union smb_chkpath *cp)
{
return NT_STATUS_ACCESS_DENIED;
}
/*
- check if a directory exists
+ return info on a pathname
*/
-static NTSTATUS ipc_chkpath(struct smbsrv_request *req, struct smb_chkpath *cp)
+static NTSTATUS ipc_qpathinfo(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req, union smb_fileinfo *info)
{
- return NT_STATUS_ACCESS_DENIED;
+ switch (info->generic.level) {
+ case RAW_FILEINFO_GENERIC:
+ return NT_STATUS_INVALID_DEVICE_REQUEST;
+ case RAW_FILEINFO_GETATTR:
+ return NT_STATUS_ACCESS_DENIED;
+ default:
+ return ntvfs_map_qpathinfo(ntvfs, req, info);
+ }
}
/*
- return info on a pathname
+ set info on a pathname
*/
-static NTSTATUS ipc_qpathinfo(struct smbsrv_request *req, union smb_fileinfo *info)
+static NTSTATUS ipc_setpathinfo(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req, union smb_setfileinfo *st)
{
return NT_STATUS_ACCESS_DENIED;
}
+
/*
- set info on a pathname
+ destroy a open pipe structure
*/
-static NTSTATUS ipc_setpathinfo(struct smbsrv_request *req, union smb_setfileinfo *st)
+static int ipc_fd_destructor(struct pipe_state *p)
{
- return NT_STATUS_ACCESS_DENIED;
+ DLIST_REMOVE(p->ipriv->pipe_list, p);
+ ntvfs_handle_remove_backend_data(p->handle, p->ipriv->ntvfs);
+ return 0;
}
+struct ipc_open_state {
+ struct ipc_private *ipriv;
+ struct pipe_state *p;
+ struct ntvfs_request *req;
+ union smb_open *oi;
+ struct netr_SamInfo3 *info3;
+};
+static void ipc_open_done(struct tevent_req *subreq);
/*
- open a file backend - used for MSRPC pipes
+ open a file - used for MSRPC pipes
*/
-static NTSTATUS ipc_open_generic(struct smbsrv_request *req, const char *fname,
- struct pipe_state **ps)
+static NTSTATUS ipc_open(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req, union smb_open *oi)
{
- struct pipe_state *p;
- TALLOC_CTX *mem_ctx;
NTSTATUS status;
- struct dcesrv_ep_description ep_description;
- struct auth_session_info *session_info = NULL;
- struct ipc_private *private = req->tcon->ntvfs_private;
+ struct pipe_state *p;
+ struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
+ struct ipc_private);
+ struct smb_iconv_convenience *smb_ic
+ = lp_iconv_convenience(ipriv->ntvfs->ctx->lp_ctx);
+ struct ntvfs_handle *h;
+ struct ipc_open_state *state;
+ struct tevent_req *subreq;
+ const char *fname;
+ const char *directory;
+ struct socket_address *client_sa;
+ struct tsocket_address *client_addr;
+ struct socket_address *server_sa;
+ struct tsocket_address *server_addr;
+ int ret;
- mem_ctx = talloc_init("ipc_open '%s'", fname);
- if (!mem_ctx) {
- return NT_STATUS_NO_MEMORY;
+ switch (oi->generic.level) {
+ case RAW_OPEN_NTCREATEX:
+ fname = oi->ntcreatex.in.fname;
+ break;
+ case RAW_OPEN_OPENX:
+ fname = oi->openx.in.fname;
+ break;
+ case RAW_OPEN_SMB2:
+ fname = oi->smb2.in.fname;
+ break;
+ default:
+ status = NT_STATUS_NOT_SUPPORTED;
+ break;
}
- p = talloc(mem_ctx, sizeof(struct pipe_state));
- if (!p) {
- talloc_destroy(mem_ctx);
- return NT_STATUS_NO_MEMORY;
- }
- p->mem_ctx = mem_ctx;
+ directory = talloc_asprintf(req, "%s/np",
+ lp_ncalrpc_dir(ipriv->ntvfs->ctx->lp_ctx));
+ NT_STATUS_HAVE_NO_MEMORY(directory);
- p->pipe_name = talloc_strdup(mem_ctx, fname);
- if (!p->pipe_name) {
- talloc_destroy(mem_ctx);
- return NT_STATUS_NO_MEMORY;
- }
+ state = talloc(req, struct ipc_open_state);
+ NT_STATUS_HAVE_NO_MEMORY(state);
- p->fnum = find_next_fnum(private);
- if (p->fnum == 0) {
- talloc_destroy(mem_ctx);
- return NT_STATUS_TOO_MANY_OPENED_FILES;
- }
+ status = ntvfs_handle_new(ntvfs, req, &h);
+ NT_STATUS_NOT_OK_RETURN(status);
- while (p->pipe_name[0] == '\\') {
- p->pipe_name++;
- }
- p->ipc_state = 0x5ff;
+ p = talloc(h, struct pipe_state);
+ NT_STATUS_HAVE_NO_MEMORY(p);
- /*
- we're all set, now ask the dcerpc server subsystem to open the
- endpoint. At this stage the pipe isn't bound, so we don't
- know what interface the user actually wants, just that they want
- one of the interfaces attached to this pipe endpoint.
-
- TODO: note that we aren't passing any credentials here. We
- will need to do that once the credentials infrastructure is
- finalised for Samba4
- */
-
- ep_description.type = ENDPOINT_SMB;
- ep_description.info.smb_pipe = p->pipe_name;
-
- /* tell the RPC layer the session_info */
- if (req->user_ctx->vuser) {
- /*
- * TODO: we need to reference count the entire session_info
- */
- session_info = req->user_ctx->vuser->session_info;
- }
-
- status = dcesrv_endpoint_search_connect(&req->smb_ctx->dcesrv,
- &ep_description,
- session_info,
- &p->dce_conn);
- if (!NT_STATUS_IS_OK(status)) {
- talloc_destroy(mem_ctx);
- return status;
- }
+ while (fname[0] == '\\') fname++;
- private->num_open++;
+ p->pipe_name = talloc_asprintf(p, "\\pipe\\%s", fname);
+ NT_STATUS_HAVE_NO_MEMORY(p->pipe_name);
- DLIST_ADD(private->pipe_list, p);
+ p->handle = h;
+ p->ipriv = ipriv;
- *ps = p;
+ p->write_queue = tevent_queue_create(p, "ipc_write_queue");
+ NT_STATUS_HAVE_NO_MEMORY(p->write_queue);
- return NT_STATUS_OK;
-}
+ p->read_queue = tevent_queue_create(p, "ipc_read_queue");
+ NT_STATUS_HAVE_NO_MEMORY(p->read_queue);
-/*
- open a file with ntcreatex - used for MSRPC pipes
-*/
-static NTSTATUS ipc_open_ntcreatex(struct smbsrv_request *req, union smb_open *oi)
-{
- struct pipe_state *p;
- NTSTATUS status;
+ state->ipriv = ipriv;
+ state->p = p;
+ state->req = req;
+ state->oi = oi;
- status = ipc_open_generic(req, oi->ntcreatex.in.fname, &p);
- if (!NT_STATUS_IS_OK(status)) {
+ status = auth_convert_server_info_saminfo3(state,
+ req->session_info->server_info,
+ &state->info3);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ client_sa = ntvfs_get_peer_addr(ntvfs, state);
+ if (!client_sa) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ server_sa = ntvfs_get_my_addr(ntvfs, state);
+ if (!server_sa) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ ret = tsocket_address_inet_from_strings(state, "ip",
+ client_sa->addr,
+ client_sa->port,
+ &client_addr);
+ if (ret == -1) {
+ status = map_nt_error_from_unix(errno);
return status;
}
- ZERO_STRUCT(oi->ntcreatex.out);
- oi->ntcreatex.out.fnum = p->fnum;
- oi->ntcreatex.out.ipc_state = p->ipc_state;
+ ret = tsocket_address_inet_from_strings(state, "ip",
+ server_sa->addr,
+ server_sa->port,
+ &server_addr);
+ if (ret == -1) {
+ status = map_nt_error_from_unix(errno);
+ return status;
+ }
- return status;
+ subreq = tstream_npa_connect_send(p,
+ ipriv->ntvfs->ctx->event_ctx,
+ smb_ic,
+ directory,
+ fname,
+ client_addr,
+ NULL,
+ server_addr,
+ NULL,
+ state->info3,
+ req->session_info->session_key);
+ NT_STATUS_HAVE_NO_MEMORY(subreq);
+ tevent_req_set_callback(subreq, ipc_open_done, state);
+
+ req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
+ return NT_STATUS_OK;
}
-/*
- open a file with openx - used for MSRPC pipes
-*/
-static NTSTATUS ipc_open_openx(struct smbsrv_request *req, union smb_open *oi)
+static void ipc_open_done(struct tevent_req *subreq)
{
- struct pipe_state *p;
+ struct ipc_open_state *state = tevent_req_callback_data(subreq,
+ struct ipc_open_state);
+ struct ipc_private *ipriv = state->ipriv;
+ struct pipe_state *p = state->p;
+ struct ntvfs_request *req = state->req;
+ union smb_open *oi = state->oi;
+ int ret;
+ int sys_errno;
NTSTATUS status;
- const char *fname = oi->openx.in.fname;
- if (strncasecmp(fname, "PIPE\\", 5) != 0) {
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ ret = tstream_npa_connect_recv(subreq, &sys_errno,
+ p, &p->npipe,
+ &p->file_type,
+ &p->device_state,
+ &p->allocation_size);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ status = map_nt_error_from_unix(sys_errno);
+ goto reply;
}
- fname += 4;
+ DLIST_ADD(ipriv->pipe_list, p);
+ talloc_set_destructor(p, ipc_fd_destructor);
- status = ipc_open_generic(req, fname, &p);
+ status = ntvfs_handle_set_backend_data(p->handle, ipriv->ntvfs, p);
if (!NT_STATUS_IS_OK(status)) {
- return status;
+ goto reply;
}
- ZERO_STRUCT(oi->openx.out);
- oi->openx.out.fnum = p->fnum;
- oi->openx.out.ftype = 2;
- oi->openx.out.devstate = p->ipc_state;
-
- return status;
-}
-
-/*
- open a file - used for MSRPC pipes
-*/
-static NTSTATUS ipc_open(struct smbsrv_request *req, union smb_open *oi)
-{
- NTSTATUS status;
-
switch (oi->generic.level) {
case RAW_OPEN_NTCREATEX:
- status = ipc_open_ntcreatex(req, oi);
+ ZERO_STRUCT(oi->ntcreatex.out);
+ oi->ntcreatex.out.file.ntvfs = p->handle;
+ oi->ntcreatex.out.oplock_level = 0;
+ oi->ntcreatex.out.create_action = NTCREATEX_ACTION_EXISTED;
+ oi->ntcreatex.out.create_time = 0;
+ oi->ntcreatex.out.access_time = 0;
+ oi->ntcreatex.out.write_time = 0;
+ oi->ntcreatex.out.change_time = 0;
+ oi->ntcreatex.out.attrib = FILE_ATTRIBUTE_NORMAL;
+ oi->ntcreatex.out.alloc_size = p->allocation_size;
+ oi->ntcreatex.out.size = 0;
+ oi->ntcreatex.out.file_type = p->file_type;
+ oi->ntcreatex.out.ipc_state = p->device_state;
+ oi->ntcreatex.out.is_directory = 0;
break;
case RAW_OPEN_OPENX:
- status = ipc_open_openx(req, oi);
+ ZERO_STRUCT(oi->openx.out);
+ oi->openx.out.file.ntvfs = p->handle;
+ oi->openx.out.attrib = FILE_ATTRIBUTE_NORMAL;
+ oi->openx.out.write_time = 0;
+ oi->openx.out.size = 0;
+ oi->openx.out.access = 0;
+ oi->openx.out.ftype = p->file_type;
+ oi->openx.out.devstate = p->device_state;
+ oi->openx.out.action = 0;
+ oi->openx.out.unique_fid = 0;
+ oi->openx.out.access_mask = 0;
+ oi->openx.out.unknown = 0;
+ break;
+ case RAW_OPEN_SMB2:
+ ZERO_STRUCT(oi->smb2.out);
+ oi->smb2.out.file.ntvfs = p->handle;
+ oi->smb2.out.oplock_level = oi->smb2.in.oplock_level;
+ oi->smb2.out.create_action = NTCREATEX_ACTION_EXISTED;
+ oi->smb2.out.create_time = 0;
+ oi->smb2.out.access_time = 0;
+ oi->smb2.out.write_time = 0;
+ oi->smb2.out.change_time = 0;
+ oi->smb2.out.alloc_size = p->allocation_size;
+ oi->smb2.out.size = 0;
+ oi->smb2.out.file_attr = FILE_ATTRIBUTE_NORMAL;
+ oi->smb2.out.reserved2 = 0;
break;
default:
- status = NT_STATUS_NOT_SUPPORTED;
break;
}
- return status;
+reply:
+ req->async_states->status = status;
+ req->async_states->send_fn(req);
}
/*
create a directory
*/
-static NTSTATUS ipc_mkdir(struct smbsrv_request *req, union smb_mkdir *md)
+static NTSTATUS ipc_mkdir(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req, union smb_mkdir *md)
{
return NT_STATUS_ACCESS_DENIED;
}
/*
remove a directory
*/
-static NTSTATUS ipc_rmdir(struct smbsrv_request *req, struct smb_rmdir *rd)
+static NTSTATUS ipc_rmdir(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req, struct smb_rmdir *rd)
{
return NT_STATUS_ACCESS_DENIED;
}
/*
rename a set of files
*/
-static NTSTATUS ipc_rename(struct smbsrv_request *req, union smb_rename *ren)
+static NTSTATUS ipc_rename(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req, union smb_rename *ren)
{
return NT_STATUS_ACCESS_DENIED;
}
/*
copy a set of files
*/
-static NTSTATUS ipc_copy(struct smbsrv_request *req, struct smb_copy *cp)
+static NTSTATUS ipc_copy(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req, struct smb_copy *cp)
{
return NT_STATUS_ACCESS_DENIED;
}
+struct ipc_readv_next_vector_state {
+ uint8_t *buf;
+ size_t len;
+ off_t ofs;
+ size_t remaining;
+};
+
+static void ipc_readv_next_vector_init(struct ipc_readv_next_vector_state *s,
+ uint8_t *buf, size_t len)
+{
+ ZERO_STRUCTP(s);
+
+ s->buf = buf;
+ s->len = MIN(len, UINT16_MAX);
+ //DEBUG(0,("readv_next_vector_init[%u 0x%04X]\n", s->len, s->len));
+}
+
+static int ipc_readv_next_vector(struct tstream_context *stream,
+ void *private_data,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **_vector,
+ size_t *count)
+{
+ struct ipc_readv_next_vector_state *state =
+ (struct ipc_readv_next_vector_state *)private_data;
+ struct iovec *vector;
+ ssize_t pending;
+ size_t wanted;
+
+ if (state->ofs == state->len) {
+ *_vector = NULL;
+ *count = 0;
+// DEBUG(0,("readv_next_vector done ofs[%u 0x%04X]\n",
+// state->ofs, state->ofs));
+ return 0;
+ }
+
+ pending = tstream_pending_bytes(stream);
+ if (pending == -1) {
+ return -1;
+ }
+
+ if (pending == 0 && state->ofs != 0) {
+ /* return a short read */
+ *_vector = NULL;
+ *count = 0;
+// DEBUG(0,("readv_next_vector short read ofs[%u 0x%04X]\n",
+// state->ofs, state->ofs));
+ return 0;
+ }
+
+ if (pending == 0) {
+ /* we want at least one byte and recheck again */
+ wanted = 1;
+ } else {
+ size_t missing = state->len - state->ofs;
+ if (pending > missing) {
+ /* there's more available */
+ state->remaining = pending - missing;
+ wanted = missing;
+ } else {
+ /* read what we can get and recheck in the next cycle */
+ wanted = pending;
+ }
+ }
+
+ vector = talloc_array(mem_ctx, struct iovec, 1);
+ if (!vector) {
+ return -1;
+ }
+
+ vector[0].iov_base = state->buf + state->ofs;
+ vector[0].iov_len = wanted;
+
+ state->ofs += wanted;
+
+ *_vector = vector;
+ *count = 1;
+ return 0;
+}
+
+struct ipc_read_state {
+ struct ipc_private *ipriv;
+ struct pipe_state *p;
+ struct ntvfs_request *req;
+ union smb_read *rd;
+ struct ipc_readv_next_vector_state next_vector;
+};
+
+static void ipc_read_done(struct tevent_req *subreq);
+
/*
read from a file
*/
-static NTSTATUS ipc_read(struct smbsrv_request *req, union smb_read *rd)
+static NTSTATUS ipc_read(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req, union smb_read *rd)
{
- struct ipc_private *private = req->tcon->ntvfs_private;
- DATA_BLOB data;
- uint16_t fnum;
+ struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
+ struct ipc_private);
struct pipe_state *p;
- NTSTATUS status;
+ struct ipc_read_state *state;
+ struct tevent_req *subreq;
- switch (rd->generic.level) {
- case RAW_READ_READ:
- fnum = rd->read.in.fnum;
- data.length = rd->read.in.count;
- data.data = rd->read.out.data;
- break;
- case RAW_READ_READX:
- fnum = rd->readx.in.fnum;
- data.length = rd->readx.in.maxcnt;
- data.data = rd->readx.out.data;
- break;
- default:
- return NT_STATUS_NOT_SUPPORTED;
+ if (rd->generic.level != RAW_READ_GENERIC) {
+ return ntvfs_map_read(ntvfs, req, rd);
}
- p = pipe_state_find(private, fnum);
+ p = pipe_state_find(ipriv, rd->readx.in.file.ntvfs);
if (!p) {
return NT_STATUS_INVALID_HANDLE;
}
- status = dcesrv_output_blob(p->dce_conn, &data);
- if (NT_STATUS_IS_ERR(status)) {
- return status;
+ state = talloc(req, struct ipc_read_state);
+ NT_STATUS_HAVE_NO_MEMORY(state);
+
+ state->ipriv = ipriv;
+ state->p = p;
+ state->req = req;
+ state->rd = rd;
+
+ /* rd->readx.out.data is already allocated */
+ ipc_readv_next_vector_init(&state->next_vector,
+ rd->readx.out.data,
+ rd->readx.in.maxcnt);
+
+ subreq = tstream_readv_pdu_queue_send(req,
+ ipriv->ntvfs->ctx->event_ctx,
+ p->npipe,
+ p->read_queue,
+ ipc_readv_next_vector,
+ &state->next_vector);
+ NT_STATUS_HAVE_NO_MEMORY(subreq);
+ tevent_req_set_callback(subreq, ipc_read_done, state);
+
+ req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
+ return NT_STATUS_OK;
+}
+
+static void ipc_read_done(struct tevent_req *subreq)
+{
+ struct ipc_read_state *state =
+ tevent_req_callback_data(subreq,
+ struct ipc_read_state);
+ struct ntvfs_request *req = state->req;
+ union smb_read *rd = state->rd;
+ int ret;
+ int sys_errno;
+ NTSTATUS status;
+
+ ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ status = map_nt_error_from_unix(sys_errno);
+ goto reply;
}
- switch (rd->generic.level) {
- case RAW_READ_READ:
- rd->read.out.nread = data.length;
- break;
- case RAW_READ_READX:
- rd->readx.out.remaining = 0;
- rd->readx.out.compaction_mode = 0;
- rd->readx.out.nread = data.length;
- break;
- default:
- return NT_STATUS_NOT_SUPPORTED;
+ status = NT_STATUS_OK;
+ if (state->next_vector.remaining > 0) {
+ status = STATUS_BUFFER_OVERFLOW;
}
- return status;
+ rd->readx.out.remaining = state->next_vector.remaining;
+ rd->readx.out.compaction_mode = 0;
+ rd->readx.out.nread = ret;
+
+reply:
+ req->async_states->status = status;
+ req->async_states->send_fn(req);
+}
+
+struct example_ocor_state {
+ const char *string;
+};
+
+static struct tevent_coroutine_result *example_ocor_body(struct tevent_coroutine *coro,
+ struct tevent_context *ev,
+ void *private_data);
+
+static struct tevent_req *example_ocor_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *string)
+{
+ struct tevent_req *req;
+ struct example_ocor_state *state;
+ struct tevent_coroutine *coro;
+
+ req = tevent_req_create(mem_ctx, &state, struct example_ocor_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->string = string;
+
+ coro = tevent_coroutine_create(req, ev, example_ocor_body);
+ if (tevent_req_nomem(coro, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static struct tevent_coroutine_result *example_ocor_body(struct tevent_coroutine *coro,
+ struct tevent_context *ev,
+ void *private_data)
+{
+ struct example_ocor_state *state = talloc_get_type_abort(private_data,
+ struct example_ocor_state);
+ struct tevent_req *subreq;
+ bool ok;
+
+ DEBUG(0,("%s[%p]: 1. %s\n", __location__, coro, state->string));
+
+ subreq = tevent_wakeup_send(state, ev, timeval_current_ofs(0,500));
+ if (!tevent_coroutine_yield(coro, subreq)) {
+ return tevent_coroutine_return(coro);
+ }
+ ok = tevent_wakeup_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (!ok) {
+ tevent_coroutine_error(coro, ENOTSUP);
+ return tevent_coroutine_return(coro);
+ }
+
+ DEBUG(0,("%s[%p]: 2. %s wakeup[%d]\n", __location__, coro, state->string, ok));
+
+ tevent_coroutine_done(coro);
+ return tevent_coroutine_return(coro);
+}
+
+static int example_ocor_recv(struct tevent_req *req, int *perrno)
+{
+ if (tevent_req_is_unix_error(req, perrno)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+struct example_coro_state {
+ const char *string;
+};
+
+static struct tevent_coroutine_result *example_coro_body(struct tevent_coroutine *coro,
+ struct tevent_context *ev,
+ void *private_data);
+
+static struct tevent_req *example_coro_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *string)
+{
+ struct tevent_req *req;
+ struct example_coro_state *state;
+ struct tevent_coroutine *coro;
+
+ req = tevent_req_create(mem_ctx, &state, struct example_coro_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->string = string;
+
+ coro = tevent_coroutine_create(req, ev, example_coro_body);
+ if (tevent_req_nomem(coro, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ return req;
}
+static struct tevent_coroutine_result *example_coro_body(struct tevent_coroutine *coro,
+ struct tevent_context *ev,
+ void *private_data)
+{
+ struct example_coro_state *state = talloc_get_type_abort(private_data,
+ struct example_coro_state);
+ struct tevent_req *subreq;
+ int ret;
+ int sys_errno;
+
+ DEBUG(0,("%s:%s[%p]: 1. %s\n", __location__, __FUNCTION__, coro, state->string));
+
+ subreq = example_ocor_send(state, ev, state->string);
+ if (!tevent_coroutine_yield(coro, subreq)) {
+ return tevent_coroutine_return(coro);
+ }
+ ret = example_ocor_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ tevent_coroutine_error(coro, sys_errno);
+ return tevent_coroutine_return(coro);
+ }
+
+ DEBUG(0,("%s:%s[%p]: 2. %s example_ocor[%d]\n", __location__, __FUNCTION__, coro, state->string, ret));
+
+ subreq = example_ocor_send(state, ev, state->string);
+ if (!tevent_coroutine_yield(coro, subreq)) {
+ return tevent_coroutine_return(coro);
+ }
+ ret = example_ocor_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ tevent_coroutine_error(coro, sys_errno);
+ return tevent_coroutine_return(coro);
+ }
+
+ DEBUG(0,("%s:%s[%p]: 3. %s example_ocor[%d]\n", __location__, __FUNCTION__, coro, state->string, ret));
+
+ tevent_coroutine_done(coro);
+ return tevent_coroutine_return(coro);
+}
+
+static int example_coro_recv(struct tevent_req *req, int *perrno)
+{
+ if (tevent_req_is_unix_error(req, perrno)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+struct ipc_write_state {
+ struct ipc_private *ipriv;
+ struct pipe_state *p;
+ struct ntvfs_request *req;
+ union smb_write *wr;
+ struct iovec iov;
+};
+
+static void ipc_write_done(struct tevent_req *subreq);
+
+static void ipc_write_coro_done(struct tevent_req *subreq);
+
/*
write to a file
*/
-static NTSTATUS ipc_write(struct smbsrv_request *req, union smb_write *wr)
+static NTSTATUS ipc_write(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req, union smb_write *wr)
{
- struct ipc_private *private = req->tcon->ntvfs_private;
- DATA_BLOB data;
- uint16_t fnum;
+ struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
+ struct ipc_private);
struct pipe_state *p;
- NTSTATUS status;
-
- switch (wr->generic.level) {
- case RAW_WRITE_WRITE:
- fnum = wr->write.in.fnum;
- data.data = wr->write.in.data;
- data.length = wr->write.in.count;
- break;
-
- case RAW_WRITE_WRITEX:
- fnum = wr->writex.in.fnum;
- data.data = wr->writex.in.data;
- data.length = wr->writex.in.count;
- break;
+ struct tevent_req *subreq;
+ struct ipc_write_state *state;
- default:
- return NT_STATUS_NOT_SUPPORTED;
+ if (wr->generic.level != RAW_WRITE_GENERIC) {
+ return ntvfs_map_write(ntvfs, req, wr);
}
- p = pipe_state_find(private, fnum);
+ p = pipe_state_find(ipriv, wr->writex.in.file.ntvfs);
if (!p) {
return NT_STATUS_INVALID_HANDLE;
}
- status = dcesrv_input(p->dce_conn, &data);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
+ state = talloc(req, struct ipc_write_state);
+ NT_STATUS_HAVE_NO_MEMORY(state);
+
+ state->ipriv = ipriv;
+ state->p = p;
+ state->req = req;
+ state->wr = wr;
+ state->iov.iov_base = discard_const_p(void, wr->writex.in.data);
+ state->iov.iov_len = wr->writex.in.count;
+
+ subreq = example_coro_send(state,
+ ipriv->ntvfs->ctx->event_ctx,
+ "write_start");
+ NT_STATUS_HAVE_NO_MEMORY(subreq);
+ tevent_req_set_callback(subreq, ipc_write_coro_done, state);
+
+ req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
+ return NT_STATUS_OK;
+}
+
+static void ipc_write_coro_done(struct tevent_req *subreq)
+{
+ struct ipc_write_state *state =
+ tevent_req_callback_data(subreq,
+ struct ipc_write_state);
+ struct pipe_state *p = state->p;
+ struct ipc_private *ipriv = state->ipriv;
+ struct ntvfs_request *req = state->req;
+ int ret;
+ int sys_errno;
+ NTSTATUS status;
+
+ ret = example_coro_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ status = map_nt_error_from_unix(sys_errno);
+ goto reply;
}
- switch (wr->generic.level) {
- case RAW_WRITE_WRITE:
- wr->write.out.nwritten = data.length;
- break;
- case RAW_WRITE_WRITEX:
- wr->writex.out.nwritten = data.length;
- wr->writex.out.remaining = 0;
- break;
- default:
- return NT_STATUS_NOT_SUPPORTED;
+ subreq = tstream_writev_queue_send(state,
+ ipriv->ntvfs->ctx->event_ctx,
+ p->npipe,
+ p->write_queue,
+ &state->iov, 1);
+ if (!subreq) {
+ status = NT_STATUS_NO_MEMORY;
+ goto reply;
}
+ tevent_req_set_callback(subreq, ipc_write_done, state);
+ return;
- return NT_STATUS_OK;
+reply:
+ req->async_states->status = status;
+ req->async_states->send_fn(req);
+}
+
+static void ipc_write_done(struct tevent_req *subreq)
+{
+ struct ipc_write_state *state =
+ tevent_req_callback_data(subreq,
+ struct ipc_write_state);
+ struct ntvfs_request *req = state->req;
+ union smb_write *wr = state->wr;
+ int ret;
+ int sys_errno;
+ NTSTATUS status;
+
+ ret = tstream_writev_queue_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ status = map_nt_error_from_unix(sys_errno);
+ goto reply;
+ }
+
+ status = NT_STATUS_OK;
+
+ wr->writex.out.nwritten = ret;
+ wr->writex.out.remaining = 0;
+
+reply:
+ req->async_states->status = status;
+ req->async_states->send_fn(req);
}
/*
seek in a file
*/
-static NTSTATUS ipc_seek(struct smbsrv_request *req, struct smb_seek *io)
+static NTSTATUS ipc_seek(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req,
+ union smb_seek *io)
{
return NT_STATUS_ACCESS_DENIED;
}
/*
flush a file
*/
-static NTSTATUS ipc_flush(struct smbsrv_request *req, struct smb_flush *io)
+static NTSTATUS ipc_flush(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req,
+ union smb_flush *io)
{
return NT_STATUS_ACCESS_DENIED;
}
/*
close a file
*/
-static NTSTATUS ipc_close(struct smbsrv_request *req, union smb_close *io)
+static NTSTATUS ipc_close(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req, union smb_close *io)
{
- struct ipc_private *private = req->tcon->ntvfs_private;
+ struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
+ struct ipc_private);
struct pipe_state *p;
if (io->generic.level != RAW_CLOSE_CLOSE) {
- return NT_STATUS_ACCESS_DENIED;
+ return ntvfs_map_close(ntvfs, req, io);
}
- p = pipe_state_find(private, io->close.in.fnum);
+ p = pipe_state_find(ipriv, io->close.in.file.ntvfs);
if (!p) {
return NT_STATUS_INVALID_HANDLE;
}
- pipe_shutdown(private, p);
- private->num_open--;
+ talloc_free(p);
return NT_STATUS_OK;
}
/*
- exit - closing files?
+ exit - closing files
*/
-static NTSTATUS ipc_exit(struct smbsrv_request *req)
+static NTSTATUS ipc_exit(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req)
{
- return NT_STATUS_ACCESS_DENIED;
+ struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
+ struct ipc_private);
+ struct pipe_state *p, *next;
+
+ for (p=ipriv->pipe_list; p; p=next) {
+ next = p->next;
+ if (p->handle->session_info == req->session_info &&
+ p->handle->smbpid == req->smbpid) {
+ talloc_free(p);
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ logoff - closing files open by the user
+*/
+static NTSTATUS ipc_logoff(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req)
+{
+ struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
+ struct ipc_private);
+ struct pipe_state *p, *next;
+
+ for (p=ipriv->pipe_list; p; p=next) {
+ next = p->next;
+ if (p->handle->session_info == req->session_info) {
+ talloc_free(p);
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ setup for an async call
+*/
+static NTSTATUS ipc_async_setup(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req,
+ void *private_data)
+{
+ return NT_STATUS_OK;
+}
+
+/*
+ cancel an async call
+*/
+static NTSTATUS ipc_cancel(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req)
+{
+ return NT_STATUS_UNSUCCESSFUL;
}
/*
lock a byte range
*/
-static NTSTATUS ipc_lock(struct smbsrv_request *req, union smb_lock *lck)
+static NTSTATUS ipc_lock(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req, union smb_lock *lck)
{
return NT_STATUS_ACCESS_DENIED;
}
/*
set info on a open file
*/
-static NTSTATUS ipc_setfileinfo(struct smbsrv_request *req, union smb_setfileinfo *info)
+static NTSTATUS ipc_setfileinfo(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req, union smb_setfileinfo *info)
{
return NT_STATUS_ACCESS_DENIED;
}
/*
query info on a open file
*/
-static NTSTATUS ipc_qfileinfo(struct smbsrv_request *req, union smb_fileinfo *info)
+static NTSTATUS ipc_qfileinfo(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req, union smb_fileinfo *info)
{
+ struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
+ struct ipc_private);
+ struct pipe_state *p = pipe_state_find(ipriv, info->generic.in.file.ntvfs);
+ if (!p) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+ switch (info->generic.level) {
+ case RAW_FILEINFO_GENERIC:
+ {
+ ZERO_STRUCT(info->generic.out);
+ info->generic.out.attrib = FILE_ATTRIBUTE_NORMAL;
+ info->generic.out.fname.s = strrchr(p->pipe_name, '\\');
+ info->generic.out.alloc_size = 4096;
+ info->generic.out.nlink = 1;
+ /* What the heck? Match Win2k3: IPC$ pipes are delete pending */
+ info->generic.out.delete_pending = 1;
+ return NT_STATUS_OK;
+ }
+ case RAW_FILEINFO_ALT_NAME_INFO:
+ case RAW_FILEINFO_ALT_NAME_INFORMATION:
+ case RAW_FILEINFO_STREAM_INFO:
+ case RAW_FILEINFO_STREAM_INFORMATION:
+ case RAW_FILEINFO_COMPRESSION_INFO:
+ case RAW_FILEINFO_COMPRESSION_INFORMATION:
+ case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
+ case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
+ return NT_STATUS_INVALID_PARAMETER;
+ case RAW_FILEINFO_ALL_EAS:
+ return NT_STATUS_ACCESS_DENIED;
+ default:
+ return ntvfs_map_qfileinfo(ntvfs, req, info);
+ }
+
return NT_STATUS_ACCESS_DENIED;
}
/*
return filesystem info
*/
-static NTSTATUS ipc_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs)
+static NTSTATUS ipc_fsinfo(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req, union smb_fsinfo *fs)
{
return NT_STATUS_ACCESS_DENIED;
}
/*
return print queue info
*/
-static NTSTATUS ipc_lpq(struct smbsrv_request *req, union smb_lpq *lpq)
+static NTSTATUS ipc_lpq(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req, union smb_lpq *lpq)
{
return NT_STATUS_ACCESS_DENIED;
}
/*
list files in a directory matching a wildcard pattern
*/
-NTSTATUS ipc_search_first(struct smbsrv_request *req, union smb_search_first *io,
+static NTSTATUS ipc_search_first(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req, union smb_search_first *io,
void *search_private,
- BOOL (*callback)(void *, union smb_search_data *))
+ bool (*callback)(void *, const union smb_search_data *))
{
return NT_STATUS_ACCESS_DENIED;
}
/*
continue listing files in a directory
*/
-NTSTATUS ipc_search_next(struct smbsrv_request *req, union smb_search_next *io,
+static NTSTATUS ipc_search_next(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req, union smb_search_next *io,
void *search_private,
- BOOL (*callback)(void *, union smb_search_data *))
+ bool (*callback)(void *, const union smb_search_data *))
{
return NT_STATUS_ACCESS_DENIED;
}
/*
end listing files in a directory
*/
-NTSTATUS ipc_search_close(struct smbsrv_request *req, union smb_search_close *io)
+static NTSTATUS ipc_search_close(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req, union smb_search_close *io)
{
return NT_STATUS_ACCESS_DENIED;
}
+struct ipc_trans_state {
+ struct ipc_private *ipriv;
+ struct pipe_state *p;
+ struct ntvfs_request *req;
+ struct smb_trans2 *trans;
+ struct iovec writev_iov;
+ struct ipc_readv_next_vector_state next_vector;
+};
+
+static void ipc_trans_writev_done(struct tevent_req *subreq);
+static void ipc_trans_readv_done(struct tevent_req *subreq);
/* SMBtrans - handle a DCERPC command */
-static NTSTATUS ipc_dcerpc_cmd(struct smbsrv_request *req, struct smb_trans2 *trans)
+static NTSTATUS ipc_dcerpc_cmd(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req, struct smb_trans2 *trans)
{
+ struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
+ struct ipc_private);
struct pipe_state *p;
- struct ipc_private *private = req->tcon->ntvfs_private;
- NTSTATUS status;
+ DATA_BLOB fnum_key;
+ uint16_t fnum;
+ struct ipc_trans_state *state;
+ struct tevent_req *subreq;
- /* the fnum is in setup[1] */
- p = pipe_state_find(private, trans->in.setup[1]);
+ /*
+ * the fnum is in setup[1], a 16 bit value
+ * the setup[*] values are already in host byteorder
+ * but ntvfs_handle_search_by_wire_key() expects
+ * network byteorder
+ */
+ SSVAL(&fnum, 0, trans->in.setup[1]);
+ fnum_key = data_blob_const(&fnum, 2);
+
+ p = pipe_state_find_key(ipriv, req, &fnum_key);
if (!p) {
return NT_STATUS_INVALID_HANDLE;
}
- trans->out.data = data_blob_talloc(req->mem_ctx, NULL, trans->in.max_data);
- if (!trans->out.data.data) {
- return NT_STATUS_NO_MEMORY;
+ /* TODO: check if this os the correct logic */
+ if (tevent_queue_length(p->read_queue) > 0) {
+ return NT_STATUS_PIPE_BUSY;
}
- /* pass the data to the dcerpc server. Note that we don't
- expect this to fail, and things like NDR faults are not
- reported at this stage. Those sorts of errors happen in the
- dcesrv_output stage */
- status = dcesrv_input(p->dce_conn, &trans->in.data);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
- /*
- now ask the dcerpc system for some output. This doesn't yet handle
- async calls. Again, we only expect NT_STATUS_OK. If the call fails then
- the error is encoded at the dcerpc level
- */
- status = dcesrv_output_blob(p->dce_conn, &trans->out.data);
- if (NT_STATUS_IS_ERR(status)) {
- return status;
- }
+ state = talloc(req, struct ipc_trans_state);
+ NT_STATUS_HAVE_NO_MEMORY(state);
trans->out.setup_count = 0;
trans->out.setup = NULL;
trans->out.params = data_blob(NULL, 0);
+ trans->out.data = data_blob_talloc(req, NULL, trans->in.max_data);
+ NT_STATUS_HAVE_NO_MEMORY(trans->out.data.data);
+
+ state->ipriv = ipriv;
+ state->p = p;
+ state->req = req;
+ state->trans = trans;
+ state->writev_iov.iov_base = trans->in.data.data;
+ state->writev_iov.iov_len = trans->in.data.length;
+
+ ipc_readv_next_vector_init(&state->next_vector,
+ trans->out.data.data,
+ trans->out.data.length);
+
+ subreq = tstream_writev_queue_send(state,
+ ipriv->ntvfs->ctx->event_ctx,
+ p->npipe,
+ p->write_queue,
+ &state->writev_iov, 1);
+ NT_STATUS_HAVE_NO_MEMORY(subreq);
+ tevent_req_set_callback(subreq, ipc_trans_writev_done, state);
+
+ req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
+ return NT_STATUS_OK;
+}
- return status;
+static void ipc_trans_writev_done(struct tevent_req *subreq)
+{
+ struct ipc_trans_state *state =
+ tevent_req_callback_data(subreq,
+ struct ipc_trans_state);
+ struct ipc_private *ipriv = state->ipriv;
+ struct pipe_state *p = state->p;
+ struct ntvfs_request *req = state->req;
+ int ret;
+ int sys_errno;
+ NTSTATUS status;
+
+ ret = tstream_writev_queue_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == 0) {
+ status = NT_STATUS_PIPE_DISCONNECTED;
+ goto reply;
+ } else if (ret == -1) {
+ status = map_nt_error_from_unix(sys_errno);
+ goto reply;
+ }
+
+ subreq = tstream_readv_pdu_queue_send(state,
+ ipriv->ntvfs->ctx->event_ctx,
+ p->npipe,
+ p->read_queue,
+ ipc_readv_next_vector,
+ &state->next_vector);
+ if (!subreq) {
+ status = NT_STATUS_NO_MEMORY;
+ goto reply;
+ }
+ tevent_req_set_callback(subreq, ipc_trans_readv_done, state);
+ return;
+
+reply:
+ req->async_states->status = status;
+ req->async_states->send_fn(req);
}
+static void ipc_trans_readv_done(struct tevent_req *subreq)
+{
+ struct ipc_trans_state *state =
+ tevent_req_callback_data(subreq,
+ struct ipc_trans_state);
+ struct ntvfs_request *req = state->req;
+ struct smb_trans2 *trans = state->trans;
+ int ret;
+ int sys_errno;
+ NTSTATUS status;
+
+ ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ status = map_nt_error_from_unix(sys_errno);
+ goto reply;
+ }
+
+ status = NT_STATUS_OK;
+ if (state->next_vector.remaining > 0) {
+ status = STATUS_BUFFER_OVERFLOW;
+ }
+
+ trans->out.data.length = ret;
+
+reply:
+ req->async_states->status = status;
+ req->async_states->send_fn(req);
+}
/* SMBtrans - set named pipe state */
-static NTSTATUS ipc_set_nm_pipe_state(struct smbsrv_request *req, struct smb_trans2 *trans)
+static NTSTATUS ipc_set_nm_pipe_state(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req, struct smb_trans2 *trans)
{
+ struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
+ struct ipc_private);
struct pipe_state *p;
- struct ipc_private *private = req->tcon->ntvfs_private;
+ DATA_BLOB fnum_key;
/* the fnum is in setup[1] */
- p = pipe_state_find(private, trans->in.setup[1]);
+ fnum_key = data_blob_const(&trans->in.setup[1], sizeof(trans->in.setup[1]));
+
+ p = pipe_state_find_key(ipriv, req, &fnum_key);
if (!p) {
return NT_STATUS_INVALID_HANDLE;
}
if (trans->in.params.length != 2) {
return NT_STATUS_INVALID_PARAMETER;
}
- p->ipc_state = SVAL(trans->in.params.data, 0);
+ // TODO...
+ p->device_state = SVAL(trans->in.params.data, 0);
trans->out.setup_count = 0;
trans->out.setup = NULL;
/* SMBtrans - used to provide access to SMB pipes */
-static NTSTATUS ipc_trans(struct smbsrv_request *req, struct smb_trans2 *trans)
+static NTSTATUS ipc_trans(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req, struct smb_trans2 *trans)
{
NTSTATUS status;
+ if (strequal(trans->in.trans_name, "\\PIPE\\LANMAN"))
+ return ipc_rap_call(req, ntvfs->ctx->event_ctx, ntvfs->ctx->lp_ctx, trans);
+
if (trans->in.setup_count != 2) {
return NT_STATUS_INVALID_PARAMETER;
}
switch (trans->in.setup[0]) {
case TRANSACT_SETNAMEDPIPEHANDLESTATE:
- status = ipc_set_nm_pipe_state(req, trans);
+ status = ipc_set_nm_pipe_state(ntvfs, req, trans);
break;
case TRANSACT_DCERPCCMD:
- status = ipc_dcerpc_cmd(req, trans);
+ status = ipc_dcerpc_cmd(ntvfs, req, trans);
break;
default:
status = NT_STATUS_INVALID_PARAMETER;
return status;
}
+struct ipc_ioctl_state {
+ struct ipc_private *ipriv;
+ struct pipe_state *p;
+ struct ntvfs_request *req;
+ union smb_ioctl *io;
+ struct iovec writev_iov;
+ struct ipc_readv_next_vector_state next_vector;
+};
+
+static void ipc_ioctl_writev_done(struct tevent_req *subreq);
+static void ipc_ioctl_readv_done(struct tevent_req *subreq);
+
+static NTSTATUS ipc_ioctl_smb2(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req, union smb_ioctl *io)
+{
+ struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
+ struct ipc_private);
+ struct pipe_state *p;
+ struct ipc_ioctl_state *state;
+ struct tevent_req *subreq;
+
+ switch (io->smb2.in.function) {
+ case FSCTL_NAMED_PIPE_READ_WRITE:
+ break;
+
+ default:
+ return NT_STATUS_FS_DRIVER_REQUIRED;
+ }
+
+ p = pipe_state_find(ipriv, io->smb2.in.file.ntvfs);
+ if (!p) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ /* TODO: check if this os the correct logic */
+ if (tevent_queue_length(p->read_queue) > 0) {
+ return NT_STATUS_PIPE_BUSY;
+ }
+
+ state = talloc(req, struct ipc_ioctl_state);
+ NT_STATUS_HAVE_NO_MEMORY(state);
+
+ io->smb2.out._pad = 0;
+ io->smb2.out.function = io->smb2.in.function;
+ io->smb2.out.unknown2 = 0;
+ io->smb2.out.unknown3 = 0;
+ io->smb2.out.in = io->smb2.in.out;
+ io->smb2.out.out = data_blob_talloc(req, NULL, io->smb2.in.max_response_size);
+ NT_STATUS_HAVE_NO_MEMORY(io->smb2.out.out.data);
+
+ state->ipriv = ipriv;
+ state->p = p;
+ state->req = req;
+ state->io = io;
+ state->writev_iov.iov_base = io->smb2.in.out.data;
+ state->writev_iov.iov_len = io->smb2.in.out.length;
+
+ ipc_readv_next_vector_init(&state->next_vector,
+ io->smb2.out.out.data,
+ io->smb2.out.out.length);
+
+ subreq = tstream_writev_queue_send(state,
+ ipriv->ntvfs->ctx->event_ctx,
+ p->npipe,
+ p->write_queue,
+ &state->writev_iov, 1);
+ NT_STATUS_HAVE_NO_MEMORY(subreq);
+ tevent_req_set_callback(subreq, ipc_ioctl_writev_done, state);
+
+ req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
+ return NT_STATUS_OK;
+}
+
+static void ipc_ioctl_writev_done(struct tevent_req *subreq)
+{
+ struct ipc_ioctl_state *state =
+ tevent_req_callback_data(subreq,
+ struct ipc_ioctl_state);
+ struct ipc_private *ipriv = state->ipriv;
+ struct pipe_state *p = state->p;
+ struct ntvfs_request *req = state->req;
+ int ret;
+ int sys_errno;
+ NTSTATUS status;
+
+ ret = tstream_writev_queue_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ status = map_nt_error_from_unix(sys_errno);
+ goto reply;
+ }
+
+ subreq = tstream_readv_pdu_queue_send(state,
+ ipriv->ntvfs->ctx->event_ctx,
+ p->npipe,
+ p->read_queue,
+ ipc_readv_next_vector,
+ &state->next_vector);
+ if (!subreq) {
+ status = NT_STATUS_NO_MEMORY;
+ goto reply;
+ }
+ tevent_req_set_callback(subreq, ipc_ioctl_readv_done, state);
+ return;
+
+reply:
+ req->async_states->status = status;
+ req->async_states->send_fn(req);
+}
+
+static void ipc_ioctl_readv_done(struct tevent_req *subreq)
+{
+ struct ipc_ioctl_state *state =
+ tevent_req_callback_data(subreq,
+ struct ipc_ioctl_state);
+ struct ntvfs_request *req = state->req;
+ union smb_ioctl *io = state->io;
+ int ret;
+ int sys_errno;
+ NTSTATUS status;
+
+ ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ status = map_nt_error_from_unix(sys_errno);
+ goto reply;
+ }
+
+ status = NT_STATUS_OK;
+ if (state->next_vector.remaining > 0) {
+ status = STATUS_BUFFER_OVERFLOW;
+ }
+
+ io->smb2.out.out.length = ret;
+
+reply:
+ req->async_states->status = status;
+ req->async_states->send_fn(req);
+}
+
+
+/*
+ ioctl interface
+*/
+static NTSTATUS ipc_ioctl(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req, union smb_ioctl *io)
+{
+ switch (io->generic.level) {
+ case RAW_IOCTL_SMB2:
+ return ipc_ioctl_smb2(ntvfs, req, io);
+
+ case RAW_IOCTL_SMB2_NO_HANDLE:
+ return NT_STATUS_FS_DRIVER_REQUIRED;
+
+ default:
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return NT_STATUS_ACCESS_DENIED;
+}
/*
{
NTSTATUS ret;
struct ntvfs_ops ops;
+ NTVFS_CURRENT_CRITICAL_SIZES(vers);
ZERO_STRUCT(ops);
ops.search_next = ipc_search_next;
ops.search_close = ipc_search_close;
ops.trans = ipc_trans;
+ ops.logoff = ipc_logoff;
+ ops.async_setup = ipc_async_setup;
+ ops.cancel = ipc_cancel;
/* register ourselves with the NTVFS subsystem. */
- ret = register_backend("ntvfs", &ops);
+ ret = ntvfs_register(&ops, &vers);
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(0,("Failed to register IPC backend!\n"));