diff options
Diffstat (limited to 'source4/ntvfs/ipc/vfs_ipc.c')
-rw-r--r-- | source4/ntvfs/ipc/vfs_ipc.c | 182 |
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; } /* |