From 713b296441ec8b1447a0bc451720a8b84fd7e1fc Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 28 Jan 2006 20:08:03 +0000 Subject: r13210: Revert my named pipes patch until it passes not just 'make quicktest' but also 'make test' (This used to be commit e3d0676aee84e96e5c87bed4cd0cde75a4191953) --- source4/ntvfs/ipc/ipc.h | 30 ------ source4/ntvfs/ipc/np_echo.c | 77 -------------- source4/ntvfs/ipc/vfs_ipc.c | 243 ++++++++++++++++++++++---------------------- 3 files changed, 121 insertions(+), 229 deletions(-) (limited to 'source4/ntvfs/ipc') diff --git a/source4/ntvfs/ipc/ipc.h b/source4/ntvfs/ipc/ipc.h index 53818a5845..e69de29bb2 100644 --- a/source4/ntvfs/ipc/ipc.h +++ b/source4/ntvfs/ipc/ipc.h @@ -1,30 +0,0 @@ -/* - Unix SMB/CIFS implementation. - NTVFS IPC$ Named Pipes - Copyright (C) Jelmer Vernooij 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 - (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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -struct named_pipe_ops { - NTSTATUS (*open)(void *context_data, - const char *path, - struct auth_session_info *session, - struct stream_connection *stream, - TALLOC_CTX *ctx, void **private_data); - NTSTATUS (*trans)(void *private_data, DATA_BLOB *in, DATA_BLOB *out); - NTSTATUS (*write)(void *private_data, DATA_BLOB *out); - NTSTATUS (*read)(void *private_data, DATA_BLOB *in); -}; diff --git a/source4/ntvfs/ipc/np_echo.c b/source4/ntvfs/ipc/np_echo.c index bfa0083b79..e69de29bb2 100644 --- a/source4/ntvfs/ipc/np_echo.c +++ b/source4/ntvfs/ipc/np_echo.c @@ -1,77 +0,0 @@ -/* - Unix SMB/CIFS implementation. - DCE/RPC over named pipes support (glue between dcerpc and smb servers) - - Copyright (C) Jelmer Vernooij 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 - (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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" -#include "lib/socket/socket.h" -#include "lib/events/events.h" -#include "rpc_server/dcerpc_server.h" -#include "ntvfs/ipc/ipc.h" - -static NTSTATUS echo_pipe_open (void *context_data, const char *path, struct auth_session_info *session_info, struct stream_connection *srv_conn, TALLOC_CTX *mem_ctx, void **private_data) -{ - *private_data = talloc_zero(mem_ctx, DATA_BLOB); - - return NT_STATUS_OK; -} - -static NTSTATUS echo_pipe_trans(void *private_data, DATA_BLOB *in, DATA_BLOB *out) -{ - memcpy(out->data, in->data, MIN(out->length,in->length)); - - return NT_STATUS_OK; -} - -static NTSTATUS echo_pipe_write(void *private_data, DATA_BLOB *out) -{ - DATA_BLOB *cache = private_data; - return data_blob_append(cache, cache, out->data, out->length); -} - -static NTSTATUS echo_pipe_read(void *private_data, DATA_BLOB *in) -{ - uint8_t *newdata; - DATA_BLOB *cache = private_data; - uint32_t numread = MIN(in->length, cache->length); - - memcpy(in->data, cache->data, numread); - - cache->length -= numread; - newdata = talloc_memdup(cache, cache+numread, cache->length); - if (newdata == NULL) - return NT_STATUS_NO_MEMORY; - - talloc_free(cache->data); - cache->data = newdata; - - return NT_STATUS_OK; -} - -const struct named_pipe_ops echo_pipe_ops = { - .open = echo_pipe_open, - .write = echo_pipe_write, - .read = echo_pipe_read, - .trans = echo_pipe_trans -}; - -NTSTATUS np_echo_init(void) -{ - return named_pipe_listen("\\PIPE\\NPECHO", &echo_pipe_ops, NULL); -} diff --git a/source4/ntvfs/ipc/vfs_ipc.c b/source4/ntvfs/ipc/vfs_ipc.c index bde87684e1..dd7994c1fb 100644 --- a/source4/ntvfs/ipc/vfs_ipc.c +++ b/source4/ntvfs/ipc/vfs_ipc.c @@ -4,7 +4,6 @@ Copyright (C) Andrew Tridgell 2003 Copyright (C) Stefan (metze) Metzmacher 2004-2005 - Copyright (C) Jelmer Vernooij 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 @@ -29,10 +28,8 @@ #include "includes.h" #include "dlinklist.h" #include "smb_server/smb_server.h" -#include "ntvfs/ipc/ipc.h" #include "ntvfs/ntvfs.h" #include "rpc_server/dcerpc_server.h" -#include "smb_build.h" #define IPC_BASE_FNUM 0x400 @@ -49,9 +46,8 @@ struct ipc_private { struct pipe_state *next, *prev; struct ipc_private *private; const char *pipe_name; - const struct named_pipe_ops *ops; - void *private_data; uint16_t fnum; + struct dcesrv_connection *dce_conn; uint16_t ipc_state; /* we need to remember the session it was opened on, as it is illegal to operate on someone elses fnum */ @@ -80,6 +76,7 @@ static struct pipe_state *pipe_state_find(struct ipc_private *private, uint16_t static NTSTATUS ipc_connect(struct ntvfs_module_context *ntvfs, struct smbsrv_request *req, const char *sharename) { + NTSTATUS status; struct smbsrv_tcon *tcon = req->tcon; struct ipc_private *private; @@ -100,6 +97,10 @@ static NTSTATUS ipc_connect(struct ntvfs_module_context *ntvfs, private->idtree_fnum = idr_init(private); NT_STATUS_HAVE_NO_MEMORY(private->idtree_fnum); + /* setup the DCERPC server subsystem */ + status = dcesrv_init_ipc_context(private, &private->dcesrv); + NT_STATUS_NOT_OK_RETURN(status); + return NT_STATUS_OK; } @@ -170,55 +171,6 @@ static int ipc_fd_destructor(void *ptr) return 0; } -static struct named_pipe { - struct named_pipe *prev, *next; - const char *name; - const struct named_pipe_ops *ops; - void *context_data; -} *named_pipes = NULL; - -static NTSTATUS find_pipe_ops(const char *fname, const struct named_pipe_ops **ops, void **context_data) -{ - struct named_pipe *np; - - for (np = named_pipes; np; np = np->next) { - if (strcasecmp_m(np->name, fname) == 0) { - if (ops) *ops = np->ops; - if (context_data) *context_data = np->context_data; - return NT_STATUS_OK; - } - } - - return NT_STATUS_OBJECT_NAME_NOT_FOUND; -} - -NTSTATUS named_pipe_listen(const char *name, const struct named_pipe_ops *ops, void *context_data) -{ - NTSTATUS status; - struct named_pipe *np; - DEBUG(3, ("Registering named pipe `%s'\n", name)); - - status = find_pipe_ops(name, NULL, NULL); - if (NT_STATUS_IS_OK(status)) { - return NT_STATUS_OBJECT_NAME_COLLISION; - } - - if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { - return status; - } - - np = talloc(talloc_autofree_context(), struct named_pipe); - np->name = talloc_strdup(np, name); - np->ops = ops; - np->context_data = context_data; - np->prev = np->next = NULL; - - DLIST_ADD(named_pipes, np); - - return NT_STATUS_OK; -} - - /* open a file backend - used for MSRPC pipes @@ -229,9 +181,10 @@ static NTSTATUS ipc_open_generic(struct ntvfs_module_context *ntvfs, { struct pipe_state *p; NTSTATUS status; + struct dcerpc_binding *ep_description; struct ipc_private *private = ntvfs->private_data; - void *context_data; int fnum; + struct stream_connection *srv_conn = req->smb_conn->connection; if (!req->session || !req->session->session_info) { return NT_STATUS_ACCESS_DENIED; @@ -240,24 +193,14 @@ static NTSTATUS ipc_open_generic(struct ntvfs_module_context *ntvfs, p = talloc(req, struct pipe_state); NT_STATUS_HAVE_NO_MEMORY(p); + ep_description = talloc(req, struct dcerpc_binding); + NT_STATUS_HAVE_NO_MEMORY(ep_description); + while (fname[0] == '\\') fname++; - + p->pipe_name = talloc_asprintf(p, "\\pipe\\%s", fname); NT_STATUS_HAVE_NO_MEMORY(p->pipe_name); - status = find_pipe_ops(p->pipe_name, &p->ops, &context_data); - - /* FIXME: Perhaps fall back to opening /var/lib/samba/ipc/ ? */ - if (NT_STATUS_IS_ERR(status)) { - DEBUG(0, ("Unable to find pipe ops for `%s'\n", p->pipe_name)); - return status; - } - - status = p->ops->open(context_data, p->pipe_name, req->session->session_info, req->smb_conn->connection, p, &p->private_data); - if (NT_STATUS_IS_ERR(status)) { - return status; - } - fnum = idr_get_new_above(private->idtree_fnum, p, IPC_BASE_FNUM, UINT16_MAX); if (fnum == -1) { return NT_STATUS_TOO_MANY_OPENED_FILES; @@ -266,6 +209,29 @@ static NTSTATUS ipc_open_generic(struct ntvfs_module_context *ntvfs, p->fnum = fnum; p->ipc_state = 0x5ff; + /* + 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. + */ + ep_description->transport = NCACN_NP; + ep_description->endpoint = talloc_reference(ep_description, p->pipe_name); + + /* The session info is refcount-increased in the + * dcesrv_endpoint_search_connect() function + */ + status = dcesrv_endpoint_search_connect(private->dcesrv, + p, + ep_description, + req->session->session_info, + srv_conn, + &p->dce_conn); + if (!NT_STATUS_IS_OK(status)) { + idr_remove(private->idtree_fnum, p->fnum); + return status; + } + DLIST_ADD(private->pipe_list, p); p->smbpid = req->smbpid; @@ -385,6 +351,18 @@ static NTSTATUS ipc_copy(struct ntvfs_module_context *ntvfs, return NT_STATUS_ACCESS_DENIED; } +static NTSTATUS ipc_readx_dcesrv_output(void *private_data, DATA_BLOB *out, size_t *nwritten) +{ + DATA_BLOB *blob = private_data; + + if (out->length < blob->length) { + blob->length = out->length; + } + memcpy(blob->data, out->data, blob->length); + *nwritten = blob->length; + return NT_STATUS_OK; +} + /* read from a file */ @@ -415,7 +393,7 @@ static NTSTATUS ipc_read(struct ntvfs_module_context *ntvfs, } if (data.length != 0) { - status = p->ops->read(p->private_data, &data); + status = dcesrv_output(p->dce_conn, &data, ipc_readx_dcesrv_output); if (NT_STATUS_IS_ERR(status)) { return status; } @@ -453,7 +431,7 @@ static NTSTATUS ipc_write(struct ntvfs_module_context *ntvfs, return NT_STATUS_INVALID_HANDLE; } - status = p->ops->write(p->private_data, &data); + status = dcesrv_input(p->dce_conn, &data); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -639,12 +617,30 @@ static NTSTATUS ipc_search_close(struct ntvfs_module_context *ntvfs, return NT_STATUS_ACCESS_DENIED; } -/* SMBtrans - set named pipe state */ -static NTSTATUS ipc_np_set_nm_state(struct ntvfs_module_context *ntvfs, - struct smbsrv_request *req, struct smb_trans2 *trans) +static NTSTATUS ipc_trans_dcesrv_output(void *private_data, DATA_BLOB *out, size_t *nwritten) +{ + NTSTATUS status = NT_STATUS_OK; + DATA_BLOB *blob = private_data; + + if (out->length > blob->length) { + status = STATUS_BUFFER_OVERFLOW; + } + + if (out->length < blob->length) { + blob->length = out->length; + } + memcpy(blob->data, out->data, blob->length); + *nwritten = blob->length; + return status; +} + +/* SMBtrans - handle a DCERPC command */ +static NTSTATUS ipc_dcerpc_cmd(struct ntvfs_module_context *ntvfs, + struct smbsrv_request *req, struct smb_trans2 *trans) { - struct ipc_private *private = ntvfs->private_data; struct pipe_state *p; + struct ipc_private *private = ntvfs->private_data; + NTSTATUS status; /* the fnum is in setup[1] */ p = pipe_state_find(private, trans->in.setup[1]); @@ -652,25 +648,43 @@ static NTSTATUS ipc_np_set_nm_state(struct ntvfs_module_context *ntvfs, return NT_STATUS_INVALID_HANDLE; } - if (trans->in.params.length != 2) { - return NT_STATUS_INVALID_PARAMETER; + trans->out.data = data_blob_talloc(req, NULL, trans->in.max_data); + if (!trans->out.data.data) { + return NT_STATUS_NO_MEMORY; + } + + /* 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(p->dce_conn, &trans->out.data, ipc_trans_dcesrv_output); + if (NT_STATUS_IS_ERR(status)) { + return status; } - p->ipc_state = SVAL(trans->in.params.data, 0); trans->out.setup_count = 0; trans->out.setup = NULL; trans->out.params = data_blob(NULL, 0); - trans->out.data = data_blob(NULL, 0); - return NT_STATUS_OK; + return status; } -/* SMBtrans - named pipe transaction */ -static NTSTATUS ipc_np_trans(struct ntvfs_module_context *ntvfs, + +/* SMBtrans - set named pipe state */ +static NTSTATUS ipc_set_nm_pipe_state(struct ntvfs_module_context *ntvfs, struct smbsrv_request *req, struct smb_trans2 *trans) { struct ipc_private *private = ntvfs->private_data; - NTSTATUS status; struct pipe_state *p; /* the fnum is in setup[1] */ @@ -679,55 +693,50 @@ static NTSTATUS ipc_np_trans(struct ntvfs_module_context *ntvfs, return NT_STATUS_INVALID_HANDLE; } - if (trans->in.setup_count != 2) { + if (trans->in.params.length != 2) { return NT_STATUS_INVALID_PARAMETER; } - - trans->out.data = data_blob_talloc(req, NULL, trans->in.max_data); - if (!trans->out.data.data) { - return NT_STATUS_NO_MEMORY; - } - - status = p->ops->trans(p->private_data, &trans->in.data, &trans->out.data); - if (NT_STATUS_IS_ERR(status)) { - return status; - } + p->ipc_state = SVAL(trans->in.params.data, 0); trans->out.setup_count = 0; trans->out.setup = NULL; trans->out.params = data_blob(NULL, 0); + trans->out.data = data_blob(NULL, 0); return NT_STATUS_OK; } + /* SMBtrans - used to provide access to SMB pipes */ static NTSTATUS ipc_trans(struct ntvfs_module_context *ntvfs, struct smbsrv_request *req, struct smb_trans2 *trans) { NTSTATUS status; - if (strequal(trans->in.trans_name, "\\PIPE\\")) { /* Named pipe */ - switch (trans->in.setup[0]) { - case NAMED_PIPE_SETHANDLESTATE: - status = ipc_np_set_nm_state(ntvfs, req, trans); - break; - case NAMED_PIPE_TRANSACT: - status = ipc_np_trans(ntvfs, req, trans); - break; - default: - status = NT_STATUS_INVALID_PARAMETER; - break; - } - } else if (strequal(trans->in.trans_name, "\\PIPE\\LANMAN")) { /* RAP */ - status = ipc_rap_call(req, trans); - } else { - DEBUG(1, ("Unknown transaction name `%s'\n", trans->in.trans_name)); - status = NT_STATUS_NOT_SUPPORTED; + if (strequal(trans->in.trans_name, "\\PIPE\\LANMAN")) + return ipc_rap_call(req, 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(ntvfs, req, trans); + break; + case TRANSACT_DCERPCCMD: + status = ipc_dcerpc_cmd(ntvfs, req, trans); + break; + default: + status = NT_STATUS_INVALID_PARAMETER; + break; } return status; } + + /* initialialise the IPC backend, registering ourselves with the ntvfs subsystem */ @@ -735,9 +744,7 @@ NTSTATUS ntvfs_ipc_init(void) { NTSTATUS ret; struct ntvfs_ops ops; - init_module_fn static_init[] = STATIC_ntvfs_ipc_MODULES; - init_module_fn *shared_init; - + ZERO_STRUCT(ops); /* fill in the name and type */ @@ -784,13 +791,5 @@ NTSTATUS ntvfs_ipc_init(void) return ret; } - /* load available named pipe backends */ - shared_init = load_samba_modules(NULL, "np"); - - run_init_functions(static_init); - run_init_functions(shared_init); - - talloc_free(shared_init); - return ret; } -- cgit