2 Unix SMB/CIFS implementation.
4 Samba internal messaging functions
6 Copyright (C) Andrew Tridgell 2004
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/>.
23 #include "lib/events/events.h"
24 #include "lib/util/server_id.h"
25 #include "system/filesys.h"
26 #include "messaging/messaging.h"
27 #include "messaging/messaging_internal.h"
28 #include "../lib/util/dlinklist.h"
29 #include "lib/socket/socket.h"
30 #include "librpc/gen_ndr/ndr_irpc.h"
31 #include "lib/messaging/irpc.h"
32 #include "../lib/util/unix_privs.h"
33 #include "librpc/rpc/dcerpc.h"
34 #include "cluster/cluster.h"
35 #include "../lib/util/tevent_ntstatus.h"
36 #include "lib/param/param.h"
37 #include "lib/util/server_id_db.h"
38 #include "lib/util/talloc_report.h"
39 #include "../source3/lib/messages_dgm.h"
40 #include "../source3/lib/messages_dgm_ref.h"
41 #include "../source3/lib/messages_util.h"
44 /* change the message version with any incompatible changes in the protocol */
45 #define IMESSAGING_VERSION 1
51 struct imessaging_context
*msg_ctx
;
54 void (*handler
)(struct irpc_request
*irpc
, struct irpc_message
*m
);
59 /* we have a linked list of dispatch handlers for each msg_type that
60 this messaging server can deal with */
62 struct dispatch_fn
*next
, *prev
;
68 /* an individual message */
70 static void irpc_handler(struct imessaging_context
*, void *,
71 uint32_t, struct server_id
, DATA_BLOB
*);
75 A useful function for testing the message system.
77 static void ping_message(struct imessaging_context
*msg
, void *private_data
,
78 uint32_t msg_type
, struct server_id src
, DATA_BLOB
*data
)
80 struct server_id_buf idbuf
;
81 DEBUG(1,("INFO: Received PING message from server %s [%.*s]\n",
82 server_id_str_buf(src
, &idbuf
), (int)data
->length
,
83 data
->data
?(const char *)data
->data
:""));
84 imessaging_send(msg
, src
, MSG_PONG
, data
);
87 static void pool_message(struct imessaging_context
*msg
, void *private_data
,
88 uint32_t msg_type
, struct server_id src
,
93 report
= talloc_report_str(msg
, NULL
);
96 DATA_BLOB blob
= { .data
= (uint8_t *)report
,
97 .length
= talloc_get_size(report
) - 1};
98 imessaging_send(msg
, src
, MSG_POOL_USAGE
, &blob
);
103 static void ringbuf_log_msg(struct imessaging_context
*msg
,
106 struct server_id src
,
109 char *log
= debug_get_ringbuf();
110 size_t logsize
= debug_get_ringbuf_size();
114 log
= discard_const_p(char, "*disabled*\n");
115 logsize
= strlen(log
) + 1;
118 blob
.data
= (uint8_t *)log
;
119 blob
.length
= logsize
;
121 imessaging_send(msg
, src
, MSG_RINGBUF_LOG
, &blob
);
125 return uptime of messaging server via irpc
127 static NTSTATUS
irpc_uptime(struct irpc_message
*msg
,
128 struct irpc_uptime
*r
)
130 struct imessaging_context
*ctx
= talloc_get_type(msg
->private_data
, struct imessaging_context
);
131 *r
->out
.start_time
= timeval_to_nttime(&ctx
->start_time
);
135 static struct dispatch_fn
*imessaging_find_dispatch(
136 struct imessaging_context
*msg
, uint32_t msg_type
)
138 /* temporary IDs use an idtree, the rest use a array of pointers */
139 if (msg_type
>= MSG_TMP_BASE
) {
140 return (struct dispatch_fn
*)idr_find(msg
->dispatch_tree
,
143 if (msg_type
< msg
->num_types
) {
144 return msg
->dispatch
[msg_type
];
150 Register a dispatch function for a particular message type.
152 NTSTATUS
imessaging_register(struct imessaging_context
*msg
, void *private_data
,
153 uint32_t msg_type
, msg_callback_t fn
)
155 struct dispatch_fn
*d
;
157 /* possibly expand dispatch array */
158 if (msg_type
>= msg
->num_types
) {
159 struct dispatch_fn
**dp
;
161 dp
= talloc_realloc(msg
, msg
->dispatch
, struct dispatch_fn
*, msg_type
+1);
162 NT_STATUS_HAVE_NO_MEMORY(dp
);
164 for (i
=msg
->num_types
;i
<=msg_type
;i
++) {
165 msg
->dispatch
[i
] = NULL
;
167 msg
->num_types
= msg_type
+1;
170 d
= talloc_zero(msg
->dispatch
, struct dispatch_fn
);
171 NT_STATUS_HAVE_NO_MEMORY(d
);
172 d
->msg_type
= msg_type
;
173 d
->private_data
= private_data
;
176 DLIST_ADD(msg
->dispatch
[msg_type
], d
);
182 register a temporary message handler. The msg_type is allocated
185 NTSTATUS
imessaging_register_tmp(struct imessaging_context
*msg
, void *private_data
,
186 msg_callback_t fn
, uint32_t *msg_type
)
188 struct dispatch_fn
*d
;
191 d
= talloc_zero(msg
->dispatch
, struct dispatch_fn
);
192 NT_STATUS_HAVE_NO_MEMORY(d
);
193 d
->private_data
= private_data
;
196 id
= idr_get_new_above(msg
->dispatch_tree
, d
, MSG_TMP_BASE
, UINT16_MAX
);
199 return NT_STATUS_TOO_MANY_CONTEXT_IDS
;
202 d
->msg_type
= (uint32_t)id
;
203 (*msg_type
) = d
->msg_type
;
209 De-register the function for a particular message type.
211 void imessaging_deregister(struct imessaging_context
*msg
, uint32_t msg_type
, void *private_data
)
213 struct dispatch_fn
*d
, *next
;
215 if (msg_type
>= msg
->num_types
) {
216 d
= (struct dispatch_fn
*)idr_find(msg
->dispatch_tree
,
219 idr_remove(msg
->dispatch_tree
, msg_type
);
224 for (d
= msg
->dispatch
[msg_type
]; d
; d
= next
) {
226 if (d
->private_data
== private_data
) {
227 DLIST_REMOVE(msg
->dispatch
[msg_type
], d
);
235 int imessaging_cleanup(struct imessaging_context
*msg
)
243 static void imessaging_dgm_recv(struct tevent_context
*ev
,
244 const uint8_t *buf
, size_t buf_len
,
245 int *fds
, size_t num_fds
,
248 /* Keep a list of imessaging contexts */
249 static struct imessaging_context
*msg_ctxs
;
252 * A process has terminated, clean-up any names it has registered.
254 NTSTATUS
imessaging_process_cleanup(
255 struct imessaging_context
*msg_ctx
,
258 struct irpc_name_records
*names
= NULL
;
261 TALLOC_CTX
*mem_ctx
= talloc_new(NULL
);
263 if (mem_ctx
== NULL
) {
264 DBG_ERR("OOM unable to clean up messaging for process (%d)\n",
266 return NT_STATUS_NO_MEMORY
;
269 names
= irpc_all_servers(msg_ctx
, mem_ctx
);
271 TALLOC_FREE(mem_ctx
);
274 for (i
= 0; i
< names
->num_records
; i
++) {
275 for (j
= 0; j
< names
->names
[i
]->count
; j
++) {
276 if (names
->names
[i
]->ids
[j
].pid
== pid
) {
277 int ret
= server_id_db_prune_name(
279 names
->names
[i
]->name
,
280 names
->names
[i
]->ids
[j
]);
281 if (ret
!= 0 && ret
!= ENOENT
) {
282 TALLOC_FREE(mem_ctx
);
283 return map_nt_error_from_unix_common(
289 TALLOC_FREE(mem_ctx
);
293 static int imessaging_context_destructor(struct imessaging_context
*msg
)
295 DLIST_REMOVE(msg_ctxs
, msg
);
296 TALLOC_FREE(msg
->msg_dgm_ref
);
301 * Cleanup messaging dgm contexts on a specific event context.
303 * We must make sure to unref all messaging_dgm_ref's *before* the
304 * tevent context goes away. Only when the last ref is freed, the
305 * refcounted messaging dgm context will be freed.
307 void imessaging_dgm_unref_ev(struct tevent_context
*ev
)
309 struct imessaging_context
*msg
= NULL
;
311 for (msg
= msg_ctxs
; msg
!= NULL
; msg
= msg
->next
) {
313 TALLOC_FREE(msg
->msg_dgm_ref
);
318 static NTSTATUS
imessaging_reinit(struct imessaging_context
*msg
)
322 TALLOC_FREE(msg
->msg_dgm_ref
);
324 msg
->server_id
.pid
= getpid();
326 msg
->msg_dgm_ref
= messaging_dgm_ref(msg
,
328 &msg
->server_id
.unique_id
,
335 if (msg
->msg_dgm_ref
== NULL
) {
336 DEBUG(2, ("messaging_dgm_ref failed: %s\n",
338 return map_nt_error_from_unix_common(ret
);
341 server_id_db_reinit(msg
->names
, msg
->server_id
);
346 * Must be called after a fork.
348 NTSTATUS
imessaging_reinit_all(void)
350 struct imessaging_context
*msg
= NULL
;
352 for (msg
= msg_ctxs
; msg
!= NULL
; msg
= msg
->next
) {
353 NTSTATUS status
= imessaging_reinit(msg
);
354 if (!NT_STATUS_IS_OK(status
)) {
362 create the listening socket and setup the dispatcher
364 static struct imessaging_context
*imessaging_init_internal(TALLOC_CTX
*mem_ctx
,
365 struct loadparm_context
*lp_ctx
,
366 struct server_id server_id
,
367 struct tevent_context
*ev
)
370 struct imessaging_context
*msg
;
373 const char *lock_dir
= NULL
;
374 int tdb_flags
= TDB_INCOMPATIBLE_HASH
| TDB_CLEAR_IF_FIRST
;
380 msg
= talloc_zero(mem_ctx
, struct imessaging_context
);
386 talloc_set_destructor(msg
, imessaging_context_destructor
);
388 /* create the messaging directory if needed */
390 lock_dir
= lpcfg_lock_directory(lp_ctx
);
391 if (lock_dir
== NULL
) {
395 msg
->sock_dir
= lpcfg_private_path(msg
, lp_ctx
, "msg.sock");
396 if (msg
->sock_dir
== NULL
) {
399 ok
= directory_create_or_exist_strict(msg
->sock_dir
, geteuid(), 0700);
404 msg
->lock_dir
= lpcfg_lock_path(msg
, lp_ctx
, "msg.lock");
405 if (msg
->lock_dir
== NULL
) {
408 ok
= directory_create_or_exist_strict(msg
->lock_dir
, geteuid(), 0755);
413 msg
->msg_dgm_ref
= messaging_dgm_ref(
414 msg
, ev
, &server_id
.unique_id
, msg
->sock_dir
, msg
->lock_dir
,
415 imessaging_dgm_recv
, msg
, &ret
);
417 if (msg
->msg_dgm_ref
== NULL
) {
421 msg
->server_id
= server_id
;
422 msg
->idr
= idr_init(msg
);
423 if (msg
->idr
== NULL
) {
427 msg
->dispatch_tree
= idr_init(msg
);
428 if (msg
->dispatch_tree
== NULL
) {
432 msg
->start_time
= timeval_current();
434 tdb_flags
|= lpcfg_tdb_flags(lp_ctx
, 0);
437 * This context holds a destructor that cleans up any names
438 * registered on this context on talloc_free()
440 msg
->names
= server_id_db_init(msg
, server_id
, lock_dir
, 0, tdb_flags
);
441 if (msg
->names
== NULL
) {
445 status
= imessaging_register(msg
, NULL
, MSG_PING
, ping_message
);
446 if (!NT_STATUS_IS_OK(status
)) {
449 status
= imessaging_register(msg
, NULL
, MSG_REQ_POOL_USAGE
,
451 if (!NT_STATUS_IS_OK(status
)) {
454 status
= imessaging_register(msg
, NULL
, MSG_IRPC
, irpc_handler
);
455 if (!NT_STATUS_IS_OK(status
)) {
458 status
= imessaging_register(msg
, NULL
, MSG_REQ_RINGBUF_LOG
,
460 if (!NT_STATUS_IS_OK(status
)) {
463 status
= IRPC_REGISTER(msg
, irpc
, IRPC_UPTIME
, irpc_uptime
, msg
);
464 if (!NT_STATUS_IS_OK(status
)) {
467 #if defined(DEVELOPER) || defined(ENABLE_SELFTEST)
469 * Register handlers for messages specific to developer and
472 status
= imessaging_register_extra_handlers(msg
);
473 if (!NT_STATUS_IS_OK(status
)) {
476 #endif /* defined(DEVELOPER) || defined(ENABLE_SELFTEST) */
478 DLIST_ADD(msg_ctxs
, msg
);
486 struct imessaging_post_state
{
487 struct imessaging_context
*msg_ctx
;
488 struct imessaging_post_state
**busy_ref
;
493 static int imessaging_post_state_destructor(struct imessaging_post_state
*state
)
495 if (state
->busy_ref
!= NULL
) {
496 *state
->busy_ref
= NULL
;
497 state
->busy_ref
= NULL
;
502 static void imessaging_post_handler(struct tevent_context
*ev
,
503 struct tevent_immediate
*ti
,
506 struct imessaging_post_state
*state
= talloc_get_type_abort(
507 private_data
, struct imessaging_post_state
);
510 * In usecases like using messaging_client_init() with irpc processing
511 * we may free the imessaging_context during the messaging handler.
512 * imessaging_post_state is a child of imessaging_context and
513 * might be implicitly free'ed before the explicit TALLOC_FREE(state).
515 * The busy_ref pointer makes sure the destructor clears
516 * the local 'state' variable.
519 SMB_ASSERT(state
->busy_ref
== NULL
);
520 state
->busy_ref
= &state
;
522 imessaging_dgm_recv(ev
, state
->buf
, state
->buf_len
, NULL
, 0,
529 state
->busy_ref
= NULL
;
533 static int imessaging_post_self(struct imessaging_context
*msg
,
534 const uint8_t *buf
, size_t buf_len
)
536 struct tevent_immediate
*ti
;
537 struct imessaging_post_state
*state
;
540 msg
, offsetof(struct imessaging_post_state
, buf
) + buf_len
);
544 talloc_set_name_const(state
, "struct imessaging_post_state");
546 talloc_set_destructor(state
, imessaging_post_state_destructor
);
548 ti
= tevent_create_immediate(state
);
554 state
->msg_ctx
= msg
;
555 state
->busy_ref
= NULL
;
556 state
->buf_len
= buf_len
;
557 memcpy(state
->buf
, buf
, buf_len
);
559 tevent_schedule_immediate(ti
, msg
->ev
, imessaging_post_handler
,
565 static void imessaging_dgm_recv(struct tevent_context
*ev
,
566 const uint8_t *buf
, size_t buf_len
,
567 int *fds
, size_t num_fds
,
570 struct imessaging_context
*msg
= talloc_get_type_abort(
571 private_data
, struct imessaging_context
);
573 struct server_id src
, dst
;
574 struct server_id_buf srcbuf
, dstbuf
;
577 if (buf_len
< MESSAGE_HDR_LENGTH
) {
578 /* Invalid message, ignore */
584 * Source4 based messaging does not expect fd's yet
591 ret
= imessaging_post_self(msg
, buf
, buf_len
);
593 DBG_WARNING("imessaging_post_self failed: %s\n",
599 message_hdr_get(&msg_type
, &src
, &dst
, buf
);
601 data
.data
= discard_const_p(uint8_t, buf
+ MESSAGE_HDR_LENGTH
);
602 data
.length
= buf_len
- MESSAGE_HDR_LENGTH
;
604 if ((cluster_id_equal(&dst
, &msg
->server_id
)) ||
605 ((dst
.task_id
== 0) && (msg
->server_id
.pid
== 0))) {
606 struct dispatch_fn
*d
, *next
;
608 DEBUG(10, ("%s: dst %s matches my id: %s, type=0x%x\n",
610 server_id_str_buf(dst
, &dstbuf
),
611 server_id_str_buf(msg
->server_id
, &srcbuf
),
612 (unsigned)msg_type
));
614 d
= imessaging_find_dispatch(msg
, msg_type
);
616 for (; d
; d
= next
) {
618 d
->fn(msg
, d
->private_data
, d
->msg_type
, src
, &data
);
621 DEBUG(10, ("%s: Ignoring type=0x%x dst %s, I am %s, \n",
622 __func__
, (unsigned)msg_type
,
623 server_id_str_buf(dst
, &dstbuf
),
624 server_id_str_buf(msg
->server_id
, &srcbuf
)));
628 struct imessaging_context
*imessaging_init(TALLOC_CTX
*mem_ctx
,
629 struct loadparm_context
*lp_ctx
,
630 struct server_id server_id
,
631 struct tevent_context
*ev
)
637 if (tevent_context_is_wrapper(ev
)) {
639 * This is really a programmer error!
641 * The main/raw tevent context should
642 * have been registered first!
644 DBG_ERR("Should not be used with a wrapper tevent context\n");
649 return imessaging_init_internal(mem_ctx
, lp_ctx
, server_id
, ev
);
653 A hack, for the short term until we get 'client only' messaging in place
655 struct imessaging_context
*imessaging_client_init(TALLOC_CTX
*mem_ctx
,
656 struct loadparm_context
*lp_ctx
,
657 struct tevent_context
*ev
)
662 id
.task_id
= generate_random();
663 id
.vnn
= NONCLUSTER_VNN
;
665 /* This is because we are not in the s3 serverid database */
666 id
.unique_id
= SERVERID_UNIQUE_ID_NOT_TO_VERIFY
;
668 return imessaging_init_internal(mem_ctx
, lp_ctx
, id
, ev
);
671 a list of registered irpc server functions
674 struct irpc_list
*next
, *prev
;
676 const struct ndr_interface_table
*table
;
684 register a irpc server function
686 NTSTATUS
irpc_register(struct imessaging_context
*msg_ctx
,
687 const struct ndr_interface_table
*table
,
688 int callnum
, irpc_function_t fn
, void *private_data
)
690 struct irpc_list
*irpc
;
692 /* override an existing handler, if any */
693 for (irpc
=msg_ctx
->irpc
; irpc
; irpc
=irpc
->next
) {
694 if (irpc
->table
== table
&& irpc
->callnum
== callnum
) {
699 irpc
= talloc(msg_ctx
, struct irpc_list
);
700 NT_STATUS_HAVE_NO_MEMORY(irpc
);
701 DLIST_ADD(msg_ctx
->irpc
, irpc
);
705 irpc
->callnum
= callnum
;
707 irpc
->private_data
= private_data
;
708 irpc
->uuid
= irpc
->table
->syntax_id
.uuid
;
715 handle an incoming irpc reply message
717 static void irpc_handler_reply(struct imessaging_context
*msg_ctx
, struct irpc_message
*m
)
719 struct irpc_request
*irpc
;
721 irpc
= (struct irpc_request
*)idr_find(msg_ctx
->idr
, m
->header
.callid
);
722 if (irpc
== NULL
) return;
724 irpc
->incoming
.handler(irpc
, m
);
730 NTSTATUS
irpc_send_reply(struct irpc_message
*m
, NTSTATUS status
)
732 struct ndr_push
*push
;
734 enum ndr_err_code ndr_err
;
736 m
->header
.status
= status
;
738 /* setup the reply */
739 push
= ndr_push_init_ctx(m
->ndr
);
741 status
= NT_STATUS_NO_MEMORY
;
745 m
->header
.flags
|= IRPC_FLAG_REPLY
;
746 m
->header
.creds
.token
= NULL
;
748 /* construct the packet */
749 ndr_err
= ndr_push_irpc_header(push
, NDR_SCALARS
|NDR_BUFFERS
, &m
->header
);
750 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
751 status
= ndr_map_error2ntstatus(ndr_err
);
755 ndr_err
= m
->irpc
->table
->calls
[m
->irpc
->callnum
].ndr_push(push
, NDR_OUT
, m
->data
);
756 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
757 status
= ndr_map_error2ntstatus(ndr_err
);
761 /* send the reply message */
762 packet
= ndr_push_blob(push
);
763 status
= imessaging_send(m
->msg_ctx
, m
->from
, MSG_IRPC
, &packet
);
764 if (!NT_STATUS_IS_OK(status
)) goto failed
;
772 handle an incoming irpc request message
774 static void irpc_handler_request(struct imessaging_context
*msg_ctx
,
775 struct irpc_message
*m
)
779 enum ndr_err_code ndr_err
;
781 for (i
=msg_ctx
->irpc
; i
; i
=i
->next
) {
782 if (GUID_equal(&i
->uuid
, &m
->header
.uuid
) &&
783 i
->table
->syntax_id
.if_version
== m
->header
.if_version
&&
784 i
->callnum
== m
->header
.callnum
) {
790 /* no registered handler for this message */
795 /* allocate space for the structure */
796 r
= talloc_zero_size(m
->ndr
, i
->table
->calls
[m
->header
.callnum
].struct_size
);
797 if (r
== NULL
) goto failed
;
799 m
->ndr
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
801 /* parse the request data */
802 ndr_err
= i
->table
->calls
[i
->callnum
].ndr_pull(m
->ndr
, NDR_IN
, r
);
803 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) goto failed
;
806 m
->private_data
= i
->private_data
;
807 m
->defer_reply
= false;
809 m
->msg_ctx
= msg_ctx
;
813 m
->header
.status
= i
->fn(m
, r
);
816 /* the server function won't ever be replying to this request */
821 if (m
->defer_reply
) {
822 /* the server function has asked to defer the reply to later */
823 talloc_steal(msg_ctx
, m
);
827 irpc_send_reply(m
, m
->header
.status
);
835 handle an incoming irpc message
837 static void irpc_handler(struct imessaging_context
*msg_ctx
, void *private_data
,
838 uint32_t msg_type
, struct server_id src
, DATA_BLOB
*packet
)
840 struct irpc_message
*m
;
841 enum ndr_err_code ndr_err
;
843 m
= talloc(msg_ctx
, struct irpc_message
);
844 if (m
== NULL
) goto failed
;
848 m
->ndr
= ndr_pull_init_blob(packet
, m
);
849 if (m
->ndr
== NULL
) goto failed
;
851 m
->ndr
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
853 ndr_err
= ndr_pull_irpc_header(m
->ndr
, NDR_BUFFERS
|NDR_SCALARS
, &m
->header
);
854 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) goto failed
;
856 if (m
->header
.flags
& IRPC_FLAG_REPLY
) {
857 irpc_handler_reply(msg_ctx
, m
);
859 irpc_handler_request(msg_ctx
, m
);
869 destroy a irpc request
871 static int irpc_destructor(struct irpc_request
*irpc
)
873 if (irpc
->callid
!= -1) {
874 idr_remove(irpc
->msg_ctx
->idr
, irpc
->callid
);
882 add a string name that this irpc server can be called on
884 It will be removed from the DB either via irpc_remove_name or on
885 talloc_free(msg_ctx->names).
887 NTSTATUS
irpc_add_name(struct imessaging_context
*msg_ctx
, const char *name
)
891 ret
= server_id_db_add(msg_ctx
->names
, name
);
893 return map_nt_error_from_unix_common(ret
);
898 static int all_servers_func(const char *name
, unsigned num_servers
,
899 const struct server_id
*servers
,
902 struct irpc_name_records
*name_records
= talloc_get_type(
903 private_data
, struct irpc_name_records
);
904 struct irpc_name_record
*name_record
;
908 = talloc_realloc(name_records
, name_records
->names
,
909 struct irpc_name_record
*, name_records
->num_records
+1);
910 if (!name_records
->names
) {
914 name_records
->names
[name_records
->num_records
] = name_record
915 = talloc(name_records
->names
,
916 struct irpc_name_record
);
921 name_records
->num_records
++;
923 name_record
->name
= talloc_strdup(name_record
, name
);
924 if (!name_record
->name
) {
928 name_record
->count
= num_servers
;
929 name_record
->ids
= talloc_array(name_record
, struct server_id
,
931 if (name_record
->ids
== NULL
) {
934 for (i
=0;i
<name_record
->count
;i
++) {
935 name_record
->ids
[i
] = servers
[i
];
941 return a list of server ids for a server name
943 struct irpc_name_records
*irpc_all_servers(struct imessaging_context
*msg_ctx
,
947 struct irpc_name_records
*name_records
= talloc_zero(mem_ctx
, struct irpc_name_records
);
948 if (name_records
== NULL
) {
952 ret
= server_id_db_traverse_read(msg_ctx
->names
, all_servers_func
,
955 TALLOC_FREE(name_records
);
963 remove a name from a messaging context
965 void irpc_remove_name(struct imessaging_context
*msg_ctx
, const char *name
)
967 server_id_db_remove(msg_ctx
->names
, name
);
970 struct server_id
imessaging_get_server_id(struct imessaging_context
*msg_ctx
)
972 return msg_ctx
->server_id
;
975 struct irpc_bh_state
{
976 struct imessaging_context
*msg_ctx
;
977 struct server_id server_id
;
978 const struct ndr_interface_table
*table
;
980 struct security_token
*token
;
983 static bool irpc_bh_is_connected(struct dcerpc_binding_handle
*h
)
985 struct irpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
986 struct irpc_bh_state
);
995 static uint32_t irpc_bh_set_timeout(struct dcerpc_binding_handle
*h
,
998 struct irpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
999 struct irpc_bh_state
);
1000 uint32_t old
= hs
->timeout
;
1002 hs
->timeout
= timeout
;
1007 struct irpc_bh_raw_call_state
{
1008 struct irpc_request
*irpc
;
1011 DATA_BLOB in_packet
;
1015 static void irpc_bh_raw_call_incoming_handler(struct irpc_request
*irpc
,
1016 struct irpc_message
*m
);
1018 static struct tevent_req
*irpc_bh_raw_call_send(TALLOC_CTX
*mem_ctx
,
1019 struct tevent_context
*ev
,
1020 struct dcerpc_binding_handle
*h
,
1021 const struct GUID
*object
,
1024 const uint8_t *in_data
,
1027 struct irpc_bh_state
*hs
=
1028 dcerpc_binding_handle_data(h
,
1029 struct irpc_bh_state
);
1030 struct tevent_req
*req
;
1031 struct irpc_bh_raw_call_state
*state
;
1033 struct irpc_header header
;
1034 struct ndr_push
*ndr
;
1036 enum ndr_err_code ndr_err
;
1038 req
= tevent_req_create(mem_ctx
, &state
,
1039 struct irpc_bh_raw_call_state
);
1043 state
->opnum
= opnum
;
1044 state
->in_data
.data
= discard_const_p(uint8_t, in_data
);
1045 state
->in_data
.length
= in_length
;
1047 ok
= irpc_bh_is_connected(h
);
1049 tevent_req_nterror(req
, NT_STATUS_CONNECTION_DISCONNECTED
);
1050 return tevent_req_post(req
, ev
);
1053 state
->irpc
= talloc_zero(state
, struct irpc_request
);
1054 if (tevent_req_nomem(state
->irpc
, req
)) {
1055 return tevent_req_post(req
, ev
);
1058 state
->irpc
->msg_ctx
= hs
->msg_ctx
;
1059 state
->irpc
->callid
= idr_get_new(hs
->msg_ctx
->idr
,
1060 state
->irpc
, UINT16_MAX
);
1061 if (state
->irpc
->callid
== -1) {
1062 tevent_req_nterror(req
, NT_STATUS_INSUFFICIENT_RESOURCES
);
1063 return tevent_req_post(req
, ev
);
1065 state
->irpc
->incoming
.handler
= irpc_bh_raw_call_incoming_handler
;
1066 state
->irpc
->incoming
.private_data
= req
;
1068 talloc_set_destructor(state
->irpc
, irpc_destructor
);
1070 /* setup the header */
1071 header
.uuid
= hs
->table
->syntax_id
.uuid
;
1073 header
.if_version
= hs
->table
->syntax_id
.if_version
;
1074 header
.callid
= state
->irpc
->callid
;
1075 header
.callnum
= state
->opnum
;
1077 header
.status
= NT_STATUS_OK
;
1078 header
.creds
.token
= hs
->token
;
1080 /* construct the irpc packet */
1081 ndr
= ndr_push_init_ctx(state
->irpc
);
1082 if (tevent_req_nomem(ndr
, req
)) {
1083 return tevent_req_post(req
, ev
);
1086 ndr_err
= ndr_push_irpc_header(ndr
, NDR_SCALARS
|NDR_BUFFERS
, &header
);
1087 status
= ndr_map_error2ntstatus(ndr_err
);
1088 if (!NT_STATUS_IS_OK(status
)) {
1089 tevent_req_nterror(req
, status
);
1090 return tevent_req_post(req
, ev
);
1093 ndr_err
= ndr_push_bytes(ndr
, in_data
, in_length
);
1094 status
= ndr_map_error2ntstatus(ndr_err
);
1095 if (!NT_STATUS_IS_OK(status
)) {
1096 tevent_req_nterror(req
, status
);
1097 return tevent_req_post(req
, ev
);
1101 state
->in_packet
= ndr_push_blob(ndr
);
1102 status
= imessaging_send(hs
->msg_ctx
, hs
->server_id
,
1103 MSG_IRPC
, &state
->in_packet
);
1104 if (!NT_STATUS_IS_OK(status
)) {
1105 tevent_req_nterror(req
, status
);
1106 return tevent_req_post(req
, ev
);
1109 if (hs
->timeout
!= IRPC_CALL_TIMEOUT_INF
) {
1110 /* set timeout-callback in case caller wants that */
1111 ok
= tevent_req_set_endtime(req
, ev
, timeval_current_ofs(hs
->timeout
, 0));
1113 return tevent_req_post(req
, ev
);
1120 static void irpc_bh_raw_call_incoming_handler(struct irpc_request
*irpc
,
1121 struct irpc_message
*m
)
1123 struct tevent_req
*req
=
1124 talloc_get_type_abort(irpc
->incoming
.private_data
,
1126 struct irpc_bh_raw_call_state
*state
=
1127 tevent_req_data(req
,
1128 struct irpc_bh_raw_call_state
);
1130 talloc_steal(state
, m
);
1132 if (!NT_STATUS_IS_OK(m
->header
.status
)) {
1133 tevent_req_nterror(req
, m
->header
.status
);
1137 state
->out_data
= data_blob_talloc(state
,
1138 m
->ndr
->data
+ m
->ndr
->offset
,
1139 m
->ndr
->data_size
- m
->ndr
->offset
);
1140 if ((m
->ndr
->data_size
- m
->ndr
->offset
) > 0 && !state
->out_data
.data
) {
1141 tevent_req_oom(req
);
1145 tevent_req_done(req
);
1148 static NTSTATUS
irpc_bh_raw_call_recv(struct tevent_req
*req
,
1149 TALLOC_CTX
*mem_ctx
,
1152 uint32_t *out_flags
)
1154 struct irpc_bh_raw_call_state
*state
=
1155 tevent_req_data(req
,
1156 struct irpc_bh_raw_call_state
);
1159 if (tevent_req_is_nterror(req
, &status
)) {
1160 tevent_req_received(req
);
1164 *out_data
= talloc_move(mem_ctx
, &state
->out_data
.data
);
1165 *out_length
= state
->out_data
.length
;
1167 tevent_req_received(req
);
1168 return NT_STATUS_OK
;
1171 struct irpc_bh_disconnect_state
{
1175 static struct tevent_req
*irpc_bh_disconnect_send(TALLOC_CTX
*mem_ctx
,
1176 struct tevent_context
*ev
,
1177 struct dcerpc_binding_handle
*h
)
1179 struct irpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
1180 struct irpc_bh_state
);
1181 struct tevent_req
*req
;
1182 struct irpc_bh_disconnect_state
*state
;
1185 req
= tevent_req_create(mem_ctx
, &state
,
1186 struct irpc_bh_disconnect_state
);
1191 ok
= irpc_bh_is_connected(h
);
1193 tevent_req_nterror(req
, NT_STATUS_CONNECTION_DISCONNECTED
);
1194 return tevent_req_post(req
, ev
);
1199 tevent_req_done(req
);
1200 return tevent_req_post(req
, ev
);
1203 static NTSTATUS
irpc_bh_disconnect_recv(struct tevent_req
*req
)
1207 if (tevent_req_is_nterror(req
, &status
)) {
1208 tevent_req_received(req
);
1212 tevent_req_received(req
);
1213 return NT_STATUS_OK
;
1216 static bool irpc_bh_ref_alloc(struct dcerpc_binding_handle
*h
)
1221 static const struct dcerpc_binding_handle_ops irpc_bh_ops
= {
1223 .is_connected
= irpc_bh_is_connected
,
1224 .set_timeout
= irpc_bh_set_timeout
,
1225 .raw_call_send
= irpc_bh_raw_call_send
,
1226 .raw_call_recv
= irpc_bh_raw_call_recv
,
1227 .disconnect_send
= irpc_bh_disconnect_send
,
1228 .disconnect_recv
= irpc_bh_disconnect_recv
,
1230 .ref_alloc
= irpc_bh_ref_alloc
,
1233 /* initialise a irpc binding handle */
1234 struct dcerpc_binding_handle
*irpc_binding_handle(TALLOC_CTX
*mem_ctx
,
1235 struct imessaging_context
*msg_ctx
,
1236 struct server_id server_id
,
1237 const struct ndr_interface_table
*table
)
1239 struct dcerpc_binding_handle
*h
;
1240 struct irpc_bh_state
*hs
;
1242 h
= dcerpc_binding_handle_create(mem_ctx
,
1247 struct irpc_bh_state
,
1252 hs
->msg_ctx
= msg_ctx
;
1253 hs
->server_id
= server_id
;
1255 hs
->timeout
= IRPC_CALL_TIMEOUT
;
1260 struct dcerpc_binding_handle
*irpc_binding_handle_by_name(TALLOC_CTX
*mem_ctx
,
1261 struct imessaging_context
*msg_ctx
,
1262 const char *dest_task
,
1263 const struct ndr_interface_table
*table
)
1265 struct dcerpc_binding_handle
*h
;
1267 struct server_id
*sids
;
1268 struct server_id sid
;
1271 /* find the server task */
1273 status
= irpc_servers_byname(msg_ctx
, mem_ctx
, dest_task
,
1275 if (!NT_STATUS_IS_OK(status
)) {
1276 errno
= EADDRNOTAVAIL
;
1282 h
= irpc_binding_handle(mem_ctx
, msg_ctx
,
1291 void irpc_binding_handle_add_security_token(struct dcerpc_binding_handle
*h
,
1292 struct security_token
*token
)
1294 struct irpc_bh_state
*hs
=
1295 dcerpc_binding_handle_data(h
,
1296 struct irpc_bh_state
);