1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-24 13:57:43 +03:00

This patch adds a better dcerpc server infastructure.

1.) We now register endpoint servers add startup via register_backend()
    and later use the smb.conf 'dcerpc endpoint servers' parameter to setup the dcesrv_context

2.) each endpoint server can register at context creation time as much interfaces as it wants
    (multiple interfaces on one endpoint are supported!)
    (NOTE:  there's a difference between 'endpoint server' and 'endpoint'!
	    for details look at rpc_server/dcesrv_server.h)

3.) one endpoint can have a security descriptor registered to it self
    this will be checked in the future when a client wants to connect
    to an smb pipe endpoint.

4.) we now have a 'remote' endpoint server, which works like the ntvfs_cifs module
    it takes this options in the [globals] section:

    dcerpc remote:interfaces = srvsvc, winreg, w32time, epmapper
    dcerpc remote:binding = ...
    dcerpc remote:user = ...
    dcerpc remote:password = ...

5.) we currently have tree endpoint servers: epmapper, rpcecho and remote

    the default for the 'dcerpc endpiont servers = epmapper, rpcecho'

    for testing you can also do
    dcerpc endpoint servers = rpcecho, remote, epmapper
    dcerpc remote:interfaces = srvsvc, samr, netlogon

6,) please notice the the epmapper now only returns NO_ENTRIES
    (but I think we'll find a solution for this too:-)

7.) also there're some other stuff left, but step by step :-)

This patch also includes updates for the
register_subsystem() , ntvfs_init(), and some other funtions
to check for duplicate subsystem registration


metze

(hmmm, my first large commit...I hope it works as supposed :-)
(This used to be commit 917e45dafd5be4c2cd90ff425b8d6f8403122349)
This commit is contained in:
Stefan Metzmacher 2004-01-08 22:55:27 +00:00
parent 8364fd2853
commit 7e6cf43756
24 changed files with 1016 additions and 454 deletions

View File

@ -284,12 +284,12 @@ NTVFS_POSIX_OBJ = ntvfs/posix/vfs_posix.o
SMBD_NTVFS_OBJ = ntvfs/ntvfs_base.o ntvfs/ntvfs_util.o \
ntvfs/ntvfs_generic.o @NTVFS_STATIC@
SMBD_RPC_OBJ = rpc_server/dcerpc_server.o \
rpc_server/dcesrv_auth.o \
rpc_server/dcerpc_tcp.o \
rpc_server/handles.o \
rpc_server/echo/rpc_echo.o \
rpc_server/epmapper/rpc_epmapper.o
DCERPC_RPCECHO_OBJ = rpc_server/echo/rpc_echo.o
DCERPC_EPMAPPER_OBJ = rpc_server/epmapper/rpc_epmapper.o
DCERPC_REMOTE_OBJ = rpc_server/remote/dcesrv_remote.o
SMBD_RPC_OBJ = rpc_server/dcerpc_server.o rpc_server/dcesrv_auth.o \
rpc_server/dcerpc_tcp.o rpc_server/handles.o @DCERPC_STATIC@
SMBD_OBJ_SRV = smbd/connection.o \
smbd/session.o \

View File

@ -278,7 +278,7 @@ sub HeaderInterface($)
$res .= "#define DCERPC_$name\_VERSION $if_version\n";
$res .= "#define DCERPC_$name\_NAME \"$interface->{NAME}\"\n\n";
$res .= "extern const struct dcerpc_interface_table dcerpc_table_$interface->{NAME};\n";
$res .= "void rpc_$interface->{NAME}_init(void *);\n\n";
$res .= "NTSTATUS dcerpc_$interface->{NAME}_init(void);\n\n";
}
foreach my $d (@{$data}) {

View File

@ -1,6 +1,7 @@
###################################################
# server boilerplate generator
# Copyright tridge@samba.org 2003
# Copyright metze@samba.org 2004
# released under the GNU GPL
package IdlServer;
@ -16,7 +17,7 @@ sub pidl($)
#####################################################################
# produce boilerplate code for a interface
sub Boilerplate($)
sub Boilerplate_Iface($)
{
my($interface) = shift;
my($data) = $interface->{DATA};
@ -41,49 +42,105 @@ sub Boilerplate($)
pidl "\tNULL};\n\n";
pidl "
static BOOL $name\_op_query_endpoint(const struct dcesrv_endpoint *ep)
{
return dcesrv_table_query(&dcerpc_table_$name, ep);
}
static BOOL $name\_op_set_interface(struct dcesrv_state *dce,
const char *uuid, uint32 if_version)
{
return dcesrv_set_interface(dce, uuid, if_version,
&dcerpc_table_$name, $name\_dispatch_table);
}
static NTSTATUS $name\_op_connect(struct dcesrv_state *dce)
static NTSTATUS $name\_op_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface)
{
return NT_STATUS_OK;
}
static void $name\_op_disconnect(struct dcesrv_state *dce)
static void $name\_op_unbind(struct dcesrv_connection *dce_conn, const struct dcesrv_interface *iface)
{
/* nothing to do */
return;
}
static int $name\_op_lookup_endpoints(TALLOC_CTX *mem_ctx, struct dcesrv_ep_iface **e)
static NTSTATUS $name\_op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
{
return dcesrv_lookup_endpoints(&dcerpc_table_$name, mem_ctx, e);
uint16 opnum = dce_call->pkt.u.request.opnum;
return $name\_dispatch_table[opnum](dce_call, mem_ctx, r);
}
static const struct dcesrv_endpoint_ops $name\_ops = {
$name\_op_query_endpoint,
$name\_op_set_interface,
$name\_op_connect,
$name\_op_disconnect,
$name\_op_lookup_endpoints
static const struct dcesrv_interface $name\_interface = {
&dcerpc_table_$name,
$name\_op_bind,
$name\_op_unbind,
$name\_op_dispatch
};
void rpc_$name\_init(void *v)
";
}
#####################################################################
# produce boilerplate code for an endpoint server
sub Boilerplate_Ep_Server($)
{
struct dcesrv_context *dce = v;
if (!dcesrv_endpoint_register(dce, &$name\_ops,
&dcerpc_table_$name)) {
DEBUG(1,(\"Failed to register rpcecho endpoint\\n\"));
my($interface) = shift;
my($data) = $interface->{DATA};
my $count = 0;
my $name = $interface->{NAME};
my $uname = uc $name;
foreach my $d (@{$data}) {
if ($d->{TYPE} eq "FUNCTION") { $count++; }
}
if ($count == 0) {
return;
}
pidl "
static NTSTATUS $name\_op_init_server(struct dcesrv_context *dce_ctx, const struct dcesrv_endpoint_server *ep_server)
{
int i;
for (i=0;i<$name\_interface.ndr->endpoints->count;i++) {
NTSTATUS ret;
const char *name = $name\_interface.ndr->endpoints->names[i];
ret = dcesrv_interface_register(dce_ctx, name, &$name\_interface, NULL);
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(1,(\"$name\_op_init_server: failed to register endpoint \'%s\'\\n\",name));
return ret;
}
}
return NT_STATUS_OK;
}
static BOOL $name\_op_interface_by_uuid(struct dcesrv_interface *iface, const char *uuid, uint32 if_version)
{
return False;
}
static BOOL $name\_op_interface_by_name(struct dcesrv_interface *iface, const char *name)
{
return False;
}
NTSTATUS dcerpc_$name\_init(void)
{
NTSTATUS ret;
struct dcesrv_endpoint_server ep_server;
/* fill in our name */
ep_server.name = \"$name\";
/* fill in all the operations */
ep_server.init_server = $name\_op_init_server;
ep_server.interface_by_uuid = $name\_op_interface_by_uuid;
ep_server.interface_by_name = $name\_op_interface_by_name;
/* register ourselves with the NTVFS subsystem. */
ret = register_backend(\"dcerpc\", &ep_server);
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(0,(\"Failed to register \'$name\' endpoint server!\\n\"));
return ret;
}
return ret;
}
";
}
@ -95,9 +152,12 @@ sub Parse($)
my($idl) = shift;
$res = "/* dcerpc server boilerplate generated by pidl */\n\n";
foreach my $x (@{$idl}) {
($x->{TYPE} eq "INTERFACE") &&
Boilerplate($x);
if ($x->{TYPE} eq "INTERFACE") {
Boilerplate_Iface($x);
Boilerplate_Ep_Server($x);
}
}
return $res;
}

View File

@ -60,7 +60,7 @@ sub process_file($)
close(FILE);
}
print "Creating $opt_output.[ch]\n";
open(TABLEH, ">$opt_output.h") || die "failed to open $opt_output.h\n";
open(TABLEC, ">$opt_output.c") || die "failed to open $opt_output.c\n";

View File

@ -18,8 +18,7 @@ sub Template($)
my $name = $interface->{NAME};
$res .=
"
/*
"/*
Unix SMB/CIFS implementation.
endpoint server for the $name pipe
@ -53,7 +52,7 @@ sub Template($)
/*
$fname
*/
static NTSTATUS $fname(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx,
static NTSTATUS $fname(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct $fname *r)
{
return NT_STATUS_NOT_IMPLEMENTED;
@ -85,4 +84,3 @@ sub Parse($)
}
1;

View File

@ -233,7 +233,7 @@ DYNEXP=
dnl Add modules that have to be built by default here
dnl These have to be built static:
default_static_modules="ntvfs_ipc ntvfs_simple ntvfs_print ntvfs_cifs"
default_static_modules="ntvfs_ipc ntvfs_simple ntvfs_print ntvfs_cifs dcerpc_rpcecho dcerpc_epmapper dcerpc_remote"
dnl These are preferably build shared, and static if dlopen() is not available
default_shared_modules=""
@ -2830,6 +2830,7 @@ SMB_MODULE(charset_weird, modules/weird.o, "bin/weird.$SHLIBEXT", CHARSET)
SMB_SUBSYSTEM(CHARSET,lib/iconv.o)
sinclude(ntvfs/config.m4)
sinclude(rpc_server/config.m4)
AC_DEFINE_UNQUOTED(STRING_STATIC_MODULES, "$string_static_modules", [String list of builtin modules])

View File

@ -125,9 +125,19 @@ struct subsystem {
static struct subsystem *subsystems = NULL;
void register_subsystem(const char *name, register_backend_function callback)
NTSTATUS register_subsystem(const char *name, register_backend_function callback)
{
struct subsystem *s;
struct subsystem *t = subsystems;
while(t) {
if(!strcmp(name, t->name)) {
/* its already registered! */
DEBUG(0,("SUBSYSTEM '%s' for type already registered\n", name));
return NT_STATUS_OBJECT_NAME_COLLISION;
}
t = t->next;
}
s = smb_xmalloc(sizeof(struct subsystem));
@ -136,6 +146,8 @@ void register_subsystem(const char *name, register_backend_function callback)
s->prev = s->next = NULL;
DLIST_ADD(subsystems, s);
return NT_STATUS_OK;
}
NTSTATUS register_backend(const char *subsystem, void *args)

View File

@ -88,6 +88,37 @@ void ndr_print_dom_sid2(struct ndr_print *ndr, const char *name, struct dom_sid2
ndr_print_dom_sid(ndr, name, sid);
}
/*
return the wire size of a dom_sid
*/
size_t ndr_size_dom_sid(struct dom_sid *sid)
{
if (!sid) return 0;
return 8 + 4*sid->num_auths;
}
/*
add a rid to a domain dom_sid to make a full dom_sid
*/
struct dom_sid *dom_sid_add_rid(TALLOC_CTX *mem_ctx,
const struct dom_sid *domain_sid,
uint32 rid)
{
struct dom_sid *sid;
sid = talloc_p(mem_ctx, struct dom_sid);
if (!sid) return NULL;
*sid = *domain_sid;
sid->sub_auths = talloc_array_p(mem_ctx, uint32, sid->num_auths+1);
if (!sid->sub_auths) {
return NULL;
}
memcpy(sid->sub_auths, domain_sid->sub_auths, sid->num_auths*sizeof(uint32));
sid->sub_auths[sid->num_auths] = rid;
sid->num_auths++;
return sid;
}
/*
return the wire size of a security_ace
@ -114,15 +145,6 @@ size_t ndr_size_security_acl(struct security_acl *acl)
return ret;
}
/*
return the wire size of a dom_sid
*/
size_t ndr_size_dom_sid(struct dom_sid *sid)
{
if (!sid) return 0;
return 8 + 4*sid->num_auths;
}
/*
return the wire size of a security descriptor
*/
@ -140,24 +162,16 @@ size_t ndr_size_security_descriptor(struct security_descriptor *sd)
}
/*
add a rid to a domain dom_sid to make a full dom_sid
talloc and copy a security descriptor
*/
struct dom_sid *dom_sid_add_rid(TALLOC_CTX *mem_ctx,
const struct dom_sid *domain_sid,
uint32 rid)
struct security_descriptor *copy_security_descriptor(TALLOC_CTX *mem_ctx,
const struct security_descriptor *osd)
{
struct dom_sid *sid;
struct security_descriptor *nsd;
sid = talloc_p(mem_ctx, struct dom_sid);
if (!sid) return NULL;
/* FIXME */
DEBUG(1, ("copy_security_descriptor: sorry unimplemented yet\n"));
nsd = NULL;
*sid = *domain_sid;
sid->sub_auths = talloc_array_p(mem_ctx, uint32, sid->num_auths+1);
if (!sid->sub_auths) {
return NULL;
}
memcpy(sid->sub_auths, domain_sid->sub_auths, sid->num_auths*sizeof(uint32));
sid->sub_auths[sid->num_auths] = rid;
sid->num_auths++;
return sid;
return nsd;
}

View File

@ -1,7 +1,9 @@
/*
Unix SMB/CIFS implementation.
default IPC$ NTVFS backend
Copyright (C) Andrew Tridgell 2003
Copyright (C) Stefan (metze) Metzmacher 2004
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
@ -39,7 +41,7 @@ struct ipc_private {
TALLOC_CTX *mem_ctx;
const char *pipe_name;
uint16 fnum;
struct dcesrv_state *pipe_state;
struct dcesrv_connection *dce_conn;
uint16 ipc_state;
} *pipe_list;
@ -77,7 +79,7 @@ again:
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);
dcesrv_endpoint_disconnect(private->pipe_list->dce_conn);
DLIST_REMOVE(private->pipe_list, private->pipe_list);
talloc_destroy(mem_ctx);
}
@ -192,7 +194,7 @@ static NTSTATUS ipc_open_generic(struct request_context *req, const char *fname,
struct pipe_state *p;
TALLOC_CTX *mem_ctx;
NTSTATUS status;
struct dcesrv_endpoint endpoint;
struct dcesrv_ep_description ep_description;
struct ipc_private *private = req->conn->ntvfs_private;
mem_ctx = talloc_init("ipc_open '%s'", fname);
@ -235,10 +237,10 @@ static NTSTATUS ipc_open_generic(struct request_context *req, const char *fname,
finalised for Samba4
*/
endpoint.type = ENDPOINT_SMB;
endpoint.info.smb_pipe = p->pipe_name;
ep_description.type = ENDPOINT_SMB;
ep_description.info.smb_pipe = p->pipe_name;
status = dcesrv_endpoint_connect(&req->smb->dcesrv, &endpoint, &p->pipe_state);
status = dcesrv_endpoint_search_connect(&req->smb->dcesrv, &ep_description, &p->dce_conn);
if (!NT_STATUS_IS_OK(status)) {
talloc_destroy(mem_ctx);
return status;
@ -386,7 +388,7 @@ static NTSTATUS ipc_read(struct request_context *req, union smb_read *rd)
return NT_STATUS_INVALID_HANDLE;
}
status = dcesrv_output(p->pipe_state, &data);
status = dcesrv_output(p->dce_conn, &data);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
@ -440,7 +442,7 @@ static NTSTATUS ipc_write(struct request_context *req, union smb_write *wr)
return NT_STATUS_INVALID_HANDLE;
}
status = dcesrv_input(p->pipe_state, &data);
status = dcesrv_input(p->dce_conn, &data);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
@ -599,7 +601,7 @@ static NTSTATUS ipc_dcerpc_cmd(struct request_context *req, struct smb_trans2 *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->pipe_state, &trans->in.data);
status = dcesrv_input(p->dce_conn, &trans->in.data);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
@ -609,7 +611,7 @@ static NTSTATUS ipc_dcerpc_cmd(struct request_context *req, struct smb_trans2 *t
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->pipe_state, &trans->out.data);
status = dcesrv_output(p->dce_conn, &trans->out.data);
if (!NT_STATUS_IS_OK(status)) {
return status;
}

View File

@ -1,7 +1,9 @@
/*
Unix SMB/CIFS implementation.
NTVFS base code
Copyright (C) Andrew Tridgell 2003
Copyright (C) Stefan (metze) Metzmacher 2004
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
@ -107,12 +109,17 @@ const struct ntvfs_critical_sizes *ntvfs_interface_version(void)
*/
BOOL ntvfs_init(void)
{
register_subsystem("ntvfs", ntvfs_register);
NTSTATUS status;
status = register_subsystem("ntvfs", ntvfs_register);
if (!NT_STATUS_IS_OK(status)) {
return False;
}
/* FIXME: Perhaps panic if a basic backend, such as IPC, fails to initialise? */
static_init_ntvfs;
DEBUG(3,("NTVFS version %d initialised\n", NTVFS_INTERFACE_VERSION));
DEBUG(3,("NTVFS subsystem version %d initialised\n", NTVFS_INTERFACE_VERSION));
return True;
}

View File

@ -151,6 +151,7 @@ typedef struct
char *szAbortShutdownScript;
char *szWINSHook;
char *szWINSPartners;
char **dcerpc_ep_servers;
#ifdef WITH_UTMP
char *szUtmpDir;
char *szWtmpDir;
@ -738,6 +739,7 @@ static struct parm_struct parm_table[] = {
{"interfaces", P_LIST, P_GLOBAL, &Globals.szInterfaces, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
{"bind interfaces only", P_BOOL, P_GLOBAL, &Globals.bBindInterfacesOnly, NULL, NULL, FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
{"ntvfs handler", P_STRING, P_LOCAL, &sDefault.ntvfs_handler, NULL, NULL, FLAG_ADVANCED},
{"dcerpc endpoint servers", P_LIST, P_GLOBAL, &Globals.dcerpc_ep_servers, NULL, NULL, FLAG_ADVANCED},
{"Security Options", P_SEP, P_SEPARATOR},
@ -1270,6 +1272,8 @@ static void init_globals(void)
string_set(&sDefault.fstype, FSTYPE_STRING);
string_set(&sDefault.ntvfs_handler, "default");
Globals.dcerpc_ep_servers = str_list_make("epmapper rpcecho", NULL);
string_set(&Globals.szSMBPasswdFile, dyn_SMB_PASSWD_FILE);
string_set(&Globals.szPrivateDir, dyn_PRIVATE_DIR);
@ -1571,6 +1575,7 @@ FN_GLOBAL_STRING(lp_lockdir, &Globals.szLockDir)
FN_GLOBAL_STRING(lp_piddir, &Globals.szPidDir)
FN_GLOBAL_STRING(lp_mangling_method, &Globals.szManglingMethod)
FN_GLOBAL_INTEGER(lp_mangle_prefix, &Globals.mangle_prefix)
FN_GLOBAL_LIST(lp_dcerpc_endpoint_servers, &Globals.dcerpc_ep_servers)
#ifdef WITH_UTMP
FN_GLOBAL_STRING(lp_utmpdir, &Globals.szUtmpDir)
FN_GLOBAL_STRING(lp_wtmpdir, &Globals.szWtmpDir)

View File

@ -0,0 +1,7 @@
default_static_modules="$default_static_modules dcerpc_rpcecho dcerpc_epmapper dcerpc_remote"
SMB_MODULE(dcerpc_rpcecho, \$(DCERPC_RPCECHO_OBJ), "bin/dcerpc_rpcecho.$SHLIBEXT$", DCERPC)
SMB_MODULE(dcerpc_epmapper, \$(DCERPC_EPMAPPER_OBJ), "bin/dcerpc_epmapper.$SHLIBEXT$", DCERPC)
SMB_MODULE(dcerpc_remote, \$(DCERPC_REMOTE_OBJ), "bin/dcerpc_remote.$SHLIBEXT$", DCERPC)
SMB_SUBSYSTEM(DCERPC,rpc_server/dcerpc_server.o)

View File

@ -4,6 +4,7 @@
server side dcerpc core code
Copyright (C) Andrew Tridgell 2003
Copyright (C) Stefan (metze) Metzmacher 2004
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
@ -23,15 +24,105 @@
#include "includes.h"
/*
find the set of endpoint operations for an endpoint server
see if two endpoints match
*/
static const struct dcesrv_endpoint_ops *find_endpoint(struct dcesrv_context *dce,
const struct dcesrv_endpoint *endpoint)
static BOOL endpoints_match(const struct dcesrv_ep_description *ep1,
const struct dcesrv_ep_description *ep2)
{
struct dce_endpoint *ep;
for (ep=dce->endpoint_list; ep; ep=ep->next) {
if (ep->endpoint_ops->query_endpoint(endpoint)) {
return ep->endpoint_ops;
if (ep1->type != ep2->type) {
return False;
}
switch (ep1->type) {
case ENDPOINT_SMB:
if (strcmp(ep1->info.smb_pipe,ep2->info.smb_pipe)==0) {
return True;
}
break;
case ENDPOINT_TCP:
if (ep1->info.tcp_port == ep2->info.tcp_port) {
return True;
}
break;
}
return False;
}
/*
find an endpoint in the dcesrv_context
*/
static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
const struct dcesrv_ep_description *ep_description)
{
struct dcesrv_endpoint *ep;
for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
if (endpoints_match(&ep->ep_description, ep_description)) {
return ep;
}
}
return NULL;
}
/*
see if a uuid and if_version match to an interface
*/
static BOOL interface_match(const struct dcesrv_interface *if1,
const struct dcesrv_interface *if2)
{
if (if1->ndr->if_version != if2->ndr->if_version) {
return False;
}
if (strcmp(if1->ndr->uuid, if2->ndr->uuid)==0) {
return True;
}
return False;
}
/*
find the interface operations on an endpoint
*/
static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
const struct dcesrv_interface *iface)
{
struct dcesrv_if_list *ifl;
for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
if (interface_match(&(ifl->iface), iface)) {
return &(ifl->iface);
}
}
return NULL;
}
/*
see if a uuid and if_version match to an interface
*/
static BOOL interface_match_by_uuid(const struct dcesrv_interface *iface,
const char *uuid, uint32 if_version)
{
if (iface->ndr->if_version != if_version) {
return False;
}
if (strcmp(iface->ndr->uuid, uuid)==0) {
return True;
}
return False;
}
/*
find the interface operations on an endpoint by uuid
*/
static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
const char *uuid, uint32 if_version)
{
struct dcesrv_if_list *ifl;
for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
return &(ifl->iface);
}
}
return NULL;
@ -40,10 +131,10 @@ static const struct dcesrv_endpoint_ops *find_endpoint(struct dcesrv_context *dc
/*
find a call that is pending in our call list
*/
static struct dcesrv_call_state *dcesrv_find_call(struct dcesrv_state *dce, uint16 call_id)
static struct dcesrv_call_state *dcesrv_find_call(struct dcesrv_connection *dce_conn, uint16 call_id)
{
struct dcesrv_call_state *c;
for (c=dce->call_list;c;c=c->next) {
for (c=dce_conn->call_list;c;c=c->next) {
if (c->pkt.call_id == call_id) {
return c;
}
@ -52,92 +143,98 @@ static struct dcesrv_call_state *dcesrv_find_call(struct dcesrv_state *dce, uint
}
/*
register an endpoint server
register an interface on an endpoint
*/
BOOL dcesrv_endpoint_register(struct dcesrv_context *dce,
const struct dcesrv_endpoint_ops *ops,
const struct dcerpc_interface_table *table)
NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
const char *ep_name,
const struct dcesrv_interface *iface,
const struct security_descriptor *sd)
{
BOOL done_smb=False;
BOOL done_tcp=False;
int i;
for (i=0;i<table->endpoints->count;i++) {
struct dce_endpoint *ep;
struct dcesrv_ep_description ep_description;
struct dcesrv_endpoint *ep;
struct dcesrv_if_list *ifl;
BOOL tcp;
BOOL add_ep = False;
tcp = (strncasecmp(table->endpoints->names[i], "TCP-", 4) == 0);
tcp = (strncasecmp(ep_name, "TCP-", 4) == 0);
if (tcp) {
if (done_tcp) continue;
done_tcp = True;
ep_description.type = ENDPOINT_TCP;
ep_description.info.tcp_port = atoi(ep_name+4);
} else {
if (done_smb) continue;
done_smb = True;
ep_description.type = ENDPOINT_SMB;
ep_description.info.smb_pipe = ep_name;
}
ep = malloc(sizeof(*ep));
if (!ep) {
return False;
}
if (tcp) {
ep->endpoint.type = ENDPOINT_TCP;
ep->endpoint.info.tcp_port = atoi(table->endpoints->names[i]+4);
} else {
ep->endpoint.type = ENDPOINT_SMB;
ep->endpoint.info.smb_pipe = table->endpoints->names[i];
}
ep->endpoint_ops = ops;
DLIST_ADD(dce->endpoint_list, ep);
}
return True;
}
/*
connect to a dcerpc endpoint
/* check if this endpoint exists
*/
NTSTATUS dcesrv_endpoint_connect_ops(struct dcesrv_context *dce,
const struct dcesrv_endpoint *endpoint,
const struct dcesrv_endpoint_ops *ops,
struct dcesrv_state **p)
{
TALLOC_CTX *mem_ctx;
NTSTATUS status;
if ((ep=find_endpoint(dce_ctx, &ep_description))==NULL) {
ep = talloc(dce_ctx->mem_ctx, sizeof(*ep));
if (!ep) {
return NT_STATUS_NO_MEMORY;
}
ZERO_STRUCTP(ep);
if (tcp) {
ep->ep_description.type = ENDPOINT_TCP;
ep->ep_description.info.tcp_port = atoi(ep_name+4);
} else {
ep->ep_description.type = ENDPOINT_SMB;
ep->ep_description.info.smb_pipe = smb_xstrdup(ep_name);
}
add_ep = True;
}
mem_ctx = talloc_init("dcesrv_endpoint_connect");
if (!mem_ctx) {
/* see if the interface is already registered on te endpoint */
if (find_interface(ep, iface)!=NULL) {
DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
iface->ndr->name, ep_name));
return NT_STATUS_OBJECT_NAME_COLLISION;
}
/* talloc a new interface list element */
ifl = talloc(dce_ctx->mem_ctx, sizeof(*ifl));
if (!ifl) {
return NT_STATUS_NO_MEMORY;
}
*p = talloc_p(mem_ctx, struct dcesrv_state);
if (! *p) {
talloc_destroy(mem_ctx);
return NT_STATUS_NO_MEMORY;
/* copy the given interface struct to the one on the endpoints interface list */
memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
/* if we have a security descriptor given,
* we should see if we can set it up on the endpoint
*/
if (sd != NULL) {
/* if there's currently no security descriptor given on the endpoint
* we try to set it
*/
if (ep->sd == NULL) {
ep->sd = copy_security_descriptor(dce_ctx->mem_ctx, sd);
}
(*p)->dce = dce;
(*p)->mem_ctx = mem_ctx;
(*p)->endpoint = *endpoint;
(*p)->ops = ops;
(*p)->private = NULL;
(*p)->call_list = NULL;
(*p)->cli_max_recv_frag = 0;
(*p)->ndr = NULL;
(*p)->dispatch = NULL;
(*p)->handles = NULL;
(*p)->partial_input = data_blob(NULL, 0);
(*p)->auth_state.ntlmssp_state = NULL;
(*p)->auth_state.auth_info = NULL;
/* make sure the endpoint server likes the connection */
status = ops->connect(*p);
if (!NT_STATUS_IS_OK(status)) {
talloc_destroy(mem_ctx);
return status;
/* if now there's no security descriptor given on the endpoint
* something goes wrong, either we failed to copy the security descriptor
* or there was already one on the endpoint
*/
if (ep->sd != NULL) {
DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
" on endpoint '%s'\n",
iface->ndr->name, ep_name));
if (add_ep) free(ep);
free(ifl);
return NT_STATUS_OBJECT_NAME_COLLISION;
}
}
/* finally add the interface on the endpoint */
DLIST_ADD(ep->interface_list, ifl);
/* if it's a new endpoint add it to the dcesrv_context */
if (add_ep) {
DLIST_ADD(dce_ctx->endpoint_list, ep);
}
DEBUG(3,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
iface->ndr->name, ep_name));
return NT_STATUS_OK;
}
@ -145,28 +242,76 @@ NTSTATUS dcesrv_endpoint_connect_ops(struct dcesrv_context *dce,
/*
connect to a dcerpc endpoint
*/
NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce,
const struct dcesrv_endpoint *endpoint,
struct dcesrv_state **p)
NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
const struct dcesrv_endpoint *ep,
struct dcesrv_connection **p)
{
const struct dcesrv_endpoint_ops *ops;
TALLOC_CTX *mem_ctx;
mem_ctx = talloc_init("dcesrv_endpoint_connect");
if (!mem_ctx) {
return NT_STATUS_NO_MEMORY;
}
*p = talloc_p(mem_ctx, struct dcesrv_connection);
if (! *p) {
talloc_destroy(mem_ctx);
return NT_STATUS_NO_MEMORY;
}
(*p)->dce_ctx = dce_ctx;
(*p)->mem_ctx = mem_ctx;
(*p)->endpoint = ep;
(*p)->iface = NULL;
(*p)->private = NULL;
(*p)->call_list = NULL;
(*p)->cli_max_recv_frag = 0;
(*p)->handles = NULL;
(*p)->partial_input = data_blob(NULL, 0);
(*p)->auth_state.ntlmssp_state = NULL;
(*p)->auth_state.auth_info = NULL;
return NT_STATUS_OK;
}
/*
search and connect to a dcerpc endpoint
*/
NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
const struct dcesrv_ep_description *ep_description,
struct dcesrv_connection **dce_conn_p)
{
NTSTATUS status;
const struct dcesrv_endpoint *ep;
/* make sure this endpoint exists */
ops = find_endpoint(dce, endpoint);
if (!ops) {
ep = find_endpoint(dce_ctx, ep_description);
if (!ep) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
}
return dcesrv_endpoint_connect_ops(dce, endpoint, ops, p);
status = dcesrv_endpoint_connect(dce_ctx, ep, dce_conn_p);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
/* TODO: check security descriptor of the endpoint here
* if it's a smb named pipe
* if it's failed free dce_conn_p
*/
return NT_STATUS_OK;
}
/*
disconnect a link to an endpoint
*/
void dcesrv_endpoint_disconnect(struct dcesrv_state *p)
void dcesrv_endpoint_disconnect(struct dcesrv_connection *p)
{
p->ops->disconnect(p);
if (p->iface) {
p->iface->unbind(p, p->iface);
}
/* destroy any handles */
while (p->handles) {
@ -315,15 +460,16 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
return dcesrv_bind_nak(call, 0);
}
if (!call->dce->ops->set_interface(call->dce, uuid, if_version)) {
call->conn->iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version);
if (!call->conn->iface) {
DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
/* we don't know about that interface */
result = DCERPC_BIND_PROVIDER_REJECT;
reason = DCERPC_BIND_REASON_ASYNTAX;
}
if (call->dce->cli_max_recv_frag == 0) {
call->dce->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
if (call->conn->cli_max_recv_frag == 0) {
call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
}
/* handle any authentication that is being requested */
@ -340,9 +486,9 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
pkt.u.bind_ack.max_xmit_frag = 0x2000;
pkt.u.bind_ack.max_recv_frag = 0x2000;
pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
if (call->dce->ndr) {
if (call->conn->iface && call->conn->iface->ndr) {
pkt.u.bind_ack.secondary_address = talloc_asprintf(call->mem_ctx, "\\PIPE\\%s",
call->dce->ndr->name);
call->conn->iface->ndr->name);
} else {
pkt.u.bind_ack.secondary_address = "";
}
@ -361,13 +507,21 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
return dcesrv_bind_nak(call, 0);
}
if (call->conn->iface) {
status = call->conn->iface->bind(call, call->conn->iface);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(2,("Request for dcerpc interface %s/%d rejected\n", uuid, if_version));
return status;
}
}
rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
if (!rep) {
return NT_STATUS_NO_MEMORY;
}
status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt,
call->dce->auth_state.auth_info);
call->conn->auth_state.auth_info);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
@ -375,7 +529,7 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
dcerpc_set_frag_length(&rep->data, rep->data.length);
DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
DLIST_ADD_END(call->dce->call_list, call, struct dcesrv_call_state *);
DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
return NT_STATUS_OK;
}
@ -413,7 +567,7 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
opnum = call->pkt.u.request.opnum;
if (opnum >= call->dce->ndr->num_calls) {
if (opnum >= call->conn->iface->ndr->num_calls) {
return dcesrv_fault(call, DCERPC_FAULT_OP_RNG_ERROR);
}
@ -422,7 +576,7 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
return NT_STATUS_NO_MEMORY;
}
r = talloc(call->mem_ctx, call->dce->ndr->calls[opnum].struct_size);
r = talloc(call->mem_ctx, call->conn->iface->ndr->calls[opnum].struct_size);
if (!r) {
return NT_STATUS_NO_MEMORY;
}
@ -432,13 +586,13 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
}
/* unravel the NDR for the packet */
status = call->dce->ndr->calls[opnum].ndr_pull(pull, NDR_IN, r);
status = call->conn->iface->ndr->calls[opnum].ndr_pull(pull, NDR_IN, r);
if (!NT_STATUS_IS_OK(status)) {
return dcesrv_fault(call, DCERPC_FAULT_NDR);
}
/* call the dispatch function */
status = call->dce->dispatch[opnum](call->dce, call->mem_ctx, r);
status = call->conn->iface->dispatch(call, call->mem_ctx, r);
if (!NT_STATUS_IS_OK(status)) {
return dcesrv_fault_nt(call, status);
}
@ -453,7 +607,7 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
push->flags |= LIBNDR_FLAG_BIGENDIAN;
}
status = call->dce->ndr->calls[opnum].ndr_push(push, NDR_OUT, r);
status = call->conn->iface->ndr->calls[opnum].ndr_push(push, NDR_OUT, r);
if (!NT_STATUS_IS_OK(status)) {
return dcesrv_fault(call, DCERPC_FAULT_NDR);
}
@ -471,9 +625,9 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
}
length = stub.length;
if (length + DCERPC_RESPONSE_LENGTH > call->dce->cli_max_recv_frag) {
if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
/* the 32 is to cope with signing data */
length = call->dce->cli_max_recv_frag -
length = call->conn->cli_max_recv_frag -
(DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
}
@ -507,7 +661,7 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
stub.length -= length;
} while (stub.length != 0);
DLIST_ADD_END(call->dce->call_list, call, struct dcesrv_call_state *);
DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
return NT_STATUS_OK;
}
@ -530,18 +684,18 @@ static BOOL dce_full_packet(const DATA_BLOB *data)
/*
we might have consumed only part of our input - advance past that part
*/
static void dce_partial_advance(struct dcesrv_state *dce, uint32 offset)
static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32 offset)
{
DATA_BLOB blob;
if (dce->partial_input.length == offset) {
free(dce->partial_input.data);
dce->partial_input = data_blob(NULL, 0);
if (dce_conn->partial_input.length == offset) {
free(dce_conn->partial_input.data);
dce_conn->partial_input = data_blob(NULL, 0);
return;
}
blob = dce->partial_input;
dce->partial_input = data_blob(blob.data + offset,
blob = dce_conn->partial_input;
dce_conn->partial_input = data_blob(blob.data + offset,
blob.length - offset);
free(blob.data);
}
@ -549,7 +703,7 @@ static void dce_partial_advance(struct dcesrv_state *dce, uint32 offset)
/*
process some input to a dcerpc endpoint server.
*/
NTSTATUS dcesrv_input_process(struct dcesrv_state *dce)
NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
{
struct ndr_pull *ndr;
TALLOC_CTX *mem_ctx;
@ -563,20 +717,20 @@ NTSTATUS dcesrv_input_process(struct dcesrv_state *dce)
}
call = talloc_p(mem_ctx, struct dcesrv_call_state);
if (!call) {
talloc_free(dce->mem_ctx, dce->partial_input.data);
talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
talloc_destroy(mem_ctx);
return NT_STATUS_NO_MEMORY;
}
call->mem_ctx = mem_ctx;
call->dce = dce;
call->conn = dce_conn;
call->replies = NULL;
blob = dce->partial_input;
blob = dce_conn->partial_input;
blob.length = dcerpc_get_frag_length(&blob);
ndr = ndr_pull_init_blob(&blob, mem_ctx);
if (!ndr) {
talloc_free(dce->mem_ctx, dce->partial_input.data);
talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
talloc_destroy(mem_ctx);
return NT_STATUS_NO_MEMORY;
}
@ -587,12 +741,12 @@ NTSTATUS dcesrv_input_process(struct dcesrv_state *dce)
status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(dce->mem_ctx, dce->partial_input.data);
talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
talloc_destroy(mem_ctx);
return status;
}
dce_partial_advance(dce, blob.length);
dce_partial_advance(dce_conn, blob.length);
/* we have to check the signing here, before combining the
pdus */
@ -613,7 +767,7 @@ NTSTATUS dcesrv_input_process(struct dcesrv_state *dce)
/* this is a continuation of an existing call - find the call then
tack it on the end */
call = dcesrv_find_call(dce, call2->pkt.call_id);
call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
if (!call) {
return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
}
@ -648,7 +802,7 @@ NTSTATUS dcesrv_input_process(struct dcesrv_state *dce)
/* this may not be the last pdu in the chain - if its isn't then
just put it on the call_list and wait for the rest */
if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
DLIST_ADD_END(dce->call_list, call, struct dcesrv_call_state *);
DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
return NT_STATUS_OK;
}
@ -682,21 +836,21 @@ NTSTATUS dcesrv_input_process(struct dcesrv_state *dce)
provide some input to a dcerpc endpoint server. This passes data
from a dcerpc client into the server
*/
NTSTATUS dcesrv_input(struct dcesrv_state *dce, const DATA_BLOB *data)
NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
{
NTSTATUS status;
dce->partial_input.data = Realloc(dce->partial_input.data,
dce->partial_input.length + data->length);
if (!dce->partial_input.data) {
dce_conn->partial_input.data = Realloc(dce_conn->partial_input.data,
dce_conn->partial_input.length + data->length);
if (!dce_conn->partial_input.data) {
return NT_STATUS_NO_MEMORY;
}
memcpy(dce->partial_input.data + dce->partial_input.length,
memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
data->data, data->length);
dce->partial_input.length += data->length;
dce_conn->partial_input.length += data->length;
while (dce_full_packet(&dce->partial_input)) {
status = dcesrv_input_process(dce);
while (dce_full_packet(&dce_conn->partial_input)) {
status = dcesrv_input_process(dce_conn);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
@ -710,12 +864,12 @@ NTSTATUS dcesrv_input(struct dcesrv_state *dce, const DATA_BLOB *data)
is wanted is in data->length and data->data is already allocated
to hold that much data.
*/
NTSTATUS dcesrv_output(struct dcesrv_state *dce, DATA_BLOB *data)
NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn, DATA_BLOB *data)
{
struct dcesrv_call_state *call;
struct dcesrv_call_reply *rep;
call = dce->call_list;
call = dce_conn->call_list;
if (!call || !call->replies) {
return NT_STATUS_FOOBAR;
}
@ -736,88 +890,151 @@ NTSTATUS dcesrv_output(struct dcesrv_state *dce, DATA_BLOB *data)
if (call->replies == NULL) {
/* we're done with the whole call */
DLIST_REMOVE(dce->call_list, call);
DLIST_REMOVE(dce_conn->call_list, call);
talloc_destroy(call->mem_ctx);
}
return NT_STATUS_OK;
}
/*
a useful function for implementing the query endpoint op
initialise the dcerpc server context
*/
BOOL dcesrv_table_query(const struct dcerpc_interface_table *table,
const struct dcesrv_endpoint *ep)
NTSTATUS dcesrv_init_context(struct dcesrv_context *dce_ctx)
{
int i;
const struct dcerpc_endpoint_list *endpoints = table->endpoints;
const char **endpoint_servers = lp_dcerpc_endpoint_servers();
if (ep->type != ENDPOINT_SMB) {
return False;
dce_ctx->mem_ctx = talloc_init("struct dcesrv_context");
if (!dce_ctx->mem_ctx) {
DEBUG(3,("dcesrv_init_context: talloc_init failed\n"));
return NT_STATUS_NO_MEMORY;
}
for (i=0;i<endpoints->count;i++) {
if (strcasecmp(ep->info.smb_pipe, endpoints->names[i]) == 0) {
return True;
}
}
return False;
dce_ctx->endpoint_list = NULL;
if (!endpoint_servers) {
DEBUG(3,("dcesrv_init_context: no endpoint servers configured\n"));
return NT_STATUS_OK;
}
for (i=0;endpoint_servers[i];i++) {
NTSTATUS ret;
const struct dcesrv_endpoint_server *ep_server;
ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
if (!ep_server) {
DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
return NT_STATUS_UNSUCCESSFUL;
}
ret = ep_server->init_server(dce_ctx, ep_server);
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
return ret;
}
}
return NT_STATUS_OK;
}
/* the list of currently registered DCERPC endpoint servers.
*/
static struct {
struct dcesrv_endpoint_server *ep_server;
} *ep_servers = NULL;
static int num_ep_servers;
/*
a useful function for implementing the lookup_endpoints op
register a DCERPC endpoint server.
The 'name' can be later used by other backends to find the operations
structure for this backend.
The 'type' is used to specify whether this is for a disk, printer or IPC$ share
*/
int dcesrv_lookup_endpoints(const struct dcerpc_interface_table *table,
TALLOC_CTX *mem_ctx,
struct dcesrv_ep_iface **e)
static NTSTATUS decrpc_register_ep_server(void *_ep_server)
{
const struct dcesrv_endpoint_server *ep_server = _ep_server;
if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
/* its already registered! */
DEBUG(1,("DCERPC endpoint server '%s' already registered\n",
ep_server->name));
return NT_STATUS_OBJECT_NAME_COLLISION;
}
ep_servers = Realloc(ep_servers, sizeof(ep_servers[0]) * (num_ep_servers+1));
if (!ep_servers) {
smb_panic("out of memory in decrpc_register");
}
ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
num_ep_servers++;
DEBUG(1,("DCERPC module '%s' registered\n",
ep_server->name));
return NT_STATUS_OK;
}
/*
return the operations structure for a named backend of the specified type
*/
const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
{
int i;
*e = talloc_array_p(mem_ctx, struct dcesrv_ep_iface, table->endpoints->count);
if (! *e) {
return -1;
}
for (i=0;i<table->endpoints->count;i++) {
(*e)[i].name = table->name;
(*e)[i].uuid = table->uuid;
(*e)[i].if_version = table->if_version;
if (strncmp(table->endpoints->names[i], "TCP-", 4) == 0) {
(*e)[i].endpoint.type = ENDPOINT_TCP;
(*e)[i].endpoint.info.tcp_port = atoi(table->endpoints->names[i]+4);
} else {
(*e)[i].endpoint.type = ENDPOINT_SMB;
(*e)[i].endpoint.info.smb_pipe = table->endpoints->names[i];
for (i=0;i<num_ep_servers;i++) {
if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
return ep_servers[i].ep_server;
}
}
return i;
return NULL;
}
BOOL dcesrv_set_interface(struct dcesrv_state *dce,
const char *uuid, uint32 if_version,
const struct dcerpc_interface_table *table,
const dcesrv_dispatch_fn_t *dispatch_table)
/*
return the DCERPC module version, and the size of some critical types
This can be used by endpoint server modules to either detect compilation errors, or provide
multiple implementations for different smbd compilation options in one module
*/
const struct dcesrv_critical_sizes *dcerpc_module_version(void)
{
if (strcasecmp(table->uuid, uuid) != 0 || if_version != table->if_version) {
DEBUG(2,("Attempt to use unknown interface %s/%d\n", uuid, if_version));
static const struct dcesrv_critical_sizes critical_sizes = {
DCERPC_MODULE_VERSION,
sizeof(struct dcesrv_context),
sizeof(struct dcesrv_endpoint),
sizeof(struct dcesrv_endpoint_server),
sizeof(struct dcesrv_ep_description),
sizeof(struct dcesrv_interface),
sizeof(struct dcesrv_if_list),
sizeof(struct dcesrv_connection),
sizeof(struct dcesrv_call_state),
sizeof(struct dcesrv_auth),
sizeof(struct dcesrv_handle)
};
return &critical_sizes;
}
/*
initialise the DCERPC subsystem
*/
BOOL dcesrv_init(void)
{
NTSTATUS status;
status = register_subsystem("dcerpc", decrpc_register_ep_server);
if (!NT_STATUS_IS_OK(status)) {
return False;
}
dce->ndr = table;
dce->dispatch = dispatch_table;
return True;
}
/*
initialise the dcerpc server subsystem
*/
BOOL dcesrv_init(struct dcesrv_context *dce)
{
rpc_rpcecho_init(dce);
rpc_epmapper_init(dce);
/* FIXME: Perhaps panic if a basic endpoint server, such as EPMAPER, fails to initialise? */
static_init_dcerpc;
DEBUG(1,("DCERPC subsystem version %d initialised\n", DCERPC_MODULE_VERSION));
return True;
}

View File

@ -4,6 +4,7 @@
server side dcerpc defines
Copyright (C) Andrew Tridgell 2003
Copyright (C) Stefan (metze) Metzmacher 2004
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
@ -20,12 +21,18 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* modules can use the following to determine if the interface has changed
* please increment the version number after each interface change
* with a comment and maybe update struct dcesrv_critical_sizes.
*/
/* version 1 - initial version - metze */
#define DCERPC_MODULE_VERSION 1
enum endpoint_type {ENDPOINT_SMB, ENDPOINT_TCP};
/* a description of a single dcerpc endpoint. Not as flexible as a full epm tower,
but much easier to work with */
struct dcesrv_endpoint {
struct dcesrv_ep_description {
enum endpoint_type type;
union {
const char *smb_pipe;
@ -33,23 +40,31 @@ struct dcesrv_endpoint {
} info;
};
/* a endpoint combined with an interface description */
struct dcesrv_ep_iface {
const char *name;
struct dcesrv_endpoint endpoint;
const char *uuid;
uint32 if_version;
};
struct dcesrv_state;
struct dcesrv_connection;
struct dcesrv_call_state;
/* the dispatch functions for an interface take this form */
typedef NTSTATUS (*dcesrv_dispatch_fn_t)(struct dcesrv_state *, TALLOC_CTX *, void *);
typedef NTSTATUS (*dcesrv_dispatch_fn_t)(struct dcesrv_call_state *, TALLOC_CTX *, void *);
struct dcesrv_interface {
/* the ndr function table for the chosen interface */
const struct dcerpc_interface_table *ndr;
/* this function is called when the client binds to this interface */
NTSTATUS (*bind)(struct dcesrv_call_state *, const struct dcesrv_interface *);
/* this function is called when the client disconnects the endpoint */
void (*unbind)(struct dcesrv_connection *, const struct dcesrv_interface *);
/* the dispatch function for the chosen interface.
*/
dcesrv_dispatch_fn_t dispatch;
};
/* the state of an ongoing dcerpc call */
struct dcesrv_call_state {
struct dcesrv_call_state *next, *prev;
struct dcesrv_state *dce;
struct dcesrv_connection *conn;
TALLOC_CTX *mem_ctx;
struct dcerpc_packet pkt;
@ -78,24 +93,17 @@ struct dcesrv_auth {
/* the state associated with a dcerpc server connection */
struct dcesrv_state {
struct dcesrv_connection {
/* the top level context for this server */
struct dcesrv_context *dce;
struct dcesrv_context *dce_ctx;
TALLOC_CTX *mem_ctx;
/* the endpoint that was opened */
struct dcesrv_endpoint endpoint;
/* endpoint operations provided by the endpoint server */
const struct dcesrv_endpoint_ops *ops;
const struct dcesrv_endpoint *endpoint;
/* the ndr function table for the chosen interface */
const struct dcerpc_interface_table *ndr;
/* the dispatch table for the chosen interface. Must contain
enough entries for all entries in the ndr table */
const dcesrv_dispatch_fn_t *dispatch;
const struct dcesrv_interface *iface;
/* the state of the current calls */
struct dcesrv_call_state *call_list;
@ -103,7 +111,7 @@ struct dcesrv_state {
/* the maximum size the client wants to receive */
uint32 cli_max_recv_frag;
/* private data for the endpoint server */
/* private data for the interface implementation */
void *private;
/* current rpc handles - this is really the wrong scope for
@ -117,34 +125,61 @@ struct dcesrv_state {
};
struct dcesrv_endpoint_ops {
/* this function is used to ask an endpoint server if it
handles a particular endpoint */
BOOL (*query_endpoint)(const struct dcesrv_endpoint *);
struct dcesrv_endpoint_server {
/* this is the name of the endpoint server */
const char *name;
/* this function sets up the dispatch table for this
connection */
BOOL (*set_interface)(struct dcesrv_state *, const char *, uint32);
/* this function should register endpoints and some other setup stuff,
* it is called when the dcesrv_context gets initialized.
*/
NTSTATUS (*init_server)(struct dcesrv_context *, const struct dcesrv_endpoint_server *);
/* connect() is called when a connection is made to an endpoint */
NTSTATUS (*connect)(struct dcesrv_state *);
/* this function can be used by other endpoint servers to
* ask for a dcesrv_interface implementation
* - iface must be referenz to an allready existent struct !
*/
BOOL (*interface_by_uuid)(struct dcesrv_interface *iface, const char *, uint32);
/* disconnect() is called when the endpoint is disconnected */
void (*disconnect)(struct dcesrv_state *);
/* this function is used to ask an endpoint server for a list
of endpoints/interfaces it wants to handle */
int (*lookup_endpoints)(TALLOC_CTX *mem_ctx, struct dcesrv_ep_iface **);
/* this function can be used by other endpoint servers to
* ask for a dcesrv_interface implementation
* - iface must be referenz to an allready existent struct !
*/
BOOL (*interface_by_name)(struct dcesrv_interface *iface, const char *);
};
/* server-wide context information for the dcerpc server */
struct dcesrv_context {
TALLOC_CTX *mem_ctx;
/* the list of endpoints servers that have registered */
struct dce_endpoint {
struct dce_endpoint *next, *prev;
struct dcesrv_endpoint endpoint;
const struct dcesrv_endpoint_ops *endpoint_ops;
/* the list of endpoints that have registered
* by the configured endpoint servers
*/
struct dcesrv_endpoint {
struct dcesrv_endpoint *next, *prev;
/* the type and location of the endpoint */
struct dcesrv_ep_description ep_description;
/* the security descriptor for smb named pipes */
struct security_descriptor *sd;
/* the list of interfaces available on this endpoint */
struct dcesrv_if_list {
struct dcesrv_if_list *next, *prev;
struct dcesrv_interface iface;
} *interface_list;
} *endpoint_list;
};
/* this structure is used by modules to determine the size of some critical types */
struct dcesrv_critical_sizes {
int interface_version;
int sizeof_dcesrv_context;
int sizeof_dcesrv_endpoint;
int sizeof_dcesrv_endpoint_server;
int sizeof_dcesrv_ep_description;
int sizeof_dcesrv_interface;
int sizeof_dcesrv_if_list;
int sizeof_dcesrv_connection;
int sizeof_dcesrv_call_state;
int sizeof_dcesrv_auth;
int sizeof_dcesrv_handle;
};

View File

@ -4,6 +4,7 @@
server side dcerpc over tcp code
Copyright (C) Andrew Tridgell 2003
Copyright (C) Stefan (metze) Metzmacher 2004
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
@ -23,10 +24,10 @@
#include "includes.h"
struct rpc_server_context {
struct dcesrv_endpoint *endpoint;
const struct dcesrv_endpoint_ops *endpoint_ops;
struct dcesrv_ep_description *ep_description;
const struct dcesrv_endpoint *endpoint;
const struct model_ops *model_ops;
struct dcesrv_state *dce;
struct dcesrv_connection *dce_conn;
struct dcesrv_context dcesrv_context;
int socket_fd;
struct event_context *events;
@ -39,7 +40,7 @@ void rpc_server_terminate(void *rr)
{
struct rpc_server_context *r = rr;
dcesrv_endpoint_disconnect(r->dce);
dcesrv_endpoint_disconnect(r->dce_conn);
close(r->socket_fd);
event_remove_fd_all(r->events, r->socket_fd);
free(r);
@ -69,13 +70,13 @@ static void dcerpc_write_handler(struct event_context *ev, struct fd_event *fde,
return;
}
status = dcesrv_output(r->dce, &blob);
status = dcesrv_output(r->dce_conn, &blob);
if (NT_STATUS_IS_OK(status)) {
write_data(fde->fd, blob.data, blob.length);
}
if (!r->dce->call_list || !r->dce->call_list->replies) {
if (!r->dce_conn->call_list || !r->dce_conn->call_list->replies) {
fde->flags &= ~EVENT_FD_WRITE;
}
@ -111,11 +112,11 @@ static void dcerpc_read_handler(struct event_context *ev, struct fd_event *fde,
blob.length = ret;
dcesrv_input(r->dce, &blob);
dcesrv_input(r->dce_conn, &blob);
data_blob_free(&blob);
if (r->dce->call_list && r->dce->call_list->replies) {
if (r->dce_conn->call_list && r->dce_conn->call_list->replies) {
fde->flags |= EVENT_FD_WRITE;
}
}
@ -146,6 +147,7 @@ void init_rpc_session(struct event_context *ev, void *private, int fd)
{
struct fd_event fde;
struct rpc_server_context *r = private;
NTSTATUS status;
r = memdup(r, sizeof(struct rpc_server_context));
@ -155,9 +157,16 @@ void init_rpc_session(struct event_context *ev, void *private, int fd)
set_socket_options(fd,"SO_KEEPALIVE");
set_socket_options(fd, lp_socket_options());
dcesrv_endpoint_connect_ops(&r->dcesrv_context, r->endpoint, r->endpoint_ops, &r->dce);
status = dcesrv_endpoint_connect(&r->dcesrv_context, r->endpoint, &r->dce_conn);
if (!NT_STATUS_IS_OK(status)) {
close(fd);
free(r);
DEBUG(0,("init_rpc_session: connection to endpoint failed: %s\n",
nt_errstr(status)));
return;
}
r->dce->dce = &r->dcesrv_context;
r->dce_conn->dce_ctx = &r->dcesrv_context;
set_blocking(fd, False);
@ -179,7 +188,7 @@ static void setup_listen_rpc(struct event_context *events,
struct model_ops *model_ops,
struct in_addr *ifip, uint32 *port,
struct rpc_server_context *r,
const struct dcesrv_endpoint_ops *endpoint_ops)
const struct dcesrv_endpoint *endpoint)
{
struct fd_event fde;
int i;
@ -209,14 +218,14 @@ static void setup_listen_rpc(struct event_context *events,
smb_panic("out of memory");
}
r->endpoint_ops = endpoint_ops;
r->endpoint = malloc(sizeof(struct dcesrv_endpoint));
if (!r->endpoint) {
r->ep_description = malloc(sizeof(struct dcesrv_ep_description));
if (!r->ep_description) {
smb_panic("out of memory");
}
r->endpoint->type = ENDPOINT_TCP;
r->endpoint->info.tcp_port = *port;
r->ep_description->type = ENDPOINT_TCP;
r->ep_description->info.tcp_port = *port;
r->endpoint = endpoint;
/* ready to listen */
set_socket_options(fde.fd, "SO_KEEPALIVE");
@ -244,7 +253,7 @@ static void add_socket_rpc(struct event_context *events,
struct model_ops *model_ops,
struct in_addr *ifip)
{
struct dce_endpoint *e;
struct dcesrv_endpoint *e;
struct rpc_server_context *r;
r = malloc(sizeof(struct rpc_server_context));
@ -253,18 +262,18 @@ static void add_socket_rpc(struct event_context *events,
}
r->dcesrv_context.endpoint_list = NULL;
dcesrv_init(&r->dcesrv_context);
r->endpoint = NULL;
dcesrv_init_context(&r->dcesrv_context);
r->ep_description = NULL;
r->model_ops = model_ops;
r->dce = NULL;
r->dce_conn = NULL;
r->socket_fd = -1;
r->events = NULL;
for (e=r->dcesrv_context.endpoint_list;e;e=e->next) {
if (e->endpoint.type == ENDPOINT_TCP) {
if (e->ep_description.type == ENDPOINT_TCP) {
setup_listen_rpc(events, model_ops, ifip,
&e->endpoint.info.tcp_port,
r, e->endpoint_ops);
&e->ep_description.info.tcp_port,
r, e);
}
}

View File

@ -31,40 +31,40 @@
BOOL dcesrv_auth_bind(struct dcesrv_call_state *call)
{
struct dcerpc_packet *pkt = &call->pkt;
struct dcesrv_state *dce = call->dce;
struct dcesrv_connection *dce_conn = call->conn;
NTSTATUS status;
if (pkt->u.bind.auth_info.length == 0) {
dce->auth_state.auth_info = NULL;
dce_conn->auth_state.auth_info = NULL;
return True;
}
dce->auth_state.auth_info = talloc_p(dce->mem_ctx, struct dcerpc_auth);
if (!dce->auth_state.auth_info) {
dce_conn->auth_state.auth_info = talloc_p(dce_conn->mem_ctx, struct dcerpc_auth);
if (!dce_conn->auth_state.auth_info) {
return False;
}
status = ndr_pull_struct_blob(&pkt->u.bind.auth_info,
call->mem_ctx,
dce->auth_state.auth_info,
dce_conn->auth_state.auth_info,
(ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
if (!NT_STATUS_IS_OK(status)) {
return False;
}
if (dce->auth_state.auth_info->auth_type != DCERPC_AUTH_TYPE_NTLMSSP) {
if (dce_conn->auth_state.auth_info->auth_type != DCERPC_AUTH_TYPE_NTLMSSP) {
/* only do NTLMSSP for now */
DEBUG(2,("auth_type %d not supported\n", dce->auth_state.auth_info->auth_type));
DEBUG(2,("auth_type %d not supported\n", dce_conn->auth_state.auth_info->auth_type));
return False;
}
if (dce->auth_state.auth_info->auth_level != DCERPC_AUTH_LEVEL_INTEGRITY &&
dce->auth_state.auth_info->auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
DEBUG(2,("auth_level %d not supported\n", dce->auth_state.auth_info->auth_level));
if (dce_conn->auth_state.auth_info->auth_level != DCERPC_AUTH_LEVEL_INTEGRITY &&
dce_conn->auth_state.auth_info->auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
DEBUG(2,("auth_level %d not supported\n", dce_conn->auth_state.auth_info->auth_level));
return False;
}
status = auth_ntlmssp_start(&dce->auth_state.ntlmssp_state);
status = auth_ntlmssp_start(&dce_conn->auth_state.ntlmssp_state);
if (!NT_STATUS_IS_OK(status)) {
return False;
}
@ -77,23 +77,23 @@ BOOL dcesrv_auth_bind(struct dcesrv_call_state *call)
*/
BOOL dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct dcerpc_packet *pkt)
{
struct dcesrv_state *dce = call->dce;
struct dcesrv_connection *dce_conn = call->conn;
NTSTATUS status;
if (!call->dce->auth_state.ntlmssp_state) {
if (!call->conn->auth_state.ntlmssp_state) {
return True;
}
status = auth_ntlmssp_update(dce->auth_state.ntlmssp_state,
dce->auth_state.auth_info->credentials,
&dce->auth_state.auth_info->credentials);
status = auth_ntlmssp_update(dce_conn->auth_state.ntlmssp_state,
dce_conn->auth_state.auth_info->credentials,
&dce_conn->auth_state.auth_info->credentials);
if (!NT_STATUS_IS_OK(status) &&
!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
return False;
}
dce->auth_state.auth_info->auth_pad_length = 0;
dce->auth_state.auth_info->auth_reserved = 0;
dce_conn->auth_state.auth_info->auth_pad_length = 0;
dce_conn->auth_state.auth_info->auth_reserved = 0;
return True;
}
@ -105,43 +105,43 @@ BOOL dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct dcerpc_packet *
BOOL dcesrv_auth_auth3(struct dcesrv_call_state *call)
{
struct dcerpc_packet *pkt = &call->pkt;
struct dcesrv_state *dce = call->dce;
struct dcesrv_connection *dce_conn = call->conn;
NTSTATUS status;
if (!dce->auth_state.auth_info ||
!dce->auth_state.ntlmssp_state ||
if (!dce_conn->auth_state.auth_info ||
!dce_conn->auth_state.ntlmssp_state ||
pkt->u.auth.auth_info.length == 0) {
return False;
}
status = ndr_pull_struct_blob(&pkt->u.auth.auth_info,
call->mem_ctx,
dce->auth_state.auth_info,
dce_conn->auth_state.auth_info,
(ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
if (!NT_STATUS_IS_OK(status)) {
return False;
}
if (dce->auth_state.auth_info->auth_type != DCERPC_AUTH_TYPE_NTLMSSP) {
if (dce_conn->auth_state.auth_info->auth_type != DCERPC_AUTH_TYPE_NTLMSSP) {
return False;
}
if (dce->auth_state.auth_info->auth_level != DCERPC_AUTH_LEVEL_INTEGRITY &&
dce->auth_state.auth_info->auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
if (dce_conn->auth_state.auth_info->auth_level != DCERPC_AUTH_LEVEL_INTEGRITY &&
dce_conn->auth_state.auth_info->auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
return False;
}
status = auth_ntlmssp_update(dce->auth_state.ntlmssp_state,
dce->auth_state.auth_info->credentials,
&dce->auth_state.auth_info->credentials);
status = auth_ntlmssp_update(dce_conn->auth_state.ntlmssp_state,
dce_conn->auth_state.auth_info->credentials,
&dce_conn->auth_state.auth_info->credentials);
if (!NT_STATUS_IS_OK(status)) {
return False;
}
switch (dce->auth_state.auth_info->auth_level) {
switch (dce_conn->auth_state.auth_info->auth_level) {
case DCERPC_AUTH_LEVEL_PRIVACY:
case DCERPC_AUTH_LEVEL_INTEGRITY:
/* setup for signing */
status = ntlmssp_sign_init(dce->auth_state.ntlmssp_state->ntlmssp_state);
status = ntlmssp_sign_init(dce_conn->auth_state.ntlmssp_state->ntlmssp_state);
break;
}
@ -155,14 +155,14 @@ BOOL dcesrv_auth_auth3(struct dcesrv_call_state *call)
BOOL dcesrv_auth_request(struct dcesrv_call_state *call)
{
struct dcerpc_packet *pkt = &call->pkt;
struct dcesrv_state *dce = call->dce;
struct dcesrv_connection *dce_conn = call->conn;
DATA_BLOB auth_blob;
struct dcerpc_auth auth;
struct ndr_pull *ndr;
NTSTATUS status;
if (!dce->auth_state.auth_info ||
!dce->auth_state.ntlmssp_state) {
if (!dce_conn->auth_state.auth_info ||
!dce_conn->auth_state.ntlmssp_state) {
return True;
}
@ -194,16 +194,16 @@ BOOL dcesrv_auth_request(struct dcesrv_call_state *call)
}
/* check signature or unseal the packet */
switch (dce->auth_state.auth_info->auth_level) {
switch (dce_conn->auth_state.auth_info->auth_level) {
case DCERPC_AUTH_LEVEL_PRIVACY:
status = ntlmssp_unseal_packet(dce->auth_state.ntlmssp_state->ntlmssp_state,
status = ntlmssp_unseal_packet(dce_conn->auth_state.ntlmssp_state->ntlmssp_state,
pkt->u.request.stub_and_verifier.data,
pkt->u.request.stub_and_verifier.length,
&auth.credentials);
break;
case DCERPC_AUTH_LEVEL_INTEGRITY:
status = ntlmssp_check_packet(dce->auth_state.ntlmssp_state->ntlmssp_state,
status = ntlmssp_check_packet(dce_conn->auth_state.ntlmssp_state->ntlmssp_state,
pkt->u.request.stub_and_verifier.data,
pkt->u.request.stub_and_verifier.length,
&auth.credentials);
@ -230,12 +230,12 @@ BOOL dcesrv_auth_request(struct dcesrv_call_state *call)
BOOL dcesrv_auth_response(struct dcesrv_call_state *call,
DATA_BLOB *blob, struct dcerpc_packet *pkt)
{
struct dcesrv_state *dce = call->dce;
struct dcesrv_connection *dce_conn = call->conn;
NTSTATUS status;
struct ndr_push *ndr;
/* non-signed packets are simple */
if (!dce->auth_state.auth_info || !dce->auth_state.ntlmssp_state) {
if (!dce_conn->auth_state.auth_info || !dce_conn->auth_state.ntlmssp_state) {
status = dcerpc_push_auth(blob, call->mem_ctx, pkt, NULL);
return NT_STATUS_IS_OK(status);
}
@ -255,23 +255,23 @@ BOOL dcesrv_auth_response(struct dcesrv_call_state *call,
}
/* pad to 8 byte multiple */
dce->auth_state.auth_info->auth_pad_length = NDR_ALIGN(ndr, 8);
ndr_push_zero(ndr, dce->auth_state.auth_info->auth_pad_length);
dce_conn->auth_state.auth_info->auth_pad_length = NDR_ALIGN(ndr, 8);
ndr_push_zero(ndr, dce_conn->auth_state.auth_info->auth_pad_length);
/* sign or seal the packet */
switch (dce->auth_state.auth_info->auth_level) {
switch (dce_conn->auth_state.auth_info->auth_level) {
case DCERPC_AUTH_LEVEL_PRIVACY:
status = ntlmssp_seal_packet(dce->auth_state.ntlmssp_state->ntlmssp_state,
status = ntlmssp_seal_packet(dce_conn->auth_state.ntlmssp_state->ntlmssp_state,
ndr->data + DCERPC_REQUEST_LENGTH,
ndr->offset - DCERPC_REQUEST_LENGTH,
&dce->auth_state.auth_info->credentials);
&dce_conn->auth_state.auth_info->credentials);
break;
case DCERPC_AUTH_LEVEL_INTEGRITY:
status = ntlmssp_sign_packet(dce->auth_state.ntlmssp_state->ntlmssp_state,
status = ntlmssp_sign_packet(dce_conn->auth_state.ntlmssp_state->ntlmssp_state,
ndr->data + DCERPC_REQUEST_LENGTH,
ndr->offset - DCERPC_REQUEST_LENGTH,
&dce->auth_state.auth_info->credentials);
&dce_conn->auth_state.auth_info->credentials);
break;
default:
status = NT_STATUS_INVALID_LEVEL;
@ -283,7 +283,7 @@ BOOL dcesrv_auth_response(struct dcesrv_call_state *call,
}
/* add the auth verifier */
status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, dce->auth_state.auth_info);
status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, dce_conn->auth_state.auth_info);
if (!NT_STATUS_IS_OK(status)) {
return False;
}
@ -295,9 +295,9 @@ BOOL dcesrv_auth_response(struct dcesrv_call_state *call,
in these earlier as we don't know the signature length (it
could be variable length) */
dcerpc_set_frag_length(blob, blob->length);
dcerpc_set_auth_length(blob, dce->auth_state.auth_info->credentials.length);
dcerpc_set_auth_length(blob, dce_conn->auth_state.auth_info->credentials.length);
data_blob_free(&dce->auth_state.auth_info->credentials);
data_blob_free(&dce_conn->auth_state.auth_info->credentials);
return True;
}

View File

@ -23,13 +23,13 @@
#include "includes.h"
static NTSTATUS echo_AddOne(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx, struct echo_AddOne *r)
static NTSTATUS echo_AddOne(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct echo_AddOne *r)
{
*r->out.v = *r->in.v + 1;
return NT_STATUS_OK;
}
static NTSTATUS echo_EchoData(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx, struct echo_EchoData *r)
static NTSTATUS echo_EchoData(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct echo_EchoData *r)
{
if (!r->in.len) {
return NT_STATUS_OK;
@ -44,12 +44,12 @@ static NTSTATUS echo_EchoData(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx, str
return NT_STATUS_OK;
}
static NTSTATUS echo_SinkData(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx, struct echo_SinkData *r)
static NTSTATUS echo_SinkData(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct echo_SinkData *r)
{
return NT_STATUS_OK;
}
static NTSTATUS echo_SourceData(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx, struct echo_SourceData *r)
static NTSTATUS echo_SourceData(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct echo_SourceData *r)
{
int i;
for (i=0;i<r->in.len;i++) {
@ -59,14 +59,14 @@ static NTSTATUS echo_SourceData(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx, s
return NT_STATUS_OK;
}
static NTSTATUS echo_TestCall(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx, struct echo_TestCall *r)
static NTSTATUS echo_TestCall(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct echo_TestCall *r)
{
r->out.s2 = "this is a test string";
return NT_STATUS_OK;
}
static NTSTATUS echo_TestCall2(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx, struct echo_TestCall2 *r)
static NTSTATUS echo_TestCall2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct echo_TestCall2 *r)
{
r->out.info = talloc(mem_ctx, sizeof(*r->out.info));
if (!r->out.info) {

View File

@ -26,6 +26,13 @@
/* handle types for this module */
enum handle_types {HTYPE_LOOKUP};
/* a endpoint combined with an interface description */
struct dcesrv_ep_iface {
const char *name;
struct dcesrv_ep_description ep_description;
const char *uuid;
uint32 if_version;
};
/*
simple routine to compare a GUID string to a GUID structure
@ -67,13 +74,13 @@ static BOOL fill_protocol_tower(TALLOC_CTX *mem_ctx, struct epm_towers *twr,
twr->floors[2].lhs.info.lhs_data = data_blob(NULL, 0);
twr->floors[2].rhs.rhs_data = data_blob_talloc_zero(mem_ctx, 2);
switch (e->endpoint.type) {
switch (e->ep_description.type) {
case ENDPOINT_SMB:
/* on a SMB pipe ... */
twr->floors[3].lhs.protocol = EPM_PROTOCOL_SMB;
twr->floors[3].lhs.info.lhs_data = data_blob(NULL, 0);
twr->floors[3].rhs.rhs_data.data = talloc_asprintf(mem_ctx, "\\PIPE\\%s",
e->endpoint.info.smb_pipe);
e->ep_description.info.smb_pipe);
twr->floors[3].rhs.rhs_data.length = strlen(twr->floors[3].rhs.rhs_data.data)+1;
/* on an NetBIOS link ... */
@ -89,7 +96,7 @@ static BOOL fill_protocol_tower(TALLOC_CTX *mem_ctx, struct epm_towers *twr,
twr->floors[3].lhs.protocol = EPM_PROTOCOL_TCP;
twr->floors[3].lhs.info.lhs_data = data_blob(NULL, 0);
twr->floors[3].rhs.rhs_data = data_blob_talloc(mem_ctx, NULL, 2);
RSSVAL(twr->floors[3].rhs.rhs_data.data, 0, e->endpoint.info.tcp_port);
RSSVAL(twr->floors[3].rhs.rhs_data.data, 0, e->ep_description.info.tcp_port);
/* on an IP link ... */
twr->floors[4].lhs.protocol = EPM_PROTOCOL_IP;
@ -106,44 +113,26 @@ static BOOL fill_protocol_tower(TALLOC_CTX *mem_ctx, struct epm_towers *twr,
build a list of all interfaces handled by all endpoint servers
*/
static uint32 build_ep_list(TALLOC_CTX *mem_ctx,
struct dce_endpoint *endpoint_list,
struct dcesrv_endpoint *endpoint_list,
struct dcesrv_ep_iface **eps)
{
struct dce_endpoint *d;
uint32 total = 0;
(*eps) = NULL;
for (d=endpoint_list; d; d=d->next) {
struct dcesrv_ep_iface *e;
int count = d->endpoint_ops->lookup_endpoints(mem_ctx, &e);
if (count > 0) {
int i;
for (i=0;i<count;i++) {
e[i].endpoint = d->endpoint;
}
(*eps) = talloc_realloc_p(mem_ctx, *eps,
struct dcesrv_ep_iface,
total + count);
if (!*eps) {
return 0;
}
memcpy((*eps) + total, e, sizeof(*e) * count);
total += count;
}
}
/* TODO */
return total;
}
static NTSTATUS epm_Insert(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx,
static NTSTATUS epm_Insert(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct epm_Insert *r)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS epm_Delete(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx,
static NTSTATUS epm_Delete(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct epm_Delete *r)
{
return NT_STATUS_NOT_IMPLEMENTED;
@ -154,7 +143,7 @@ static NTSTATUS epm_Delete(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx,
implement epm_Lookup. This call is used to enumerate the interfaces
available on a rpc server
*/
static NTSTATUS epm_Lookup(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx,
static NTSTATUS epm_Lookup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct epm_Lookup *r)
{
struct dcesrv_handle *h;
@ -165,7 +154,7 @@ static NTSTATUS epm_Lookup(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx,
uint32 num_ents;
int i;
h = dcesrv_handle_fetch(dce, r->in.entry_handle, HTYPE_LOOKUP);
h = dcesrv_handle_fetch(dce_call->conn, r->in.entry_handle, HTYPE_LOOKUP);
if (!h) {
return NT_STATUS_INVALID_HANDLE;
}
@ -181,7 +170,7 @@ static NTSTATUS epm_Lookup(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx,
}
h->data = eps;
eps->count = build_ep_list(h->mem_ctx, dce->dce->endpoint_list, &eps->e);
eps->count = build_ep_list(h->mem_ctx, dce_call->conn->dce_ctx->endpoint_list, &eps->e);
}
/* return the next N elements */
@ -198,7 +187,7 @@ static NTSTATUS epm_Lookup(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx,
r->out.entries = NULL;
r->out.status = EPMAPPER_STATUS_NO_MORE_ENTRIES;
ZERO_STRUCTP(r->out.entry_handle);
dcesrv_handle_destroy(dce, h);
dcesrv_handle_destroy(dce_call->conn, h);
return NT_STATUS_OK;
}
@ -231,7 +220,7 @@ static NTSTATUS epm_Lookup(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx,
implement epm_Map. This is used to find the specific endpoint to talk to given
a generic protocol tower
*/
static NTSTATUS epm_Map(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx,
static NTSTATUS epm_Map(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct epm_Map *r)
{
uint32 count;
@ -239,7 +228,7 @@ static NTSTATUS epm_Map(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx,
struct dcesrv_ep_iface *eps;
struct epm_floor *floors;
count = build_ep_list(mem_ctx, dce->dce->endpoint_list, &eps);
count = build_ep_list(mem_ctx, dce_call->conn->dce_ctx->endpoint_list, &eps);
ZERO_STRUCTP(r->out.entry_handle);
r->out.num_towers = 1;
@ -273,7 +262,7 @@ static NTSTATUS epm_Map(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx,
floors[0].lhs.info.uuid.version != eps[i].if_version) {
continue;
}
switch (eps[i].endpoint.type) {
switch (eps[i].ep_description.type) {
case ENDPOINT_SMB:
if (floors[3].lhs.protocol != EPM_PROTOCOL_SMB ||
floors[4].lhs.protocol != EPM_PROTOCOL_NETBIOS) {
@ -300,19 +289,19 @@ failed:
return NT_STATUS_OK;
}
static NTSTATUS epm_LookupHandleFree(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx,
static NTSTATUS epm_LookupHandleFree(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct epm_LookupHandleFree *r)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS epm_InqObject(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx,
static NTSTATUS epm_InqObject(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct epm_InqObject *r)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS epm_MgmtDelete(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx,
static NTSTATUS epm_MgmtDelete(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct epm_MgmtDelete *r)
{
return NT_STATUS_NOT_IMPLEMENTED;

View File

@ -25,7 +25,7 @@
/*
allocate a new rpc handle
*/
struct dcesrv_handle *dcesrv_handle_new(struct dcesrv_state *dce,
struct dcesrv_handle *dcesrv_handle_new(struct dcesrv_connection *dce_conn,
uint8 handle_type)
{
TALLOC_CTX *mem_ctx;
@ -46,7 +46,7 @@ struct dcesrv_handle *dcesrv_handle_new(struct dcesrv_state *dce,
h->wire_handle.handle_type = handle_type;
uuid_generate_random(&h->wire_handle.uuid);
DLIST_ADD(dce->handles, h);
DLIST_ADD(dce_conn->handles, h);
return h;
}
@ -54,10 +54,10 @@ struct dcesrv_handle *dcesrv_handle_new(struct dcesrv_state *dce,
/*
destroy a rpc handle
*/
void dcesrv_handle_destroy(struct dcesrv_state *dce,
void dcesrv_handle_destroy(struct dcesrv_connection *dce_conn,
struct dcesrv_handle *h)
{
DLIST_REMOVE(dce->handles, h);
DLIST_REMOVE(dce_conn->handles, h);
talloc_destroy(h->mem_ctx);
}
@ -66,17 +66,17 @@ void dcesrv_handle_destroy(struct dcesrv_state *dce,
find an internal handle given a wire handle. If the wire handle is NULL then
allocate a new handle
*/
struct dcesrv_handle *dcesrv_handle_fetch(struct dcesrv_state *dce,
struct dcesrv_handle *dcesrv_handle_fetch(struct dcesrv_connection *dce_conn,
struct policy_handle *p,
uint8 handle_type)
{
struct dcesrv_handle *h;
if (policy_handle_empty(p)) {
return dcesrv_handle_new(dce, handle_type);
return dcesrv_handle_new(dce_conn, handle_type);
}
for (h=dce->handles; h; h=h->next) {
for (h=dce_conn->handles; h; h=h->next) {
if (h->wire_handle.handle_type == p->handle_type &&
uuid_equal(&p->uuid, &h->wire_handle.uuid)) {
if (p->handle_type != handle_type) {

View File

@ -0,0 +1,198 @@
/*
Unix SMB/CIFS implementation.
remote dcerpc operations
Copyright (C) Stefan (metze) Metzmacher 2004
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"
struct dcesrv_remote_private {
struct dcerpc_pipe *c_pipe;
void *private;
};
static NTSTATUS remote_op_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface)
{
NTSTATUS status;
struct dcesrv_remote_private *private;
const char *binding = lp_parm_string(-1, "dcerpc_remote", "binding");
const char *print_debug = lp_parm_string(-1, "dcerpc_remote", "print_debug");
if (!binding) {
printf("You must specify a ncacn binding string\n");
return NT_STATUS_INVALID_PARAMETER;
}
private = talloc_p(dce_call->conn->mem_ctx, struct dcesrv_remote_private);
if (!private) {
return NT_STATUS_NO_MEMORY;
}
status = dcerpc_pipe_connect(&(private->c_pipe), binding, iface->ndr->uuid, iface->ndr->if_version,
lp_workgroup(),
lp_parm_string(-1, "dcerpc_remote", "username"),
lp_parm_string(-1, "dcerpc_remote", "password"));
if (print_debug && strcasecmp("yes",print_debug) == 0) {
private->c_pipe->flags |= DCERPC_DEBUG_PRINT_BOTH;
}
dce_call->conn->private = private;
return NT_STATUS_OK;
}
static void remote_op_unbind(struct dcesrv_connection *dce_conn, const struct dcesrv_interface *iface)
{
struct dcesrv_remote_private *private = dce_conn->private;
dcerpc_pipe_close(private->c_pipe);
return;
}
static NTSTATUS remote_op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
{
struct dcesrv_remote_private *private = dce_call->conn->private;
NTSTATUS status;
uint16 opnum = dce_call->pkt.u.request.opnum;
ndr_push_flags_fn_t ndr_push_fn = dce_call->conn->iface->ndr->calls[opnum].ndr_push;
ndr_pull_flags_fn_t ndr_pull_fn = dce_call->conn->iface->ndr->calls[opnum].ndr_pull;
size_t struct_size = dce_call->conn->iface->ndr->calls[opnum].struct_size;
status = dcerpc_ndr_request(private->c_pipe, opnum, mem_ctx,
(ndr_push_flags_fn_t) ndr_push_fn,
(ndr_pull_flags_fn_t) ndr_pull_fn,
r, struct_size);
return status;
}
static NTSTATUS remote_register_one_iface(struct dcesrv_context *dce_ctx, const struct dcesrv_interface *iface)
{
int i;
for (i=0;i<iface->ndr->endpoints->count;i++) {
NTSTATUS ret;
const char *name = iface->ndr->endpoints->names[i];
ret = dcesrv_interface_register(dce_ctx, name, iface, NULL);
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(1,("remote_op_init_server: failed to register endpoint '%s'\n",name));
return ret;
}
}
return NT_STATUS_OK;
}
static NTSTATUS remote_op_init_server(struct dcesrv_context *dce_ctx, const struct dcesrv_endpoint_server *ep_server)
{
int i;
char **ifaces = str_list_make(lp_parm_string(-1,"dcerpc_remote","interfaces"),NULL);
if (!ifaces) {
DEBUG(3,("remote_op_init_server: no interfaces configured\n"));
return NT_STATUS_OK;
}
for (i=0;ifaces[i];i++) {
NTSTATUS ret;
struct dcesrv_interface iface;
if (!ep_server->interface_by_name(&iface, ifaces[i])) {
DEBUG(0,("remote_op_init_server: failed to find interface = '%s'\n", ifaces[i]));
str_list_free(&ifaces);
return NT_STATUS_UNSUCCESSFUL;
}
ret = remote_register_one_iface(dce_ctx, &iface);
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(0,("remote_op_init_server: failed to register interface = '%s'\n", ifaces[i]));
str_list_free(&ifaces);
return ret;
}
}
str_list_free(&ifaces);
return NT_STATUS_OK;
}
static BOOL remote_fill_interface(struct dcesrv_interface *iface, const struct dcerpc_interface_table *if_tabl)
{
iface->ndr = if_tabl;
iface->bind = remote_op_bind;
iface->unbind = remote_op_unbind;
iface->dispatch = remote_op_dispatch;
return True;
}
static BOOL remote_op_interface_by_uuid(struct dcesrv_interface *iface, const char *uuid, uint32 if_version)
{
int i;
for (i=0;dcerpc_pipes[i];i++) {
if (dcerpc_pipes[i]->if_version == if_version &&
strcmp(dcerpc_pipes[i]->uuid, uuid)==0) {
return remote_fill_interface(iface, dcerpc_pipes[i]);
}
}
return False;
}
static BOOL remote_op_interface_by_name(struct dcesrv_interface *iface, const char *name)
{
int i;
for (i=0;dcerpc_pipes[i];i++) {
if (strcmp(dcerpc_pipes[i]->name, name)==0) {
return remote_fill_interface(iface, dcerpc_pipes[i]);
}
}
return False;
}
NTSTATUS dcerpc_remote_init(void)
{
NTSTATUS ret;
struct dcesrv_endpoint_server ep_server;
ZERO_STRUCT(ep_server);
/* fill in our name */
ep_server.name = "remote";
/* fill in all the operations */
ep_server.init_server = remote_op_init_server;
ep_server.interface_by_uuid = remote_op_interface_by_uuid;
ep_server.interface_by_name = remote_op_interface_by_name;
/* register ourselves with the NTVFS subsystem. */
ret = register_backend("dcerpc", &ep_server);
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(0,("Failed to register 'remote' endpoint server!\n"));
return ret;
}
return ret;
}

View File

@ -765,7 +765,7 @@ void init_smbsession(struct event_context *ev, struct model_ops *model_ops, int
event_add_fd(ev, &fde);
/* setup the DCERPC server subsystem */
dcesrv_init(&smb->dcesrv);
dcesrv_init_context(&smb->dcesrv);
}
@ -825,6 +825,10 @@ void smbd_process_init(void)
if (!ntvfs_init())
exit(1);
/* Setup the DCERPC subsystem */
if (!dcesrv_init())
exit(1);
/* re-initialise the timezone */
TimeInit();

View File

@ -110,7 +110,7 @@ static void accept_rpc_connection(struct event_context *ev, struct fd_event *fde
ev = event_context_init();
MUTEX_LOCK_BY_ID(MUTEX_SMBD);
init_rpcsession(ev, fde->private, accepted_fd);
init_rpc_session(ev, fde->private, accepted_fd);
MUTEX_UNLOCK_BY_ID(MUTEX_SMBD);
pthread_attr_init(&thread_attr);

View File

@ -249,7 +249,7 @@ void reply_ioctl(struct request_context *req)
{
union smb_ioctl *io;
/* parse requst */
/* parse request */
REQ_CHECK_WCT(req, 3);
REQ_TALLOC(io, sizeof(*io));

View File

@ -62,6 +62,10 @@ struct request_context *init_smb_request(struct server_context *smb)
smb->socket.pkt_count++;
req = talloc(mem_ctx, sizeof(*req));
if (!req) {
return NULL;
}
ZERO_STRUCTP(req);
/* setup the request context */