s3: use monotonic clock for time deltas in namequery functions
[Samba/ita.git] / source3 / rpc_server / rpc_ncacn_np_internal.c
blobd4cb342e1ab6f15fd31410e38478f336b10e03f0
1 /*
2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client / server routines
4 * Copyright (C) Andrew Tridgell 1992-1998,
5 * Largely re-written : 2005
6 * Copyright (C) Jeremy Allison 1998 - 2005
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.
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.
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/>.
22 #include "includes.h"
23 #include "rpc_server/srv_pipe_internal.h"
24 #include "rpc_dce.h"
26 #undef DBGC_CLASS
27 #define DBGC_CLASS DBGC_RPC_SRV
29 static int pipes_open;
31 static struct pipes_struct *InternalPipes;
33 /* TODO
34 * the following prototypes are declared here to avoid
35 * code being moved about too much for a patch to be
36 * disrupted / less obvious.
38 * these functions, and associated functions that they
39 * call, should be moved behind a .so module-loading
40 * system _anyway_. so that's the next step...
43 static int close_internal_rpc_pipe_hnd(struct pipes_struct *p);
45 /****************************************************************************
46 Internal Pipe iterator functions.
47 ****************************************************************************/
49 struct pipes_struct *get_first_internal_pipe(void)
51 return InternalPipes;
54 struct pipes_struct *get_next_internal_pipe(struct pipes_struct *p)
56 return p->next;
59 static void free_pipe_rpc_context_internal( PIPE_RPC_FNS *list )
61 PIPE_RPC_FNS *tmp = list;
62 PIPE_RPC_FNS *tmp2;
64 while (tmp) {
65 tmp2 = tmp->next;
66 SAFE_FREE(tmp);
67 tmp = tmp2;
70 return;
73 bool check_open_pipes(void)
75 struct pipes_struct *p;
77 for (p = InternalPipes; p != NULL; p = p->next) {
78 if (num_pipe_handles(p) != 0) {
79 return true;
82 return false;
85 /****************************************************************************
86 Close an rpc pipe.
87 ****************************************************************************/
89 static int close_internal_rpc_pipe_hnd(struct pipes_struct *p)
91 if (!p) {
92 DEBUG(0,("Invalid pipe in close_internal_rpc_pipe_hnd\n"));
93 return False;
96 if (p->auth.auth_data_free_func) {
97 (*p->auth.auth_data_free_func)(&p->auth);
100 free_pipe_rpc_context_internal( p->contexts );
102 /* Free the handles database. */
103 close_policy_by_pipe(p);
105 DLIST_REMOVE(InternalPipes, p);
107 ZERO_STRUCTP(p);
109 return 0;
112 /****************************************************************************
113 Make an internal namedpipes structure
114 ****************************************************************************/
116 struct pipes_struct *make_internal_rpc_pipe_p(TALLOC_CTX *mem_ctx,
117 const struct ndr_syntax_id *syntax,
118 struct client_address *client_id,
119 struct auth_serversupplied_info *server_info,
120 struct messaging_context *msg_ctx)
122 struct pipes_struct *p;
124 DEBUG(4,("Create pipe requested %s\n",
125 get_pipe_name_from_syntax(talloc_tos(), syntax)));
127 p = TALLOC_ZERO_P(mem_ctx, struct pipes_struct);
129 if (!p) {
130 DEBUG(0,("ERROR! no memory for pipes_struct!\n"));
131 return NULL;
134 p->mem_ctx = talloc_named(p, 0, "pipe %s %p",
135 get_pipe_name_from_syntax(talloc_tos(),
136 syntax), p);
137 if (p->mem_ctx == NULL) {
138 DEBUG(0,("open_rpc_pipe_p: talloc_init failed.\n"));
139 TALLOC_FREE(p);
140 return NULL;
143 if (!init_pipe_handles(p, syntax)) {
144 DEBUG(0,("open_rpc_pipe_p: init_pipe_handles failed.\n"));
145 TALLOC_FREE(p);
146 return NULL;
149 p->server_info = copy_serverinfo(p, server_info);
150 if (p->server_info == NULL) {
151 DEBUG(0, ("open_rpc_pipe_p: copy_serverinfo failed\n"));
152 close_policy_by_pipe(p);
153 TALLOC_FREE(p);
154 return NULL;
157 p->msg_ctx = msg_ctx;
159 DLIST_ADD(InternalPipes, p);
161 p->client_id = client_id;
163 p->endian = RPC_LITTLE_ENDIAN;
165 p->syntax = *syntax;
167 DEBUG(4,("Created internal pipe %s (pipes_open=%d)\n",
168 get_pipe_name_from_syntax(talloc_tos(), syntax), pipes_open));
170 talloc_set_destructor(p, close_internal_rpc_pipe_hnd);
172 return p;
175 static NTSTATUS rpcint_dispatch(struct pipes_struct *p,
176 TALLOC_CTX *mem_ctx,
177 uint32_t opnum,
178 const DATA_BLOB *in_data,
179 DATA_BLOB *out_data)
181 uint32_t num_cmds = rpc_srv_get_pipe_num_cmds(&p->syntax);
182 const struct api_struct *cmds = rpc_srv_get_pipe_cmds(&p->syntax);
183 uint32_t i;
184 bool ok;
186 /* set opnum */
187 p->opnum = opnum;
189 for (i = 0; i < num_cmds; i++) {
190 if (cmds[i].opnum == opnum && cmds[i].fn != NULL) {
191 break;
195 if (i == num_cmds) {
196 return NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE;
199 p->in_data.data = *in_data;
200 p->out_data.rdata = data_blob_null;
202 ok = cmds[i].fn(p);
203 p->in_data.data = data_blob_null;
204 if (!ok) {
205 data_blob_free(&p->out_data.rdata);
206 talloc_free_children(p->mem_ctx);
207 return NT_STATUS_RPC_CALL_FAILED;
210 if (p->fault_state) {
211 p->fault_state = false;
212 data_blob_free(&p->out_data.rdata);
213 talloc_free_children(p->mem_ctx);
214 return NT_STATUS_RPC_CALL_FAILED;
217 if (p->bad_handle_fault_state) {
218 p->bad_handle_fault_state = false;
219 data_blob_free(&p->out_data.rdata);
220 talloc_free_children(p->mem_ctx);
221 return NT_STATUS_RPC_SS_CONTEXT_MISMATCH;
224 if (p->rng_fault_state) {
225 p->rng_fault_state = false;
226 data_blob_free(&p->out_data.rdata);
227 talloc_free_children(p->mem_ctx);
228 return NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE;
231 *out_data = p->out_data.rdata;
232 talloc_steal(mem_ctx, out_data->data);
233 p->out_data.rdata = data_blob_null;
235 talloc_free_children(p->mem_ctx);
236 return NT_STATUS_OK;
239 struct rpcint_bh_state {
240 struct pipes_struct *p;
243 static bool rpcint_bh_is_connected(struct dcerpc_binding_handle *h)
245 struct rpcint_bh_state *hs = dcerpc_binding_handle_data(h,
246 struct rpcint_bh_state);
248 if (!hs->p) {
249 return false;
252 return true;
255 struct rpcint_bh_raw_call_state {
256 DATA_BLOB in_data;
257 DATA_BLOB out_data;
258 uint32_t out_flags;
261 static struct tevent_req *rpcint_bh_raw_call_send(TALLOC_CTX *mem_ctx,
262 struct tevent_context *ev,
263 struct dcerpc_binding_handle *h,
264 const struct GUID *object,
265 uint32_t opnum,
266 uint32_t in_flags,
267 const uint8_t *in_data,
268 size_t in_length)
270 struct rpcint_bh_state *hs =
271 dcerpc_binding_handle_data(h,
272 struct rpcint_bh_state);
273 struct tevent_req *req;
274 struct rpcint_bh_raw_call_state *state;
275 bool ok;
276 NTSTATUS status;
278 req = tevent_req_create(mem_ctx, &state,
279 struct rpcint_bh_raw_call_state);
280 if (req == NULL) {
281 return NULL;
283 state->in_data.data = discard_const_p(uint8_t, in_data);
284 state->in_data.length = in_length;
286 ok = rpcint_bh_is_connected(h);
287 if (!ok) {
288 tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
289 return tevent_req_post(req, ev);
292 /* TODO: allow async */
293 status = rpcint_dispatch(hs->p, state, opnum,
294 &state->in_data,
295 &state->out_data);
296 if (!NT_STATUS_IS_OK(status)) {
297 tevent_req_nterror(req, status);
298 return tevent_req_post(req, ev);
301 tevent_req_done(req);
302 return tevent_req_post(req, ev);
305 static NTSTATUS rpcint_bh_raw_call_recv(struct tevent_req *req,
306 TALLOC_CTX *mem_ctx,
307 uint8_t **out_data,
308 size_t *out_length,
309 uint32_t *out_flags)
311 struct rpcint_bh_raw_call_state *state =
312 tevent_req_data(req,
313 struct rpcint_bh_raw_call_state);
314 NTSTATUS status;
316 if (tevent_req_is_nterror(req, &status)) {
317 tevent_req_received(req);
318 return status;
321 *out_data = talloc_move(mem_ctx, &state->out_data.data);
322 *out_length = state->out_data.length;
323 *out_flags = 0;
324 tevent_req_received(req);
325 return NT_STATUS_OK;
328 struct rpcint_bh_disconnect_state {
329 uint8_t _dummy;
332 static struct tevent_req *rpcint_bh_disconnect_send(TALLOC_CTX *mem_ctx,
333 struct tevent_context *ev,
334 struct dcerpc_binding_handle *h)
336 struct rpcint_bh_state *hs = dcerpc_binding_handle_data(h,
337 struct rpcint_bh_state);
338 struct tevent_req *req;
339 struct rpcint_bh_disconnect_state *state;
340 bool ok;
342 req = tevent_req_create(mem_ctx, &state,
343 struct rpcint_bh_disconnect_state);
344 if (req == NULL) {
345 return NULL;
348 ok = rpcint_bh_is_connected(h);
349 if (!ok) {
350 tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
351 return tevent_req_post(req, ev);
355 * TODO: do a real async disconnect ...
357 * For now the caller needs to free pipes_struct
359 hs->p = NULL;
361 tevent_req_done(req);
362 return tevent_req_post(req, ev);
365 static NTSTATUS rpcint_bh_disconnect_recv(struct tevent_req *req)
367 NTSTATUS status;
369 if (tevent_req_is_nterror(req, &status)) {
370 tevent_req_received(req);
371 return status;
374 tevent_req_received(req);
375 return NT_STATUS_OK;
378 static bool rpcint_bh_ref_alloc(struct dcerpc_binding_handle *h)
380 return true;
383 static void rpcint_bh_do_ndr_print(struct dcerpc_binding_handle *h,
384 int ndr_flags,
385 const void *_struct_ptr,
386 const struct ndr_interface_call *call)
388 void *struct_ptr = discard_const(_struct_ptr);
390 if (DEBUGLEVEL < 10) {
391 return;
394 if (ndr_flags & NDR_IN) {
395 ndr_print_function_debug(call->ndr_print,
396 call->name,
397 ndr_flags,
398 struct_ptr);
400 if (ndr_flags & NDR_OUT) {
401 ndr_print_function_debug(call->ndr_print,
402 call->name,
403 ndr_flags,
404 struct_ptr);
408 static const struct dcerpc_binding_handle_ops rpcint_bh_ops = {
409 .name = "rpcint",
410 .is_connected = rpcint_bh_is_connected,
411 .raw_call_send = rpcint_bh_raw_call_send,
412 .raw_call_recv = rpcint_bh_raw_call_recv,
413 .disconnect_send = rpcint_bh_disconnect_send,
414 .disconnect_recv = rpcint_bh_disconnect_recv,
416 .ref_alloc = rpcint_bh_ref_alloc,
417 .do_ndr_print = rpcint_bh_do_ndr_print,
420 /* initialise a wbint binding handle */
421 static struct dcerpc_binding_handle *rpcint_binding_handle(struct pipes_struct *p)
423 struct dcerpc_binding_handle *h;
424 struct rpcint_bh_state *hs;
426 h = dcerpc_binding_handle_create(p,
427 &rpcint_bh_ops,
428 NULL,
429 NULL, /* TODO */
430 &hs,
431 struct rpcint_bh_state,
432 __location__);
433 if (h == NULL) {
434 return NULL;
436 hs->p = p;
438 return h;
442 * @brief Create a new RPC client context which uses a local dispatch function.
444 * @param[in] mem_ctx The memory context to use.
446 * @param[in] abstract_syntax Normally the syntax_id of the autogenerated
447 * ndr_table_<name>.
449 * @param[in] dispatch The corresponding autogenerated dispatch function
450 * rpc_<name>_dispatch.
452 * @param[in] serversupplied_info The server supplied authentication function.
454 * @param[out] presult A pointer to store the connected rpc client pipe.
456 * @return NT_STATUS_OK on success, a corresponding NT status if an
457 * error occured.
459 * @code
460 * struct rpc_pipe_client *winreg_pipe;
461 * NTSTATUS status;
463 * status = rpc_pipe_open_internal(tmp_ctx,
464 * &ndr_table_winreg.syntax_id,
465 * rpc_winreg_dispatch,
466 * p->server_info,
467 * &winreg_pipe);
468 * @endcode
470 NTSTATUS rpc_pipe_open_internal(TALLOC_CTX *mem_ctx,
471 const struct ndr_syntax_id *abstract_syntax,
472 struct auth_serversupplied_info *serversupplied_info,
473 struct client_address *client_id,
474 struct messaging_context *msg_ctx,
475 struct rpc_pipe_client **presult)
477 struct rpc_pipe_client *result;
479 result = TALLOC_ZERO_P(mem_ctx, struct rpc_pipe_client);
480 if (result == NULL) {
481 return NT_STATUS_NO_MEMORY;
484 result->abstract_syntax = *abstract_syntax;
485 result->transfer_syntax = ndr_transfer_syntax;
487 if (client_id == NULL) {
488 static struct client_address unknown;
489 strlcpy(unknown.addr, "<UNKNOWN>", sizeof(unknown.addr));
490 unknown.name = "<UNKNOWN>";
491 client_id = &unknown;
494 result->pipes_struct = make_internal_rpc_pipe_p(
495 result, abstract_syntax, client_id, serversupplied_info,
496 msg_ctx);
497 if (result->pipes_struct == NULL) {
498 TALLOC_FREE(result);
499 return NT_STATUS_NO_MEMORY;
502 result->max_xmit_frag = -1;
503 result->max_recv_frag = -1;
505 result->binding_handle = rpcint_binding_handle(result->pipes_struct);
506 if (result->binding_handle == NULL) {
507 TALLOC_FREE(result);
508 return NT_STATUS_NO_MEMORY;
511 *presult = result;
512 return NT_STATUS_OK;