c2dd500b2e27d30bd3c482351c5605d5f5f4d10e
[metze/samba/wip.git] / source4 / rpc_server / common / forward.c
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         struct dcerpc_binding_handle_call_params params;
35 };
36
37 /*
38   called when the forwarded rpc request is finished
39  */
40 static void dcesrv_irpc_forward_callback(struct tevent_req *subreq)
41 {
42         struct dcesrv_forward_state *st =
43                 tevent_req_callback_data(subreq,
44                 struct dcesrv_forward_state);
45         const char *opname = st->opname;
46         NTSTATUS status;
47
48         status = dcerpc_binding_handle_call_recv(subreq);
49         TALLOC_FREE(subreq);
50         if (!NT_STATUS_IS_OK(status)) {
51                 DEBUG(0,("IRPC callback failed for %s - %s\n",
52                          opname, nt_errstr(status)));
53                 st->dce_call->fault_code = DCERPC_FAULT_CANT_PERFORM;
54         }
55         status = dcesrv_reply(st->dce_call);
56         if (!NT_STATUS_IS_OK(status)) {
57                 DEBUG(0,("%s_handler: dcesrv_reply() failed - %s\n",
58                          opname, nt_errstr(status)));
59         }
60 }
61
62
63
64 /**
65  * Forward a RPC call using IRPC to another task
66  */
67 void dcesrv_irpc_forward_rpc_call(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
68                                   void *r, uint32_t callid,
69                                   const struct ndr_interface_table *ndr_table,
70                                   const char *dest_task, const char *opname,
71                                   uint32_t timeout)
72 {
73         struct dcesrv_forward_state *st;
74         struct dcerpc_binding_handle *binding_handle;
75         struct tevent_req *subreq;
76         struct auth_session_info *session_info =
77                 dcesrv_call_session_info(dce_call);
78
79         st = talloc(mem_ctx, struct dcesrv_forward_state);
80         if (st == NULL) {
81                 dce_call->fault_code = DCERPC_FAULT_CANT_PERFORM;
82                 return;
83         }
84
85         st->dce_call = dce_call;
86         st->opname   = opname;
87
88         /* if the caller has said they can't support async calls
89            then fail the call */
90         if (!(dce_call->state_flags & DCESRV_CALL_STATE_FLAG_MAY_ASYNC)) {
91                 /* we're not allowed to reply async */
92                 DEBUG(0,("%s: Not available synchronously\n", dest_task));
93                 dce_call->fault_code = DCERPC_FAULT_CANT_PERFORM;
94                 return;
95         }
96
97         binding_handle = irpc_binding_handle_by_name(st, dce_call->msg_ctx,
98                                                      dest_task, ndr_table);
99         if (binding_handle == NULL) {
100                 DEBUG(0,("%s: Failed to forward request to %s task\n",
101                          opname, dest_task));
102                 dce_call->fault_code = DCERPC_FAULT_CANT_PERFORM;
103                 return;
104         }
105
106         /* reset timeout for the handle */
107         dcerpc_binding_handle_set_timeout(binding_handle, timeout);
108
109         /* add security token to the handle*/
110         irpc_binding_handle_add_security_token(binding_handle,
111                                                session_info->security_token);
112
113         st->params.r_mem = dce_call;
114         st->params.r_ptr = r;
115         st->params.in.num_pipes = 0;
116         st->params.in.pipes = NULL;
117         st->params.out.num_pipes = 0;
118         st->params.out.pipes = NULL;
119
120         /* forward the call */
121         subreq = dcerpc_binding_handle_call_send(st, dce_call->event_ctx,
122                                                  binding_handle,
123                                                  NULL, ndr_table,
124                                                  callid, &st->params);
125         if (subreq == NULL) {
126                 DEBUG(0,("%s: Failed to forward request to %s task\n", 
127                          opname, dest_task));
128                 dce_call->fault_code = DCERPC_FAULT_CANT_PERFORM;
129                 return;
130         }
131
132         /* mark the request as replied async */
133         dce_call->state_flags |= DCESRV_CALL_STATE_FLAG_ASYNC;
134
135         /* setup the callback */
136         tevent_req_set_callback(subreq, dcesrv_irpc_forward_callback, st);
137 }