summaryrefslogtreecommitdiff
path: root/source4/ntvfs/ipc/vfs_ipc.c
diff options
context:
space:
mode:
Diffstat (limited to 'source4/ntvfs/ipc/vfs_ipc.c')
-rw-r--r--source4/ntvfs/ipc/vfs_ipc.c182
1 files changed, 179 insertions, 3 deletions
diff --git a/source4/ntvfs/ipc/vfs_ipc.c b/source4/ntvfs/ipc/vfs_ipc.c
index 7ada031bd5..7ad02bb8cb 100644
--- a/source4/ntvfs/ipc/vfs_ipc.c
+++ b/source4/ntvfs/ipc/vfs_ipc.c
@@ -25,16 +25,102 @@
#include "includes.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 next_fnum;
+ uint16 num_open;
+
+ /* a list of open pipes */
+ struct pipe_state {
+ struct pipe_state *next, *prev;
+ TALLOC_CTX *mem_ctx;
+ const char *pipe_name;
+ uint16 fnum;
+ struct dcesrv_state *pipe_state;
+ } *pipe_list;
+
+};
+
+
+/*
+ find the next fnum available on this connection
+*/
+static uint16 find_next_fnum(struct ipc_private *ipc)
+{
+ struct pipe_state *p;
+ uint32 ret;
+
+ if (ipc->num_open == 0xFFFF) {
+ return 0;
+ }
+
+again:
+ ret = ipc->next_fnum++;
+
+ for (p=ipc->pipe_list; p; p=p->next) {
+ if (p->fnum == ret) {
+ goto again;
+ }
+ }
+
+ return ret;
+}
+
+
+/*
+ shutdown a single pipe. Called on a close or disconnect
+*/
+static void pipe_shutdown(struct ipc_private *private, struct pipe_state *p)
+{
+ TALLOC_CTX *mem_ctx = private->pipe_list->mem_ctx;
+ dcesrv_endpoint_disconnect(private->pipe_list->pipe_state);
+ DLIST_REMOVE(private->pipe_list, private->pipe_list);
+ talloc_destroy(mem_ctx);
+}
+
+
+/*
+ find a open pipe give a file descriptor
+*/
+static struct pipe_state *pipe_state_find(struct ipc_private *private, uint16 fnum)
+{
+ struct pipe_state *p;
+
+ for (p=private->pipe_list; p; p=p->next) {
+ if (p->fnum == fnum) {
+ return p;
+ }
+ }
+
+ return NULL;
+}
+
+
/*
connect to a share - always works
*/
static NTSTATUS ipc_connect(struct request_context *req, const char *sharename)
{
struct tcon_context *conn = req->conn;
+ struct ipc_private *private;
conn->fs_type = talloc_strdup(conn->mem_ctx, "IPC");
conn->dev_type = talloc_strdup(conn->mem_ctx, "IPC");
+ /* prepare the private state for this connection */
+ private = talloc(conn->mem_ctx, sizeof(struct ipc_private));
+ if (!private) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ conn->ntvfs_private = (void *)private;
+
+ private->pipe_list = NULL;
+ private->next_fnum = 1;
+ private->num_open = 0;
+
return NT_STATUS_OK;
}
@@ -43,6 +129,13 @@ static NTSTATUS ipc_connect(struct request_context *req, const char *sharename)
*/
static NTSTATUS ipc_disconnect(struct tcon_context *tcon)
{
+ 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;
}
@@ -88,11 +181,79 @@ static NTSTATUS ipc_setpathinfo(struct request_context *req, union smb_setfilein
}
/*
- open a file
+ open a file - used for MSRPC pipes
*/
static NTSTATUS ipc_open(struct request_context *req, union smb_open *oi)
{
- return NT_STATUS_ACCESS_DENIED;
+ struct pipe_state *p;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+ struct dcesrv_endpoint endpoint;
+ struct ipc_private *private = req->conn->ntvfs_private;
+
+ /* for now only handle NTcreateX style opens */
+ if (oi->generic.level != RAW_OPEN_NTCREATEX) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ mem_ctx = talloc_init("ipc_open '%s'", oi->ntcreatex.in.fname);
+ if (!mem_ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ p = talloc(mem_ctx, sizeof(struct pipe_state));
+ if (!p) {
+ talloc_destroy(mem_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ p->mem_ctx = mem_ctx;
+
+ p->pipe_name = talloc_strdup(mem_ctx, oi->ntcreatex.in.fname);
+ if (!p->pipe_name) {
+ talloc_destroy(mem_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ p->fnum = find_next_fnum(private);
+ if (p->fnum == 0) {
+ talloc_destroy(mem_ctx);
+ return NT_STATUS_TOO_MANY_OPENED_FILES;
+ }
+
+ if (strncasecmp(p->pipe_name, "\\pipe\\", 6) != 0) {
+ talloc_destroy(mem_ctx);
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+ p->pipe_name += 6;
+
+ /*
+ 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
+ */
+
+ endpoint.type = ENDPOINT_SMB;
+ endpoint.info.smb_pipe = p->pipe_name;
+
+ status = dcesrv_endpoint_connect(req->smb, &endpoint, &p->pipe_state);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_destroy(mem_ctx);
+ return status;
+ }
+
+ private->num_open++;
+
+ DLIST_ADD(private->pipe_list, p);
+
+ ZERO_STRUCT(oi->ntcreatex.out);
+ oi->ntcreatex.out.fnum = p->fnum;
+
+ return NT_STATUS_OK;
}
/*
@@ -164,7 +325,22 @@ static NTSTATUS ipc_flush(struct request_context *req, struct smb_flush *io)
*/
static NTSTATUS ipc_close(struct request_context *req, union smb_close *io)
{
- return NT_STATUS_ACCESS_DENIED;
+ struct ipc_private *private = req->conn->ntvfs_private;
+ struct pipe_state *p;
+
+ if (io->generic.level != RAW_CLOSE_CLOSE) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ p = pipe_state_find(private, io->close.in.fnum);
+ if (!p) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ pipe_shutdown(private, p);
+ private->num_open--;
+
+ return NT_STATUS_OK;
}
/*