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:
parent
8364fd2853
commit
7e6cf43756
@ -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 \
|
||||
|
@ -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}) {
|
||||
|
@ -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)
|
||||
static NTSTATUS $name\_op_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface)
|
||||
{
|
||||
return dcesrv_table_query(&dcerpc_table_$name, ep);
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static BOOL $name\_op_set_interface(struct dcesrv_state *dce,
|
||||
const char *uuid, uint32 if_version)
|
||||
static void $name\_op_unbind(struct dcesrv_connection *dce_conn, const struct dcesrv_interface *iface)
|
||||
{
|
||||
return dcesrv_set_interface(dce, uuid, if_version,
|
||||
&dcerpc_table_$name, $name\_dispatch_table);
|
||||
return;
|
||||
}
|
||||
|
||||
static NTSTATUS $name\_op_connect(struct dcesrv_state *dce)
|
||||
static NTSTATUS $name\_op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
|
||||
{
|
||||
uint16 opnum = dce_call->pkt.u.request.opnum;
|
||||
|
||||
return $name\_dispatch_table[opnum](dce_call, mem_ctx, r);
|
||||
}
|
||||
|
||||
static const struct dcesrv_interface $name\_interface = {
|
||||
&dcerpc_table_$name,
|
||||
$name\_op_bind,
|
||||
$name\_op_unbind,
|
||||
$name\_op_dispatch
|
||||
};
|
||||
|
||||
";
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# produce boilerplate code for an endpoint server
|
||||
sub Boilerplate_Ep_Server($)
|
||||
{
|
||||
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 void $name\_op_disconnect(struct dcesrv_state *dce)
|
||||
static BOOL $name\_op_interface_by_uuid(struct dcesrv_interface *iface, const char *uuid, uint32 if_version)
|
||||
{
|
||||
/* nothing to do */
|
||||
return False;
|
||||
}
|
||||
|
||||
static int $name\_op_lookup_endpoints(TALLOC_CTX *mem_ctx, struct dcesrv_ep_iface **e)
|
||||
static BOOL $name\_op_interface_by_name(struct dcesrv_interface *iface, const char *name)
|
||||
{
|
||||
return dcesrv_lookup_endpoints(&dcerpc_table_$name, mem_ctx, e);
|
||||
return False;
|
||||
}
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
void rpc_$name\_init(void *v)
|
||||
|
||||
NTSTATUS dcerpc_$name\_init(void)
|
||||
{
|
||||
struct dcesrv_context *dce = v;
|
||||
if (!dcesrv_endpoint_register(dce, &$name\_ops,
|
||||
&dcerpc_table_$name)) {
|
||||
DEBUG(1,(\"Failed to register rpcecho endpoint\\n\"));
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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";
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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])
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
*/
|
||||
@ -139,25 +161,17 @@ size_t ndr_size_security_descriptor(struct security_descriptor *sd)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
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)
|
||||
/*
|
||||
talloc and copy a security descriptor
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
7
source4/rpc_server/config.m4
Normal file
7
source4/rpc_server/config.m4
Normal 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)
|
@ -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,121 +143,175 @@ 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;
|
||||
struct dcesrv_ep_description ep_description;
|
||||
struct dcesrv_endpoint *ep;
|
||||
struct dcesrv_if_list *ifl;
|
||||
BOOL tcp;
|
||||
BOOL add_ep = False;
|
||||
|
||||
for (i=0;i<table->endpoints->count;i++) {
|
||||
struct dce_endpoint *ep;
|
||||
BOOL tcp;
|
||||
tcp = (strncasecmp(ep_name, "TCP-", 4) == 0);
|
||||
|
||||
tcp = (strncasecmp(table->endpoints->names[i], "TCP-", 4) == 0);
|
||||
if (tcp) {
|
||||
ep_description.type = ENDPOINT_TCP;
|
||||
ep_description.info.tcp_port = atoi(ep_name+4);
|
||||
} else {
|
||||
ep_description.type = ENDPOINT_SMB;
|
||||
ep_description.info.smb_pipe = ep_name;
|
||||
}
|
||||
|
||||
if (tcp) {
|
||||
if (done_tcp) continue;
|
||||
done_tcp = True;
|
||||
} else {
|
||||
if (done_smb) continue;
|
||||
done_smb = True;
|
||||
}
|
||||
|
||||
ep = malloc(sizeof(*ep));
|
||||
/* check if this endpoint exists
|
||||
*/
|
||||
if ((ep=find_endpoint(dce_ctx, &ep_description))==NULL) {
|
||||
ep = talloc(dce_ctx->mem_ctx, sizeof(*ep));
|
||||
if (!ep) {
|
||||
return False;
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
ZERO_STRUCTP(ep);
|
||||
if (tcp) {
|
||||
ep->endpoint.type = ENDPOINT_TCP;
|
||||
ep->endpoint.info.tcp_port = atoi(table->endpoints->names[i]+4);
|
||||
ep->ep_description.type = ENDPOINT_TCP;
|
||||
ep->ep_description.info.tcp_port = atoi(ep_name+4);
|
||||
} else {
|
||||
ep->endpoint.type = ENDPOINT_SMB;
|
||||
ep->endpoint.info.smb_pipe = table->endpoints->names[i];
|
||||
ep->ep_description.type = ENDPOINT_SMB;
|
||||
ep->ep_description.info.smb_pipe = smb_xstrdup(ep_name);
|
||||
}
|
||||
add_ep = True;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
ep->endpoint_ops = ops;
|
||||
DLIST_ADD(dce->endpoint_list, ep);
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
/* finally add the interface on the endpoint */
|
||||
DLIST_ADD(ep->interface_list, ifl);
|
||||
|
||||
/*
|
||||
connect to a dcerpc endpoint
|
||||
*/
|
||||
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;
|
||||
|
||||
mem_ctx = talloc_init("dcesrv_endpoint_connect");
|
||||
if (!mem_ctx) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
/* if it's a new endpoint add it to the dcesrv_context */
|
||||
if (add_ep) {
|
||||
DLIST_ADD(dce_ctx->endpoint_list, ep);
|
||||
}
|
||||
|
||||
*p = talloc_p(mem_ctx, struct dcesrv_state);
|
||||
if (! *p) {
|
||||
talloc_destroy(mem_ctx);
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
DEBUG(3,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
|
||||
iface->ndr->name, ep_name));
|
||||
|
||||
(*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;
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
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;
|
||||
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
|
||||
*/
|
||||
BOOL dcesrv_table_query(const struct dcerpc_interface_table *table,
|
||||
const struct dcesrv_endpoint *ep)
|
||||
{
|
||||
int i;
|
||||
const struct dcerpc_endpoint_list *endpoints = table->endpoints;
|
||||
|
||||
if (ep->type != ENDPOINT_SMB) {
|
||||
return False;
|
||||
}
|
||||
|
||||
for (i=0;i<endpoints->count;i++) {
|
||||
if (strcasecmp(ep->info.smb_pipe, endpoints->names[i]) == 0) {
|
||||
return True;
|
||||
}
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
a useful function for implementing the lookup_endpoints op
|
||||
*/
|
||||
int dcesrv_lookup_endpoints(const struct dcerpc_interface_table *table,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct dcesrv_ep_iface **e)
|
||||
{
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
if (strcasecmp(table->uuid, uuid) != 0 || if_version != table->if_version) {
|
||||
DEBUG(2,("Attempt to use unknown interface %s/%d\n", uuid, if_version));
|
||||
return False;
|
||||
}
|
||||
|
||||
dce->ndr = table;
|
||||
dce->dispatch = dispatch_table;
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
initialise the dcerpc server subsystem
|
||||
initialise the dcerpc server context
|
||||
*/
|
||||
BOOL dcesrv_init(struct dcesrv_context *dce)
|
||||
NTSTATUS dcesrv_init_context(struct dcesrv_context *dce_ctx)
|
||||
{
|
||||
rpc_rpcecho_init(dce);
|
||||
rpc_epmapper_init(dce);
|
||||
int i;
|
||||
const char **endpoint_servers = lp_dcerpc_endpoint_servers();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
/*
|
||||
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
|
||||
*/
|
||||
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;
|
||||
|
||||
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 NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
@ -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 {
|
||||
|
||||
/* 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;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
|
||||
/* 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;
|
||||
};
|
||||
|
@ -4,7 +4,8 @@
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
server side dcerpc authentication code
|
||||
|
||||
Copyright (C) Andrew Tridgell 2003
|
||||
|
||||
|
||||
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
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
198
source4/rpc_server/remote/dcesrv_remote.c
Normal file
198
source4/rpc_server/remote/dcesrv_remote.c
Normal 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;
|
||||
}
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user