From f80363c90a60a4496309a50d760ca05ac4b59e4f Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 15 Sep 2009 20:50:30 -0700 Subject: s4-rpc: added a module for forwarding RPC requests dcesrv_irpc_forward_rpc_call() can be used to forward an arbitrary RPC request to another task in Samba4, with the return being handled asynchronously. This is useful for forwarding DRS requests to the repl or kcc tasks --- source4/rpc_server/common/common.h | 10 +--- source4/rpc_server/common/forward.c | 112 ++++++++++++++++++++++++++++++++++++ source4/rpc_server/config.mk | 3 +- 3 files changed, 116 insertions(+), 9 deletions(-) create mode 100644 source4/rpc_server/common/forward.c diff --git a/source4/rpc_server/common/common.h b/source4/rpc_server/common/common.h index aacd460388..5a1d7abab9 100644 --- a/source4/rpc_server/common/common.h +++ b/source4/rpc_server/common/common.h @@ -25,14 +25,6 @@ struct share_config; struct dcesrv_context; -enum srvsvc_ShareType dcesrv_common_get_share_type(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx, struct share_config *scfg); -enum srvsvc_PlatformId dcesrv_common_get_platform_id(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx); -const char *dcesrv_common_get_lan_root(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx); -const char *dcesrv_common_get_server_name(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx, const char *server_unc); -uint32_t dcesrv_common_get_share_permissions(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx, struct share_config *scfg); -uint32_t dcesrv_common_get_share_current_users(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx, struct share_config *scfg); -const char *dcesrv_common_get_share_path(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx, struct share_config *scfg); - struct dcesrv_context; struct dcerpc_server_info { @@ -42,4 +34,6 @@ struct dcerpc_server_info { uint32_t version_build; }; +#include "rpc_server/common/proto.h" + #endif /* _DCERPC_SERVER_COMMON_H_ */ diff --git a/source4/rpc_server/common/forward.c b/source4/rpc_server/common/forward.c new file mode 100644 index 0000000000..e0fac0ea08 --- /dev/null +++ b/source4/rpc_server/common/forward.c @@ -0,0 +1,112 @@ +/* + Unix SMB/CIFS implementation. + + forwarding of RPC calls to other tasks + + Copyright (C) Andrew Tridgell 2009 + + 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 3 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, see . +*/ + +#include "includes.h" +#include "librpc/gen_ndr/ndr_srvsvc.h" +#include "librpc/gen_ndr/svcctl.h" +#include "rpc_server/dcerpc_server.h" +#include "rpc_server/common/common.h" +#include "rpc_server/common/proto.h" +#include "messaging/irpc.h" + +struct dcesrv_forward_state { + const char *opname; + struct dcesrv_call_state *dce_call; +}; + +/* + called when the forwarded rpc request is finished + */ +static void dcesrv_irpc_forward_callback(struct irpc_request *ireq) +{ + struct dcesrv_forward_state *st = talloc_get_type(ireq->async.private_data, + struct dcesrv_forward_state); + const char *opname = st->opname; + NTSTATUS status; + if (!NT_STATUS_IS_OK(ireq->status)) { + DEBUG(0,("IRPC callback failed for %s - %s\n", + opname, nt_errstr(ireq->status))); + st->dce_call->fault_code = DCERPC_FAULT_CANT_PERFORM; + } + talloc_free(ireq); + status = dcesrv_reply(st->dce_call); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("%s_handler: dcesrv_reply() failed - %s\n", + opname, nt_errstr(status))); + } +} + + + +/* + forward a RPC call using IRPC to another task + */ +void dcesrv_irpc_forward_rpc_call(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, + void *r, uint32_t callid, + const struct ndr_interface_table *ndr_table, + const char *dest_task, const char *opname) +{ + struct server_id *sid; + struct irpc_request *ireq; + struct dcesrv_forward_state *st; + + st = talloc(mem_ctx, struct dcesrv_forward_state); + if (st == NULL) { + dce_call->fault_code = DCERPC_FAULT_CANT_PERFORM; + return; + } + + st->dce_call = dce_call; + st->opname = opname; + + /* if the caller has said they can't support async calls + then fail the call */ + if (!(dce_call->state_flags & DCESRV_CALL_STATE_FLAG_MAY_ASYNC)) { + /* we're not allowed to reply async */ + DEBUG(0,("%s: Not available synchronously\n", dest_task)); + dce_call->fault_code = DCERPC_FAULT_CANT_PERFORM; + return; + } + + /* find the server task */ + sid = irpc_servers_byname(dce_call->msg_ctx, mem_ctx, dest_task); + if (sid == NULL || sid[0].id == 0) { + DEBUG(0,("%s: Unable to find %s task\n", dest_task, opname)); + dce_call->fault_code = DCERPC_FAULT_CANT_PERFORM; + return; + } + + /* forward the call */ + ireq = irpc_call_send(dce_call->msg_ctx, sid[0], ndr_table, callid, r, mem_ctx); + if (ireq == NULL) { + DEBUG(0,("%s: Failed to forward request to %s task\n", + opname, dest_task)); + dce_call->fault_code = DCERPC_FAULT_CANT_PERFORM; + return; + } + + /* mark the request as replied async */ + dce_call->state_flags |= DCESRV_CALL_STATE_FLAG_ASYNC; + + /* setup the callback */ + ireq->async.fn = dcesrv_irpc_forward_callback; + ireq->async.private_data = st; +} diff --git a/source4/rpc_server/config.mk b/source4/rpc_server/config.mk index f60f83327b..93617c2c98 100644 --- a/source4/rpc_server/config.mk +++ b/source4/rpc_server/config.mk @@ -8,7 +8,8 @@ PRIVATE_DEPENDENCIES = LIBLDB # End SUBSYSTEM DCERPC_COMMON ################################################ -DCERPC_COMMON_OBJ_FILES = $(addprefix $(rpc_serversrcdir)/common/, server_info.o share_info.o) +DCERPC_COMMON_OBJ_FILES = $(addprefix $(rpc_serversrcdir)/common/, \ + server_info.o share_info.o forward.o) $(eval $(call proto_header_template,$(rpc_serversrcdir)/common/proto.h,$(DCERPC_COMMON_OBJ_FILES:.o=.c))) -- cgit From 30d13288e5bb506584a0bf012d7b2e579a6a2074 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 15 Sep 2009 20:51:10 -0700 Subject: s4-repl: take advantage of async RPC forwarding This uses async RPC forwarding for the DsReplicaSync call --- source4/dsdb/repl/drepl_service.c | 8 +++----- source4/rpc_server/drsuapi/dcesrv_drsuapi.c | 25 ++++--------------------- 2 files changed, 7 insertions(+), 26 deletions(-) diff --git a/source4/dsdb/repl/drepl_service.c b/source4/dsdb/repl/drepl_service.c index cb415b65e6..75ce42b91a 100644 --- a/source4/dsdb/repl/drepl_service.c +++ b/source4/dsdb/repl/drepl_service.c @@ -113,18 +113,16 @@ static NTSTATUS drepl_replica_sync(struct irpc_message *msg, { struct dreplsrv_service *service = talloc_get_type(msg->private_data, struct dreplsrv_service); - WERROR werr; struct GUID *guid = &r->in.req.req1.naming_context->guid; - werr = dreplsrv_schedule_partition_pull_by_guid(service, msg, guid); - if (W_ERROR_IS_OK(werr)) { + r->out.result = dreplsrv_schedule_partition_pull_by_guid(service, msg, guid); + if (W_ERROR_IS_OK(r->out.result)) { DEBUG(3,("drepl_replica_sync: forcing sync of partition %s\n", GUID_string(msg, guid))); dreplsrv_run_pending_ops(service); } else { DEBUG(3,("drepl_replica_sync: failed setup of sync of partition %s - %s\n", - GUID_string(msg, guid), win_errstr(werr))); - return NT_STATUS_INTERNAL_ERROR; + GUID_string(msg, guid), win_errstr(r->out.result))); } return NT_STATUS_OK; } diff --git a/source4/rpc_server/drsuapi/dcesrv_drsuapi.c b/source4/rpc_server/drsuapi/dcesrv_drsuapi.c index c01711d2d9..491b962a85 100644 --- a/source4/rpc_server/drsuapi/dcesrv_drsuapi.c +++ b/source4/rpc_server/drsuapi/dcesrv_drsuapi.c @@ -28,7 +28,6 @@ #include "lib/ldb/include/ldb_errors.h" #include "param/param.h" #include "librpc/gen_ndr/ndr_drsblobs.h" -#include "messaging/irpc.h" #include "rpc_server/drsuapi/dcesrv_drsuapi.h" #include "libcli/security/security.h" @@ -232,35 +231,19 @@ static WERROR dcesrv_drsuapi_DsUnbind(struct dcesrv_call_state *dce_call, TALLOC static WERROR dcesrv_drsuapi_DsReplicaSync(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct drsuapi_DsReplicaSync *r) { - struct server_id *repld; - struct irpc_request *ireq; - if (security_session_user_level(dce_call->conn->auth_state.session_info) < SECURITY_DOMAIN_CONTROLLER) { DEBUG(0,("DsReplicaSync refused for security token\n")); return WERR_DS_DRA_ACCESS_DENIED; } - repld = irpc_servers_byname(dce_call->msg_ctx, mem_ctx, "dreplsrv"); - if (repld == NULL || repld[0].id == 0) { - DEBUG(0,("DsReplicaSync: Unable to find dreplsrv task\n")); - return WERR_DS_DRA_INTERNAL_ERROR; - } - - ireq = IRPC_CALL_SEND(dce_call->msg_ctx, repld[0], - drsuapi, DRSUAPI_DSREPLICASYNC, - r, mem_ctx); - if (ireq == NULL) { - DEBUG(0,("DsReplicaSync: Failed to forward request to dreplsrv task\n")); - return WERR_DS_DRA_INTERNAL_ERROR; - } - - /* we are not interested in a reply */ - talloc_free(ireq); - + dcesrv_irpc_forward_rpc_call(dce_call, mem_ctx, r, NDR_DRSUAPI_DSREPLICASYNC, + &ndr_table_drsuapi, + "dreplsrv", "DsReplicaSync"); return WERR_OK; } + /* drsuapi_DsReplicaAdd */ -- cgit