From 7e6cf43756b7643e2f0ee7ada5076f36f3a24bb7 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 8 Jan 2004 22:55:27 +0000 Subject: 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) --- source4/Makefile.in | 12 +- source4/build/pidl/header.pm | 2 +- source4/build/pidl/server.pm | 114 +++++-- source4/build/pidl/tables.pl | 2 +- source4/build/pidl/template.pm | 6 +- source4/configure.in | 3 +- source4/lib/module.c | 14 +- source4/librpc/ndr/ndr_sec.c | 68 ++-- source4/ntvfs/ipc/vfs_ipc.c | 22 +- source4/ntvfs/ntvfs_base.c | 11 +- source4/param/loadparm.c | 5 + source4/rpc_server/config.m4 | 7 + source4/rpc_server/dcerpc_server.c | 529 ++++++++++++++++++++--------- source4/rpc_server/dcerpc_server.h | 129 ++++--- source4/rpc_server/dcerpc_tcp.c | 59 ++-- source4/rpc_server/dcesrv_auth.c | 98 +++--- source4/rpc_server/echo/rpc_echo.c | 12 +- source4/rpc_server/epmapper/rpc_epmapper.c | 59 ++-- source4/rpc_server/handles.c | 14 +- source4/rpc_server/remote/dcesrv_remote.c | 198 +++++++++++ source4/smbd/process.c | 6 +- source4/smbd/process_thread.c | 2 +- source4/smbd/reply.c | 2 +- source4/smbd/request.c | 4 + 24 files changed, 970 insertions(+), 408 deletions(-) create mode 100644 source4/rpc_server/config.m4 create mode 100644 source4/rpc_server/remote/dcesrv_remote.c (limited to 'source4') diff --git a/source4/Makefile.in b/source4/Makefile.in index 784ed22f10..00adf52e07 100644 --- a/source4/Makefile.in +++ b/source4/Makefile.in @@ -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 \ diff --git a/source4/build/pidl/header.pm b/source4/build/pidl/header.pm index 418ae97aed..c1b6eb44a1 100644 --- a/source4/build/pidl/header.pm +++ b/source4/build/pidl/header.pm @@ -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}) { diff --git a/source4/build/pidl/server.pm b/source4/build/pidl/server.pm index f5256d18a6..0938515f48 100644 --- a/source4/build/pidl/server.pm +++ b/source4/build/pidl/server.pm @@ -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; } + +NTSTATUS dcerpc_$name\_init(void) +{ + NTSTATUS ret; + struct dcesrv_endpoint_server ep_server; -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 -}; + /* fill in our name */ + ep_server.name = \"$name\"; -void rpc_$name\_init(void *v) -{ - struct dcesrv_context *dce = v; - if (!dcesrv_endpoint_register(dce, &$name\_ops, - &dcerpc_table_$name)) { - DEBUG(1,(\"Failed to register rpcecho endpoint\\n\")); + /* 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; } diff --git a/source4/build/pidl/tables.pl b/source4/build/pidl/tables.pl index fa53af1c09..bf1db20e28 100755 --- a/source4/build/pidl/tables.pl +++ b/source4/build/pidl/tables.pl @@ -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"; diff --git a/source4/build/pidl/template.pm b/source4/build/pidl/template.pm index f9f9897ce2..6e0decbf40 100644 --- a/source4/build/pidl/template.pm +++ b/source4/build/pidl/template.pm @@ -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; - diff --git a/source4/configure.in b/source4/configure.in index 82773bc179..e615a31cee 100644 --- a/source4/configure.in +++ b/source4/configure.in @@ -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]) diff --git a/source4/lib/module.c b/source4/lib/module.c index ffd6a38c77..15f92db59e 100644 --- a/source4/lib/module.c +++ b/source4/lib/module.c @@ -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) diff --git a/source4/librpc/ndr/ndr_sec.c b/source4/librpc/ndr/ndr_sec.c index a3be697c49..49c88d1563 100644 --- a/source4/librpc/ndr/ndr_sec.c +++ b/source4/librpc/ndr/ndr_sec.c @@ -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; } diff --git a/source4/ntvfs/ipc/vfs_ipc.c b/source4/ntvfs/ipc/vfs_ipc.c index 96f28895c9..cd300b6589 100644 --- a/source4/ntvfs/ipc/vfs_ipc.c +++ b/source4/ntvfs/ipc/vfs_ipc.c @@ -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; } diff --git a/source4/ntvfs/ntvfs_base.c b/source4/ntvfs/ntvfs_base.c index ad1b3ae671..e4009fd1f0 100644 --- a/source4/ntvfs/ntvfs_base.c +++ b/source4/ntvfs/ntvfs_base.c @@ -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; } diff --git a/source4/param/loadparm.c b/source4/param/loadparm.c index aff4a4f12a..9052fe4409 100644 --- a/source4/param/loadparm.c +++ b/source4/param/loadparm.c @@ -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) diff --git a/source4/rpc_server/config.m4 b/source4/rpc_server/config.m4 new file mode 100644 index 0000000000..cdc4f65186 --- /dev/null +++ b/source4/rpc_server/config.m4 @@ -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) diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c index d3e2f1917f..46341e6db1 100644 --- a/source4/rpc_server/dcerpc_server.c +++ b/source4/rpc_server/dcerpc_server.c @@ -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;iendpoints->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; + } + /* 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 NT_STATUS_NO_MEMORY; + } + ZERO_STRUCTP(ep); if (tcp) { - if (done_tcp) continue; - done_tcp = True; + ep->ep_description.type = ENDPOINT_TCP; + ep->ep_description.info.tcp_port = atoi(ep_name+4); } else { - if (done_smb) continue; - done_smb = True; + ep->ep_description.type = ENDPOINT_SMB; + ep->ep_description.info.smb_pipe = smb_xstrdup(ep_name); } + add_ep = True; + } - ep = malloc(sizeof(*ep)); - if (!ep) { - return False; + /* 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); } - if (tcp) { - ep->endpoint.type = ENDPOINT_TCP; - ep->endpoint.info.tcp_port = atoi(table->endpoints->names[i]+4); - } else { - ep->endpoint.type = ENDPOINT_SMB; - ep->endpoint.info.smb_pipe = table->endpoints->names[i]; + /* 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; } + } - ep->endpoint_ops = ops; - DLIST_ADD(dce->endpoint_list, ep); + /* finally add the interface on the endpoint */ + DLIST_ADD(ep->interface_list, ifl); + + /* if it's a new endpoint add it to the dcesrv_context */ + if (add_ep) { + DLIST_ADD(dce_ctx->endpoint_list, ep); } - return True; + DEBUG(3,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n", + iface->ndr->name, ep_name)); + + return NT_STATUS_OK; } /* 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) +NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx, + const struct dcesrv_endpoint *ep, + struct dcesrv_connection **p) { TALLOC_CTX *mem_ctx; - NTSTATUS status; mem_ctx = talloc_init("dcesrv_endpoint_connect"); if (!mem_ctx) { return NT_STATUS_NO_MEMORY; } - *p = talloc_p(mem_ctx, struct dcesrv_state); + *p = talloc_p(mem_ctx, struct dcesrv_connection); if (! *p) { talloc_destroy(mem_ctx); return NT_STATUS_NO_MEMORY; } - (*p)->dce = dce; + (*p)->dce_ctx = dce_ctx; (*p)->mem_ctx = mem_ctx; - (*p)->endpoint = *endpoint; - (*p)->ops = ops; + (*p)->endpoint = ep; + (*p)->iface = NULL; (*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 + search and 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_search_connect(struct dcesrv_context *dce_ctx, + const struct dcesrv_ep_description *ep_description, + struct dcesrv_connection **dce_conn_p) { - const struct dcesrv_endpoint_ops *ops; + 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) + initialise the dcerpc server context +*/ +NTSTATUS dcesrv_init_context(struct dcesrv_context *dce_ctx) { int i; - const struct dcerpc_endpoint_list *endpoints = table->endpoints; + const char **endpoint_servers = lp_dcerpc_endpoint_servers(); - if (ep->type != ENDPOINT_SMB) { - return False; + dce_ctx->mem_ctx = talloc_init("struct dcesrv_context"); + if (!dce_ctx->mem_ctx) { + DEBUG(3,("dcesrv_init_context: talloc_init failed\n")); + return NT_STATUS_NO_MEMORY; } - for (i=0;icount;i++) { - if (strcasecmp(ep->info.smb_pipe, endpoints->names[i]) == 0) { - return True; + 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 False; + + return NT_STATUS_OK; } +/* the list of currently registered DCERPC endpoint servers. + */ +static struct { + struct dcesrv_endpoint_server *ep_server; +} *ep_servers = NULL; +static int num_ep_servers; /* - a useful function for implementing the lookup_endpoints op - */ -int dcesrv_lookup_endpoints(const struct dcerpc_interface_table *table, - TALLOC_CTX *mem_ctx, - struct dcesrv_ep_iface **e) + 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) { - int i; - *e = talloc_array_p(mem_ctx, struct dcesrv_ep_iface, table->endpoints->count); - if (! *e) { - return -1; - } - - for (i=0;iendpoints->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]; - } + 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; } - return i; -} + 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; +} -BOOL dcesrv_set_interface(struct dcesrv_state *dce, - const char *uuid, uint32 if_version, - const struct dcerpc_interface_table *table, - const dcesrv_dispatch_fn_t *dispatch_table) +/* + return the operations structure for a named backend of the specified type +*/ +const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name) { - 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; + int i; + + for (i=0;iname, name) == 0) { + return ep_servers[i].ep_server; + } } - dce->ndr = table; - dce->dispatch = dispatch_table; - return True; + 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 server subsystem + initialise the DCERPC subsystem */ -BOOL dcesrv_init(struct dcesrv_context *dce) +BOOL dcesrv_init(void) { - rpc_rpcecho_init(dce); - rpc_epmapper_init(dce); + 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; } diff --git a/source4/rpc_server/dcerpc_server.h b/source4/rpc_server/dcerpc_server.h index 8481372d55..411bf400bf 100644 --- a/source4/rpc_server/dcerpc_server.h +++ b/source4/rpc_server/dcerpc_server.h @@ -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 *); - - /* this function sets up the dispatch table for this - connection */ - BOOL (*set_interface)(struct dcesrv_state *, const char *, uint32); - - /* connect() is called when a connection is made to an endpoint */ - NTSTATUS (*connect)(struct dcesrv_state *); - - /* disconnect() is called when the endpoint is disconnected */ - void (*disconnect)(struct dcesrv_state *); +struct dcesrv_endpoint_server { + /* this is the name of the endpoint server */ + const char *name; - /* 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 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 *); + + /* 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); + + /* 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; +}; diff --git a/source4/rpc_server/dcerpc_tcp.c b/source4/rpc_server/dcerpc_tcp.c index c9aeb400d0..34e6db63e3 100644 --- a/source4/rpc_server/dcerpc_tcp.c +++ b/source4/rpc_server/dcerpc_tcp.c @@ -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); } } diff --git a/source4/rpc_server/dcesrv_auth.c b/source4/rpc_server/dcesrv_auth.c index 776d394e99..a117f08445 100644 --- a/source4/rpc_server/dcesrv_auth.c +++ b/source4/rpc_server/dcesrv_auth.c @@ -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; } diff --git a/source4/rpc_server/echo/rpc_echo.c b/source4/rpc_server/echo/rpc_echo.c index 9d2c72e1b6..ec5d667b46 100644 --- a/source4/rpc_server/echo/rpc_echo.c +++ b/source4/rpc_server/echo/rpc_echo.c @@ -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;iin.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) { diff --git a/source4/rpc_server/epmapper/rpc_epmapper.c b/source4/rpc_server/epmapper/rpc_epmapper.c index 5e571ee1ef..f3285729a6 100644 --- a/source4/rpc_server/epmapper/rpc_epmapper.c +++ b/source4/rpc_server/epmapper/rpc_epmapper.c @@ -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;iendpoint; - } - (*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; diff --git a/source4/rpc_server/handles.c b/source4/rpc_server/handles.c index 26d7552afb..043318c075 100644 --- a/source4/rpc_server/handles.c +++ b/source4/rpc_server/handles.c @@ -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) { diff --git a/source4/rpc_server/remote/dcesrv_remote.c b/source4/rpc_server/remote/dcesrv_remote.c new file mode 100644 index 0000000000..381c79135c --- /dev/null +++ b/source4/rpc_server/remote/dcesrv_remote.c @@ -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;indr->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; +} diff --git a/source4/smbd/process.c b/source4/smbd/process.c index b5138ac971..411ffef717 100644 --- a/source4/smbd/process.c +++ b/source4/smbd/process.c @@ -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(); diff --git a/source4/smbd/process_thread.c b/source4/smbd/process_thread.c index 523c38f521..9acd49916b 100644 --- a/source4/smbd/process_thread.c +++ b/source4/smbd/process_thread.c @@ -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); diff --git a/source4/smbd/reply.c b/source4/smbd/reply.c index ce203cbf93..7d6450b395 100644 --- a/source4/smbd/reply.c +++ b/source4/smbd/reply.c @@ -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)); diff --git a/source4/smbd/request.c b/source4/smbd/request.c index 65bf71051f..065e63a8d2 100644 --- a/source4/smbd/request.c +++ b/source4/smbd/request.c @@ -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 */ -- cgit