summaryrefslogtreecommitdiff
path: root/source4/ntvfs
diff options
context:
space:
mode:
authorJelmer Vernooij <jelmer@samba.org>2006-01-28 12:58:38 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:51:34 -0500
commitad6303f82fa862111c239b32b39f299e563a0802 (patch)
tree8534fe0fab5b44b8f50f70c46141225704e3de42 /source4/ntvfs
parent654a21178fa7e908e3a2be42d5522ea1b1b23250 (diff)
downloadsamba-ad6303f82fa862111c239b32b39f299e563a0802.tar.gz
samba-ad6303f82fa862111c239b32b39f299e563a0802.tar.bz2
samba-ad6303f82fa862111c239b32b39f299e563a0802.zip
r13208: Clearly separate named pipes from the IPC$ NTVFS type.
This allows the easy addition of additional named pipes and removes the circular dependencies between the CIFS, RPC and RAP servers. Simple tests for a custom named pipe included. (This used to be commit 898d15acbd18e3b302a856c847e08c22c5024792)
Diffstat (limited to 'source4/ntvfs')
-rw-r--r--source4/ntvfs/config.mk5
-rw-r--r--source4/ntvfs/ipc/ipc.h30
-rw-r--r--source4/ntvfs/ipc/np_echo.c77
-rw-r--r--source4/ntvfs/ipc/vfs_ipc.c243
4 files changed, 233 insertions, 122 deletions
diff --git a/source4/ntvfs/config.mk b/source4/ntvfs/config.mk
index 74b62809f7..df96998cfe 100644
--- a/source4/ntvfs/config.mk
+++ b/source4/ntvfs/config.mk
@@ -47,7 +47,10 @@ OBJ_FILES = \
# End MODULE ntvfs_ipc
################################################
-
+[MODULE::np_echo]
+INIT_FUNCTION = np_echo_init
+OBJ_FILES = ipc/np_echo.o
+SUBSYSTEM = ntvfs_ipc
################################################
# Start MODULE ntvfs_nbench
diff --git a/source4/ntvfs/ipc/ipc.h b/source4/ntvfs/ipc/ipc.h
new file mode 100644
index 0000000000..53818a5845
--- /dev/null
+++ b/source4/ntvfs/ipc/ipc.h
@@ -0,0 +1,30 @@
+/*
+ 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
new file mode 100644
index 0000000000..bfa0083b79
--- /dev/null
+++ b/source4/ntvfs/ipc/np_echo.c
@@ -0,0 +1,77 @@
+/*
+ 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 dd7994c1fb..bde87684e1 100644
--- a/source4/ntvfs/ipc/vfs_ipc.c
+++ b/source4/ntvfs/ipc/vfs_ipc.c
@@ -4,6 +4,7 @@
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
@@ -28,8 +29,10 @@
#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
@@ -46,8 +49,9 @@ 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 */
@@ -76,7 +80,6 @@ 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;
@@ -97,10 +100,6 @@ 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;
}
@@ -171,6 +170,55 @@ 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
@@ -181,10 +229,9 @@ 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;
@@ -193,14 +240,24 @@ 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/<pipename> ? */
+ 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;
@@ -209,29 +266,6 @@ 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;
@@ -351,18 +385,6 @@ 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
*/
@@ -393,7 +415,7 @@ static NTSTATUS ipc_read(struct ntvfs_module_context *ntvfs,
}
if (data.length != 0) {
- status = dcesrv_output(p->dce_conn, &data, ipc_readx_dcesrv_output);
+ status = p->ops->read(p->private_data, &data);
if (NT_STATUS_IS_ERR(status)) {
return status;
}
@@ -431,7 +453,7 @@ static NTSTATUS ipc_write(struct ntvfs_module_context *ntvfs,
return NT_STATUS_INVALID_HANDLE;
}
- status = dcesrv_input(p->dce_conn, &data);
+ status = p->ops->write(p->private_data, &data);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
@@ -617,30 +639,12 @@ static NTSTATUS ipc_search_close(struct ntvfs_module_context *ntvfs,
return NT_STATUS_ACCESS_DENIED;
}
-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)
+/* 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)
{
- struct pipe_state *p;
struct ipc_private *private = ntvfs->private_data;
- NTSTATUS status;
+ struct pipe_state *p;
/* the fnum is in setup[1] */
p = pipe_state_find(private, trans->in.setup[1]);
@@ -648,43 +652,25 @@ static NTSTATUS ipc_dcerpc_cmd(struct ntvfs_module_context *ntvfs,
return NT_STATUS_INVALID_HANDLE;
}
- 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;
+ if (trans->in.params.length != 2) {
+ return NT_STATUS_INVALID_PARAMETER;
}
+ 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 status;
+ return NT_STATUS_OK;
}
-
-/* SMBtrans - set named pipe state */
-static NTSTATUS ipc_set_nm_pipe_state(struct ntvfs_module_context *ntvfs,
+/* SMBtrans - named pipe transaction */
+static NTSTATUS ipc_np_trans(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] */
@@ -693,50 +679,55 @@ static NTSTATUS ipc_set_nm_pipe_state(struct ntvfs_module_context *ntvfs,
return NT_STATUS_INVALID_HANDLE;
}
- if (trans->in.params.length != 2) {
+ if (trans->in.setup_count != 2) {
return NT_STATUS_INVALID_PARAMETER;
}
- p->ipc_state = SVAL(trans->in.params.data, 0);
+
+ 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;
+ }
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\\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;
+ 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;
}
return status;
}
-
-
/*
initialialise the IPC backend, registering ourselves with the ntvfs subsystem
*/
@@ -744,7 +735,9 @@ 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 */
@@ -791,5 +784,13 @@ 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;
}