mirror of
https://github.com/samba-team/samba.git
synced 2025-01-11 05:18:09 +03:00
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 898d15acbd
)
This commit is contained in:
parent
654a21178f
commit
ad6303f82f
@ -28,7 +28,10 @@ sub _prepare_build_h($)
|
||||
|
||||
foreach my $key (values %{$depend}) {
|
||||
my $DEFINE = ();
|
||||
next if ($key->{TYPE} ne "LIBRARY" and $key->{TYPE} ne "SUBSYSTEM");
|
||||
next if ($key->{TYPE} ne "LIBRARY" and
|
||||
$key->{TYPE} ne "SUBSYSTEM" and
|
||||
$key->{TYPE} ne "BINARY" and
|
||||
$key->{TYPE} ne "MODULE");
|
||||
next unless defined($key->{INIT_FUNCTIONS});
|
||||
|
||||
$DEFINE->{COMMENT} = "$key->{TYPE} $key->{NAME} INIT";
|
||||
|
@ -319,10 +319,10 @@
|
||||
/* used to indicate end of chain */
|
||||
#define SMB_CHAIN_NONE 0xFF
|
||||
|
||||
/* These are the trans subcommands */
|
||||
#define TRANSACT_SETNAMEDPIPEHANDLESTATE 0x01
|
||||
#define TRANSACT_DCERPCCMD 0x26
|
||||
#define TRANSACT_WAITNAMEDPIPEHANDLESTATE 0x53
|
||||
/* These are the named pipe commands */
|
||||
#define NAMED_PIPE_SETHANDLESTATE 0x01
|
||||
#define NAMED_PIPE_TRANSACT 0x26
|
||||
#define NAMED_PIPE_WAITHANDLESTATE 0x53
|
||||
|
||||
/* These are the NT transact sub commands. */
|
||||
#define NT_TRANSACT_CREATE 1
|
||||
|
@ -164,3 +164,5 @@ struct smbcli_state;
|
||||
struct substitute_context;
|
||||
|
||||
struct model_ops;
|
||||
|
||||
struct named_pipe_ops;
|
||||
|
@ -240,7 +240,7 @@ static NTSTATUS smb_send_trans_request(struct dcerpc_connection *c, DATA_BLOB *b
|
||||
trans->in.data = *blob;
|
||||
trans->in.params = data_blob(NULL, 0);
|
||||
|
||||
setup[0] = TRANSACT_DCERPCCMD;
|
||||
setup[0] = NAMED_PIPE_TRANSACT;
|
||||
setup[1] = smb->fnum;
|
||||
|
||||
trans->in.max_param = 0;
|
||||
|
@ -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
|
||||
|
30
source4/ntvfs/ipc/ipc.h
Normal file
30
source4/ntvfs/ipc/ipc.h
Normal file
@ -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);
|
||||
};
|
77
source4/ntvfs/ipc/np_echo.c
Normal file
77
source4/ntvfs/ipc/np_echo.c
Normal file
@ -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);
|
||||
}
|
@ -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,71 +639,8 @@ 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)
|
||||
{
|
||||
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]);
|
||||
if (!p) {
|
||||
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;
|
||||
}
|
||||
|
||||
trans->out.setup_count = 0;
|
||||
trans->out.setup = NULL;
|
||||
trans->out.params = data_blob(NULL, 0);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/* SMBtrans - set named pipe state */
|
||||
static NTSTATUS ipc_set_nm_pipe_state(struct ntvfs_module_context *ntvfs,
|
||||
static NTSTATUS ipc_np_set_nm_state(struct ntvfs_module_context *ntvfs,
|
||||
struct smbsrv_request *req, struct smb_trans2 *trans)
|
||||
{
|
||||
struct ipc_private *private = ntvfs->private_data;
|
||||
@ -706,6 +665,40 @@ static NTSTATUS ipc_set_nm_pipe_state(struct ntvfs_module_context *ntvfs,
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/* 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] */
|
||||
p = pipe_state_find(private, trans->in.setup[1]);
|
||||
if (!p) {
|
||||
return NT_STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (trans->in.setup_count != 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;
|
||||
}
|
||||
|
||||
trans->out.setup_count = 0;
|
||||
trans->out.setup = NULL;
|
||||
trans->out.params = 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,
|
||||
@ -713,30 +706,28 @@ static NTSTATUS ipc_trans(struct ntvfs_module_context *ntvfs,
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -204,6 +204,7 @@ REQUIRED_SUBSYSTEMS = \
|
||||
PRIVATE_PROTO_HEADER = dcerpc_server_proto.h
|
||||
OBJ_FILES = \
|
||||
dcerpc_server.o \
|
||||
dcerpc_np.o \
|
||||
dcerpc_sock.o \
|
||||
dcesrv_auth.o \
|
||||
handles.o
|
||||
|
167
source4/rpc_server/dcerpc_np.c
Normal file
167
source4/rpc_server/dcerpc_np.c
Normal file
@ -0,0 +1,167 @@
|
||||
/*
|
||||
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 dcesrv_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)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct dcerpc_binding *ep_description;
|
||||
struct dcesrv_connection *dce_conn;
|
||||
|
||||
ep_description = talloc(mem_ctx, struct dcerpc_binding);
|
||||
NT_STATUS_HAVE_NO_MEMORY(ep_description);
|
||||
|
||||
/*
|
||||
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, path);
|
||||
|
||||
/* The session info is refcount-increased in the
|
||||
* dcesrv_endpoint_search_connect() function
|
||||
*/
|
||||
status = dcesrv_endpoint_search_connect(context_data,
|
||||
mem_ctx,
|
||||
ep_description,
|
||||
session_info,
|
||||
srv_conn,
|
||||
&dce_conn);
|
||||
talloc_free(ep_description);
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
*private_data = dce_conn;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
static NTSTATUS dcesrv_pipe_trans(void *private_data, DATA_BLOB *in, DATA_BLOB *out)
|
||||
{
|
||||
struct dcesrv_connection *dce_conn = private_data;
|
||||
NTSTATUS status;
|
||||
|
||||
/* 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(dce_conn, in);
|
||||
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(dce_conn, out, ipc_trans_dcesrv_output);
|
||||
if (NT_STATUS_IS_ERR(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static NTSTATUS dcesrv_pipe_write(void *private_data, DATA_BLOB *out)
|
||||
{
|
||||
struct dcesrv_connection *dce_conn = private_data;
|
||||
NTSTATUS status;
|
||||
|
||||
status = dcesrv_input(dce_conn, out);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
static NTSTATUS dcesrv_pipe_read(void *private_data, DATA_BLOB *in)
|
||||
{
|
||||
struct dcesrv_connection *dce_conn = private_data;
|
||||
NTSTATUS status;
|
||||
|
||||
status = dcesrv_output(dce_conn, in, ipc_readx_dcesrv_output);
|
||||
if (NT_STATUS_IS_ERR(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
const struct named_pipe_ops dce_pipe_ops = {
|
||||
.open = dcesrv_pipe_open,
|
||||
.write = dcesrv_pipe_write,
|
||||
.read = dcesrv_pipe_read,
|
||||
.trans = dcesrv_pipe_trans
|
||||
};
|
||||
|
||||
/* Add named pipe endpoint */
|
||||
NTSTATUS dcesrv_add_ep_np(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e, struct event_context *event_ctx, const struct model_ops *model_ops)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
status = named_pipe_listen(e->ep_description->endpoint, &dce_pipe_ops, dce_ctx);
|
||||
if (NT_STATUS_IS_ERR(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
@ -1171,21 +1171,6 @@ static NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, const char **endpoint_s
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
initialise the dcerpc server context for ncacn_np based services
|
||||
*/
|
||||
NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **_dce_ctx)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct dcesrv_context *dce_ctx;
|
||||
|
||||
status = dcesrv_init_context(mem_ctx, lp_dcerpc_endpoint_servers(), 0, &dce_ctx);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
*_dce_ctx = dce_ctx;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/* the list of currently registered DCERPC endpoint servers.
|
||||
*/
|
||||
static struct ep_server {
|
||||
@ -1305,8 +1290,8 @@ static NTSTATUS dcesrv_init(struct event_context *event_context, const struct mo
|
||||
break;
|
||||
|
||||
case NCACN_NP:
|
||||
/* FIXME: status = dcesrv_add_ep_np(dce_ctx, e, event_context, model_ops);
|
||||
NT_STATUS_NOT_OK_RETURN(status); */
|
||||
status = dcesrv_add_ep_np(dce_ctx, e, event_context, model_ops);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -23,7 +23,7 @@ tests="$tests BASE-DIR2 BASE-TCON BASE-OPEN"
|
||||
tests="$tests BASE-CHKPATH RAW-QFSINFO RAW-QFILEINFO RAW-SFILEINFO"
|
||||
tests="$tests RAW-LOCK RAW-MKDIR RAW-SEEK RAW-OPEN RAW-WRITE"
|
||||
tests="$tests RAW-UNLINK RAW-READ RAW-CLOSE RAW-IOCTL RAW-RENAME"
|
||||
tests="$tests RAW-EAS RAW-STREAMS RAW-ACLS"
|
||||
tests="$tests RAW-EAS RAW-STREAMS RAW-ACLS RAW-PIPE-ECHO"
|
||||
|
||||
failed=0
|
||||
for t in $tests; do
|
||||
|
@ -121,13 +121,14 @@ REQUIRED_SUBSYSTEMS = \
|
||||
#################################
|
||||
|
||||
#################################
|
||||
# Start SUBSYSTEM TORTURE_RAP
|
||||
[SUBSYSTEM::TORTURE_RAP]
|
||||
# Start SUBSYSTEM TORTURE_IPC
|
||||
[SUBSYSTEM::TORTURE_IPC]
|
||||
OBJ_FILES = \
|
||||
rap/rap.o
|
||||
ipc/rap.o \
|
||||
ipc/np_echo.o
|
||||
REQUIRED_SUBSYSTEMS = \
|
||||
LIBSMB
|
||||
# End SUBSYSTEM TORTURE_RAP
|
||||
# End SUBSYSTEM TORTURE_IPC
|
||||
#################################
|
||||
|
||||
#################################
|
||||
@ -210,7 +211,7 @@ REQUIRED_SUBSYSTEMS = \
|
||||
TORTURE_RAW \
|
||||
TORTURE_SMB2 \
|
||||
TORTURE_RPC \
|
||||
TORTURE_RAP \
|
||||
TORTURE_IPC \
|
||||
TORTURE_AUTH \
|
||||
TORTURE_LOCAL \
|
||||
TORTURE_NBENCH \
|
||||
|
119
source4/torture/ipc/np_echo.c
Normal file
119
source4/torture/ipc/np_echo.c
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Named Pipe Echo test
|
||||
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 "librpc/gen_ndr/security.h"
|
||||
#include "smb.h"
|
||||
#include "torture/torture.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/libcli.h"
|
||||
|
||||
#define ECHODATA "Good Times, Bad Times"
|
||||
|
||||
int torture_np_echo(void)
|
||||
{
|
||||
NTSTATUS status;
|
||||
TALLOC_CTX *mem_ctx = NULL;
|
||||
struct smbcli_state *cli;
|
||||
const char *pipe_name = "\\NPECHO";
|
||||
union smb_open open;
|
||||
union smb_read read;
|
||||
union smb_write write;
|
||||
union smb_close close;
|
||||
int fnum;
|
||||
BOOL ret;
|
||||
|
||||
ret = torture_open_connection_share(mem_ctx, &cli,
|
||||
lp_parm_string(-1, "torture", "host"),
|
||||
"IPC$",
|
||||
NULL);
|
||||
if (!ret)
|
||||
return False;
|
||||
|
||||
open.ntcreatex.level = RAW_OPEN_NTCREATEX;
|
||||
open.ntcreatex.in.flags = 0;
|
||||
open.ntcreatex.in.root_fid = 0;
|
||||
open.ntcreatex.in.access_mask =
|
||||
SEC_STD_READ_CONTROL |
|
||||
SEC_FILE_WRITE_ATTRIBUTE |
|
||||
SEC_FILE_WRITE_EA |
|
||||
SEC_FILE_READ_DATA |
|
||||
SEC_FILE_WRITE_DATA;
|
||||
open.ntcreatex.in.file_attr = 0;
|
||||
open.ntcreatex.in.alloc_size = 0;
|
||||
open.ntcreatex.in.share_access =
|
||||
NTCREATEX_SHARE_ACCESS_READ |
|
||||
NTCREATEX_SHARE_ACCESS_WRITE;
|
||||
open.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
|
||||
open.ntcreatex.in.create_options = 0;
|
||||
open.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_IMPERSONATION;
|
||||
open.ntcreatex.in.security_flags = 0;
|
||||
open.ntcreatex.in.fname = pipe_name;
|
||||
|
||||
status = smb_raw_open(cli->tree, cli->tree, &open);
|
||||
if (NT_STATUS_IS_ERR(status))
|
||||
return False;
|
||||
|
||||
fnum = open.ntcreatex.out.fnum;
|
||||
|
||||
write.write.level = RAW_WRITE_WRITE;
|
||||
write.write.in.fnum = fnum;
|
||||
write.write.in.count = strlen(ECHODATA);
|
||||
write.write.in.offset = 0;
|
||||
write.write.in.remaining = 0;
|
||||
write.write.in.data = (const uint8_t *)ECHODATA;
|
||||
|
||||
status = smb_raw_write(cli->tree, &write);
|
||||
if (NT_STATUS_IS_ERR(status))
|
||||
return False;
|
||||
|
||||
if (write.write.out.nwritten != strlen(ECHODATA))
|
||||
return False;
|
||||
|
||||
read.read.level = RAW_READ_READ;
|
||||
read.read.in.fnum = fnum;
|
||||
read.read.in.count = strlen(ECHODATA);
|
||||
read.read.in.offset = 0;
|
||||
read.read.in.remaining = 0;
|
||||
read.read.out.data = talloc_array(mem_ctx, uint8_t, strlen(ECHODATA));
|
||||
|
||||
status = smb_raw_read(cli->tree, &read);
|
||||
|
||||
if (NT_STATUS_IS_ERR(status))
|
||||
return False;
|
||||
|
||||
if (read.read.out.nread != strlen(ECHODATA))
|
||||
return False;
|
||||
|
||||
if (memcmp(read.read.out.data, ECHODATA, strlen(ECHODATA)) != 0) {
|
||||
printf ("np_echo: Returned data did not match!\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
close.close.level = RAW_CLOSE_CLOSE;
|
||||
close.close.in.fnum = fnum;
|
||||
close.close.in.write_time = 0;
|
||||
|
||||
status = smb_raw_close(cli->tree, &close);
|
||||
if (NT_STATUS_IS_ERR(status))
|
||||
return False;
|
||||
|
||||
return True;
|
||||
}
|
@ -20,10 +20,10 @@
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "torture/torture.h"
|
||||
#include "rap.h"
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/libcli.h"
|
||||
#include "torture/torture.h"
|
||||
|
||||
struct rap_call {
|
||||
uint16_t callno;
|
@ -2246,6 +2246,7 @@ static struct {
|
||||
{"RAW-ACLS", torture_raw_acls, 0},
|
||||
{"RAW-RAP", torture_raw_rap, 0},
|
||||
{"RAW-COMPOSITE", torture_raw_composite, 0},
|
||||
{"RAW-PIPE-ECHO", torture_np_echo, 0 },
|
||||
|
||||
/* SMB2 tests */
|
||||
{"SMB2-CONNECT", torture_smb2_connect, 0},
|
||||
|
Loading…
Reference in New Issue
Block a user