Line data Source code
1 : /* 2 : Unix SMB/CIFS implementation. 3 : 4 : forwarding of RPC calls to other tasks 5 : 6 : Copyright (C) Andrew Tridgell 2009 7 : 8 : This program is free software; you can redistribute it and/or modify 9 : it under the terms of the GNU General Public License as published by 10 : the Free Software Foundation; either version 3 of the License, or 11 : (at your option) any later version. 12 : 13 : This program is distributed in the hope that it will be useful, 14 : but WITHOUT ANY WARRANTY; without even the implied warranty of 15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 : GNU General Public License for more details. 17 : 18 : You should have received a copy of the GNU General Public License 19 : along with this program. If not, see <http://www.gnu.org/licenses/>. 20 : */ 21 : 22 : #include "includes.h" 23 : #include <tevent.h> 24 : #include "rpc_server/dcerpc_server.h" 25 : #include "librpc/gen_ndr/dcerpc.h" 26 : #include "rpc_server/common/common.h" 27 : #include "messaging/irpc.h" 28 : #include "auth/auth.h" 29 : 30 : 31 : struct dcesrv_forward_state { 32 : const char *opname; 33 : struct dcesrv_call_state *dce_call; 34 : }; 35 : 36 : /* 37 : called when the forwarded rpc request is finished 38 : */ 39 2113 : static void dcesrv_irpc_forward_callback(struct tevent_req *subreq) 40 : { 41 0 : struct dcesrv_forward_state *st = 42 2113 : tevent_req_callback_data(subreq, 43 : struct dcesrv_forward_state); 44 2113 : const char *opname = st->opname; 45 0 : NTSTATUS status; 46 : 47 2113 : status = dcerpc_binding_handle_call_recv(subreq); 48 2113 : TALLOC_FREE(subreq); 49 2113 : if (!NT_STATUS_IS_OK(status)) { 50 0 : DEBUG(0,("IRPC callback failed for %s - %s\n", 51 : opname, nt_errstr(status))); 52 0 : st->dce_call->fault_code = DCERPC_FAULT_CANT_PERFORM; 53 : } 54 2113 : _dcesrv_async_reply(st->dce_call, __func__, opname); 55 2113 : } 56 : 57 : 58 : 59 : /** 60 : * Forward a RPC call using IRPC to another task 61 : */ 62 2113 : void dcesrv_irpc_forward_rpc_call(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, 63 : void *r, uint32_t callid, 64 : const struct ndr_interface_table *ndr_table, 65 : const char *dest_task, const char *opname, 66 : uint32_t timeout) 67 : { 68 0 : struct dcesrv_forward_state *st; 69 0 : struct dcerpc_binding_handle *binding_handle; 70 0 : struct tevent_req *subreq; 71 0 : struct auth_session_info *session_info = 72 2113 : dcesrv_call_session_info(dce_call); 73 0 : struct imessaging_context *imsg_ctx = 74 2113 : dcesrv_imessaging_context(dce_call->conn); 75 : 76 2113 : st = talloc(mem_ctx, struct dcesrv_forward_state); 77 2113 : if (st == NULL) { 78 0 : dce_call->fault_code = DCERPC_FAULT_CANT_PERFORM; 79 0 : return; 80 : } 81 : 82 2113 : st->dce_call = dce_call; 83 2113 : st->opname = opname; 84 : 85 : /* if the caller has said they can't support async calls 86 : then fail the call */ 87 2113 : if (!(dce_call->state_flags & DCESRV_CALL_STATE_FLAG_MAY_ASYNC)) { 88 : /* we're not allowed to reply async */ 89 0 : DEBUG(0,("%s: Not available synchronously\n", dest_task)); 90 0 : dce_call->fault_code = DCERPC_FAULT_CANT_PERFORM; 91 0 : return; 92 : } 93 : 94 2113 : binding_handle = irpc_binding_handle_by_name(st, 95 : imsg_ctx, 96 : dest_task, 97 : ndr_table); 98 2113 : if (binding_handle == NULL) { 99 0 : DEBUG(0,("%s: Failed to forward request to %s task\n", 100 : opname, dest_task)); 101 0 : dce_call->fault_code = DCERPC_FAULT_CANT_PERFORM; 102 0 : return; 103 : } 104 : 105 : /* reset timeout for the handle */ 106 2113 : dcerpc_binding_handle_set_timeout(binding_handle, timeout); 107 : 108 : /* add security token to the handle*/ 109 2113 : irpc_binding_handle_add_security_token(binding_handle, 110 : session_info->security_token); 111 : 112 : /* forward the call */ 113 2113 : subreq = dcerpc_binding_handle_call_send(st, dce_call->event_ctx, 114 : binding_handle, 115 : NULL, ndr_table, 116 : callid, 117 : dce_call, r); 118 2113 : if (subreq == NULL) { 119 0 : DEBUG(0,("%s: Failed to forward request to %s task\n", 120 : opname, dest_task)); 121 0 : dce_call->fault_code = DCERPC_FAULT_CANT_PERFORM; 122 0 : return; 123 : } 124 : 125 : /* mark the request as replied async */ 126 2113 : dce_call->state_flags |= DCESRV_CALL_STATE_FLAG_ASYNC; 127 : 128 : /* setup the callback */ 129 2113 : tevent_req_set_callback(subreq, dcesrv_irpc_forward_callback, st); 130 : }