2 * Unix SMB/CIFS implementation.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 #include "source3/include/includes.h"
19 #include "lib/cmdline/cmdline.h"
20 #include "rpc_worker.h"
21 #include "rpc_config.h"
22 #include "librpc/rpc/dcesrv_core.h"
23 #include "librpc/rpc/dcerpc_util.h"
24 #include "source3/librpc/gen_ndr/ndr_rpc_host.h"
25 #include "lib/util/debug.h"
26 #include "lib/util/fault.h"
27 #include "lib/util/util_file.h"
28 #include "rpc_server.h"
29 #include "rpc_pipes.h"
30 #include "source3/smbd/proto.h"
31 #include "source3/lib/smbd_shim.h"
32 #include "source3/lib/global_contexts.h"
33 #include "source3/lib/util_procid.h"
34 #include "lib/tsocket/tsocket.h"
35 #include "libcli/named_pipe_auth/npa_tstream.h"
36 #include "libcli/smb/smb_constants.h"
37 #include "lib/param/param.h"
38 #include "lib/util/idtree_random.h"
39 #include "lib/util/tevent_unix.h"
40 #include "lib/async_req/async_sock.h"
41 #include "lib/util/dlinklist.h"
42 #include "source3/include/auth.h"
43 #include "nsswitch/winbind_client.h"
44 #include "source3/include/messages.h"
45 #include "libcli/security/security_token.h"
46 #include "libcli/security/dom_sid.h"
47 #include "source3/include/proto.h"
50 * This is the generic code that becomes the
51 * template that all rpcd_* instances that
52 * serve DCERPC can use to provide services to samba-dcerpcd.
54 * The external entry point is:
55 * rpc_worker_main() which takes an argc/argv list
58 * get_interfaces() - List all interfaces that this server provides
59 * get_servers() - Provide the RPC server implementations
61 * Each rpcd_* service needs only to provide
62 * the implementations of get_interfaces() and get_servers()
63 * and call rpc_worker_main() from their main() function
64 * to provide services that can be connected to from samba-dcerpcd.
68 struct dcerpc_ncacn_conn
*conns
;
69 struct server_id rpc_host_pid
;
70 struct messaging_context
*msg_ctx
;
71 struct dcesrv_context
*dce_ctx
;
73 struct dcesrv_context_callbacks cb
;
75 struct rpc_worker_status status
;
80 static void rpc_worker_print_interface(
81 FILE *f
, const struct ndr_interface_table
*t
)
83 const struct ndr_interface_string_array
*endpoints
= t
->endpoints
;
85 struct ndr_syntax_id_buf id_buf
;
89 ndr_syntax_id_buf_string(&t
->syntax_id
, &id_buf
),
92 for (i
=0; i
<endpoints
->count
; i
++) {
93 fprintf(f
, " %s\n", endpoints
->names
[i
]);
97 static NTSTATUS
rpc_worker_report_status(struct rpc_worker
*worker
)
100 DATA_BLOB blob
= { .data
= buf
, .length
= sizeof(buf
), };
101 enum ndr_err_code ndr_err
;
104 worker
->status
.num_association_groups
= worker
->dce_ctx
->assoc_groups_num
;
106 if (DEBUGLEVEL
>= 10) {
107 NDR_PRINT_DEBUG(rpc_worker_status
, &worker
->status
);
110 ndr_err
= ndr_push_struct_into_fixed_blob(
113 (ndr_push_flags_fn_t
)ndr_push_rpc_worker_status
);
114 SMB_ASSERT(NDR_ERR_CODE_IS_SUCCESS(ndr_err
));
116 status
= messaging_send(
118 worker
->rpc_host_pid
,
119 MSG_RPC_WORKER_STATUS
,
124 static void rpc_worker_connection_terminated(
125 struct dcesrv_connection
*conn
, void *private_data
)
127 struct rpc_worker
*worker
= talloc_get_type_abort(
128 private_data
, struct rpc_worker
);
129 struct dcerpc_ncacn_conn
*ncacn_conn
= talloc_get_type_abort(
130 conn
->transport
.private_data
, struct dcerpc_ncacn_conn
);
131 struct dcerpc_ncacn_conn
*w
= NULL
;
136 * We need to drop the association group reference
137 * explicitly here in order to avoid the order given
138 * by the destructors. rpc_worker_report_status() below,
139 * expects worker->dce_ctx->assoc_groups_num to be updated
142 if (conn
->assoc_group
!= NULL
) {
143 talloc_unlink(conn
, conn
->assoc_group
);
144 conn
->assoc_group
= NULL
;
147 SMB_ASSERT(worker
->status
.num_connections
> 0);
149 for (w
= worker
->conns
; w
!= NULL
; w
= w
->next
) {
150 if (w
== ncacn_conn
) {
157 DLIST_REMOVE(worker
->conns
, ncacn_conn
);
159 worker
->status
.num_connections
-= 1;
161 status
= rpc_worker_report_status(worker
);
162 if (!NT_STATUS_IS_OK(status
)) {
163 DBG_DEBUG("rpc_worker_report_status returned %s\n",
168 static int dcesrv_connection_destructor(struct dcesrv_connection
*conn
)
170 struct dcerpc_ncacn_conn
*ncacn_conn
= talloc_get_type_abort(
171 conn
->transport
.private_data
,
172 struct dcerpc_ncacn_conn
);
174 if (ncacn_conn
->termination_fn
!= NULL
) {
175 ncacn_conn
->termination_fn(conn
, ncacn_conn
->termination_data
);
182 * A new client has been passed to us from samba-dcerpcd.
184 static void rpc_worker_new_client(
185 struct rpc_worker
*worker
,
186 struct rpc_host_client
*client
,
189 struct dcesrv_context
*dce_ctx
= worker
->dce_ctx
;
190 struct named_pipe_auth_req_info8
*info8
= client
->npa_info8
;
191 struct tsocket_address
*remote_client_addr
= NULL
;
192 struct tsocket_address
*local_server_addr
= NULL
;
193 struct dcerpc_binding
*b
= NULL
;
194 enum dcerpc_transport_t transport
;
195 struct dcesrv_endpoint
*ep
= NULL
;
196 struct tstream_context
*tstream
= NULL
;
197 struct dcerpc_ncacn_conn
*ncacn_conn
= NULL
;
198 struct dcesrv_connection
*dcesrv_conn
= NULL
;
199 DATA_BLOB buffer
= { .data
= NULL
};
200 struct ncacn_packet
*pkt
= NULL
;
201 struct security_token
*token
= NULL
;
202 uint32_t npa_flags
, state_flags
;
203 bool found_npa_flags
;
207 DBG_DEBUG("Got new conn sock %d for binding %s\n",
211 status
= dcerpc_parse_binding(client
, client
->binding
, &b
);
212 if (!NT_STATUS_IS_OK(status
)) {
213 DBG_DEBUG("dcerpc_parse_binding(%s) failed: %s\n",
218 transport
= dcerpc_binding_get_transport(b
);
220 status
= dcesrv_find_endpoint(dce_ctx
, b
, &ep
);
222 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
) &&
223 ((transport
== NCACN_IP_TCP
) || (transport
== NCALRPC
)) &&
224 (dcerpc_binding_get_string_option(b
, "endpoint") != NULL
)) {
226 * We have two kinds of servers: Those who explicitly
227 * bind to a port (e.g. 135 for epmapper) and those
228 * who just specify a transport. The client specified
229 * a port (or socket name), but we did not find this
230 * in the list of servers having specified a
231 * port. Retry just matching for the transport,
232 * catching the servers that did not explicitly
235 * This is not fully correct, what we should do is
236 * that once the port the server listens on has been
237 * finalized we should mark this in the server list,
238 * but for now it works. We don't have the same RPC
239 * interface listening twice on different ports.
241 struct dcerpc_binding
*b_without_port
= dcerpc_binding_dup(
243 if (b_without_port
== NULL
) {
244 status
= NT_STATUS_NO_MEMORY
;
248 status
= dcerpc_binding_set_string_option(
249 b_without_port
, "endpoint", NULL
);
250 if (!NT_STATUS_IS_OK(status
)) {
251 DBG_DEBUG("Could not delete endpoint: %s\n",
253 TALLOC_FREE(b_without_port
);
257 status
= dcesrv_find_endpoint(dce_ctx
, b_without_port
, &ep
);
259 TALLOC_FREE(b_without_port
);
262 if (!NT_STATUS_IS_OK(status
)) {
263 DBG_DEBUG("Could not find endpoint for %s: %s\n",
269 ncacn_conn
= talloc(dce_ctx
, struct dcerpc_ncacn_conn
);
270 if (ncacn_conn
== NULL
) {
271 DBG_DEBUG("talloc failed\n");
274 *ncacn_conn
= (struct dcerpc_ncacn_conn
) {
277 .termination_fn
= rpc_worker_connection_terminated
,
278 .termination_data
= worker
,
281 if (transport
== NCALRPC
) {
282 ret
= tsocket_address_unix_from_path(ncacn_conn
,
283 info8
->remote_client_addr
,
284 &remote_client_addr
);
286 DBG_DEBUG("tsocket_address_unix_from_path"
288 info8
->remote_client_addr
,
293 ncacn_conn
->remote_client_name
=
294 talloc_strdup(ncacn_conn
, info8
->remote_client_name
);
295 if (ncacn_conn
->remote_client_name
== NULL
) {
296 DBG_DEBUG("talloc_strdup(%s) failed\n",
297 info8
->remote_client_name
);
301 ret
= tsocket_address_unix_from_path(ncacn_conn
,
302 info8
->local_server_addr
,
305 DBG_DEBUG("tsocket_address_unix_from_path"
307 info8
->local_server_addr
,
312 ncacn_conn
->local_server_name
=
313 talloc_strdup(ncacn_conn
, info8
->local_server_name
);
314 if (ncacn_conn
->local_server_name
== NULL
) {
315 DBG_DEBUG("talloc_strdup(%s) failed\n",
316 info8
->local_server_name
);
320 ret
= tsocket_address_inet_from_strings(
323 info8
->remote_client_addr
,
324 info8
->remote_client_port
,
325 &remote_client_addr
);
327 DBG_DEBUG("tsocket_address_inet_from_strings"
328 "(%s, %" PRIu16
") failed: %s\n",
329 info8
->remote_client_addr
,
330 info8
->remote_client_port
,
334 ncacn_conn
->remote_client_name
=
335 talloc_strdup(ncacn_conn
, info8
->remote_client_name
);
336 if (ncacn_conn
->remote_client_name
== NULL
) {
337 DBG_DEBUG("talloc_strdup(%s) failed\n",
338 info8
->remote_client_name
);
342 ret
= tsocket_address_inet_from_strings(
345 info8
->local_server_addr
,
346 info8
->local_server_port
,
349 DBG_DEBUG("tsocket_address_inet_from_strings"
350 "(%s, %" PRIu16
") failed: %s\n",
351 info8
->local_server_addr
,
352 info8
->local_server_port
,
356 ncacn_conn
->local_server_name
=
357 talloc_strdup(ncacn_conn
, info8
->local_server_name
);
358 if (ncacn_conn
->local_server_name
== NULL
) {
359 DBG_DEBUG("talloc_strdup(%s) failed\n",
360 info8
->local_server_name
);
365 if (transport
== NCACN_NP
) {
366 ret
= tstream_npa_existing_socket(
369 FILE_TYPE_MESSAGE_MODE_PIPE
,
372 DBG_DEBUG("tstream_npa_existing_socket failed: %s\n",
378 * "transport" so far is implicitly assigned by the
379 * socket that the client connected to, passed in from
380 * samba-dcerpcd via the binding. For NCACN_NP (root
381 * only by unix permissions) we got a
382 * named_pipe_auth_req_info8 where the transport can
385 transport
= info8
->transport
;
387 ret
= tstream_bsd_existing_socket(
388 ncacn_conn
, sock
, &tstream
);
390 DBG_DEBUG("tstream_bsd_existing_socket failed: %s\n",
394 /* as server we want to fail early */
395 tstream_bsd_fail_readv_first_error(tstream
, true);
399 token
= info8
->session_info
->session_info
->security_token
;
401 if (security_token_is_system(token
) && (transport
!= NCALRPC
)) {
402 DBG_DEBUG("System token only allowed on NCALRPC\n");
406 state_flags
= DCESRV_CALL_STATE_FLAG_MAY_ASYNC
;
408 found_npa_flags
= security_token_find_npa_flags(token
, &npa_flags
);
409 if (found_npa_flags
) {
410 if (npa_flags
& SAMBA_NPA_FLAGS_WINBIND_OFF
) {
412 DCESRV_CALL_STATE_FLAG_WINBIND_OFF
;
416 * Delete the flags so that we don't bail in
417 * local_np_connect_send() on subsequent
418 * connects. Once we connect to another RPC service, a
419 * new flags sid will be added if required.
421 security_token_del_npa_flags(token
);
424 ncacn_conn
->p
.msg_ctx
= global_messaging_context();
425 ncacn_conn
->p
.transport
= transport
;
427 status
= dcesrv_endpoint_connect(dce_ctx
,
430 info8
->session_info
->session_info
,
431 global_event_context(),
434 if (!NT_STATUS_IS_OK(status
)) {
435 DBG_DEBUG("Failed to connect to endpoint: %s\n",
440 talloc_set_destructor(dcesrv_conn
, dcesrv_connection_destructor
);
442 dcesrv_conn
->transport
.private_data
= ncacn_conn
;
443 dcesrv_conn
->transport
.report_output_data
=
444 dcesrv_sock_report_output_data
;
445 dcesrv_conn
->transport
.terminate_connection
=
446 dcesrv_transport_terminate_connection
;
448 dcesrv_conn
->send_queue
= tevent_queue_create(
449 dcesrv_conn
, "dcesrv send queue");
450 if (dcesrv_conn
->send_queue
== NULL
) {
451 DBG_DEBUG("tevent_queue_create failed\n");
455 dcesrv_conn
->stream
= talloc_move(dcesrv_conn
, &tstream
);
456 dcesrv_conn
->local_address
=
457 talloc_move(dcesrv_conn
, &local_server_addr
);
458 dcesrv_conn
->remote_address
=
459 talloc_move(dcesrv_conn
, &remote_client_addr
);
461 if (client
->bind_packet
.length
== 0) {
462 DBG_DEBUG("Expected bind packet\n");
466 buffer
= (DATA_BLOB
) {
467 .data
= talloc_move(dcesrv_conn
, &client
->bind_packet
.data
),
468 .length
= client
->bind_packet
.length
,
471 pkt
= talloc(dcesrv_conn
, struct ncacn_packet
);
473 DBG_DEBUG("talloc failed\n");
477 status
= dcerpc_pull_ncacn_packet(pkt
, &buffer
, pkt
);
478 if (!NT_STATUS_IS_OK(status
)) {
479 DBG_DEBUG("dcerpc_pull_ncacn_packet failed: %s\n",
486 DLIST_ADD(worker
->conns
, ncacn_conn
);
487 worker
->status
.num_connections
+= 1;
489 dcesrv_loop_next_packet(dcesrv_conn
, pkt
, buffer
);
493 TALLOC_FREE(ncacn_conn
);
494 TALLOC_FREE(dcesrv_conn
);
501 * Parent thinks it successfully sent us a client. Tell it
504 status
= rpc_worker_report_status(worker
);
505 if (!NT_STATUS_IS_OK(status
)) {
506 DBG_DEBUG("rpc_worker_report_status returned %s\n",
512 * New client message processing.
514 static bool rpc_worker_new_client_filter(
515 struct messaging_rec
*rec
, void *private_data
)
517 struct rpc_worker
*worker
= talloc_get_type_abort(
518 private_data
, struct rpc_worker
);
519 struct dcesrv_context
*dce_ctx
= worker
->dce_ctx
;
520 struct rpc_host_client
*client
= NULL
;
521 enum ndr_err_code ndr_err
;
524 if (rec
->msg_type
!= MSG_RPC_HOST_NEW_CLIENT
) {
528 if (rec
->num_fds
!= 1) {
529 DBG_DEBUG("Got %"PRIu8
" fds\n", rec
->num_fds
);
533 client
= talloc(dce_ctx
, struct rpc_host_client
);
534 if (client
== NULL
) {
535 DBG_DEBUG("talloc failed\n");
539 ndr_err
= ndr_pull_struct_blob_all(
543 (ndr_pull_flags_fn_t
)ndr_pull_rpc_host_client
);
544 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
545 DBG_DEBUG("ndr_pull_rpc_host_client failed: %s\n",
546 ndr_errstr(ndr_err
));
551 if (DEBUGLEVEL
>= 10) {
552 NDR_PRINT_DEBUG(rpc_host_client
, client
);
558 rpc_worker_new_client(worker
, client
, sock
);
564 * Return your status message processing.
566 static bool rpc_worker_status_filter(
567 struct messaging_rec
*rec
, void *private_data
)
569 struct rpc_worker
*worker
= talloc_get_type_abort(
570 private_data
, struct rpc_worker
);
571 struct dcerpc_ncacn_conn
*conn
= NULL
;
574 if (rec
->msg_type
!= MSG_RPC_DUMP_STATUS
) {
578 if (rec
->num_fds
!= 1) {
579 DBG_DEBUG("Got %"PRIu8
" fds\n", rec
->num_fds
);
583 f
= fdopen_keepfd(rec
->fds
[0], "w");
585 DBG_DEBUG("fdopen_keepfd failed: %s\n", strerror(errno
));
589 for (conn
= worker
->conns
; conn
!= NULL
; conn
= conn
->next
) {
590 char *endpoint
= NULL
;
592 endpoint
= dcerpc_binding_string(
593 conn
, conn
->endpoint
->ep_description
);
596 "endpoint=%s client=%s server=%s\n",
597 endpoint
? endpoint
: "UNKNOWN",
598 conn
->remote_client_name
,
599 conn
->local_server_name
);
600 TALLOC_FREE(endpoint
);
609 take a reference to an existing association group
611 static struct dcesrv_assoc_group
*rpc_worker_assoc_group_reference(
612 struct dcesrv_connection
*conn
,
615 const struct dcesrv_endpoint
*endpoint
= conn
->endpoint
;
616 enum dcerpc_transport_t transport
= dcerpc_binding_get_transport(
617 endpoint
->ep_description
);
618 struct dcesrv_assoc_group
*assoc_group
= NULL
;
621 /* find an association group given a assoc_group_id */
622 id_ptr
= idr_find(conn
->dce_ctx
->assoc_groups_idr
, id
& UINT16_MAX
);
623 if (id_ptr
== NULL
) {
624 DBG_NOTICE("Failed to find assoc_group 0x%08x\n", id
);
627 assoc_group
= talloc_get_type_abort(id_ptr
, struct dcesrv_assoc_group
);
629 if (assoc_group
->transport
!= transport
) {
630 const char *at
= derpc_transport_string_by_transport(
631 assoc_group
->transport
);
632 const char *ct
= derpc_transport_string_by_transport(
635 DBG_NOTICE("assoc_group 0x%08x (transport %s) "
636 "is not available on transport %s\n",
642 * Yes, this is a talloc_reference: The assoc group must be
643 * removed when all connections go. This should be replaced by
644 * adding a linked list of dcesrv_connection structs to the
647 return talloc_reference(conn
, assoc_group
);
650 static int rpc_worker_assoc_group_destructor(
651 struct dcesrv_assoc_group
*assoc_group
)
655 dcesrv_assoc_group_common_destructor(assoc_group
);
658 assoc_group
->dce_ctx
->assoc_groups_idr
,
659 assoc_group
->id
& UINT16_MAX
);
661 DBG_WARNING("Failed to remove assoc_group 0x%08x\n",
665 SMB_ASSERT(assoc_group
->dce_ctx
->assoc_groups_num
> 0);
666 assoc_group
->dce_ctx
->assoc_groups_num
-= 1;
671 allocate a new association group
673 static struct dcesrv_assoc_group
*rpc_worker_assoc_group_new(
674 struct dcesrv_connection
*conn
, uint16_t worker_index
)
676 struct dcesrv_context
*dce_ctx
= conn
->dce_ctx
;
677 const struct dcesrv_endpoint
*endpoint
= conn
->endpoint
;
678 enum dcerpc_transport_t transport
= dcerpc_binding_get_transport(
679 endpoint
->ep_description
);
680 struct dcesrv_assoc_group
*assoc_group
= NULL
;
683 assoc_group
= talloc_zero(conn
, struct dcesrv_assoc_group
);
684 if (assoc_group
== NULL
) {
689 * We use 16-bit to encode the worker index,
690 * have 16-bits left within the worker to form a
691 * 32-bit association group id.
693 id
= idr_get_new_random(
694 dce_ctx
->assoc_groups_idr
, assoc_group
, 1, UINT16_MAX
);
696 talloc_free(assoc_group
);
697 DBG_WARNING("Out of association groups!\n");
700 assoc_group
->id
= (((uint32_t)worker_index
) << 16) | id
;
701 assoc_group
->transport
= transport
;
702 assoc_group
->dce_ctx
= dce_ctx
;
704 talloc_set_destructor(assoc_group
, rpc_worker_assoc_group_destructor
);
706 SMB_ASSERT(dce_ctx
->assoc_groups_num
< UINT16_MAX
);
707 dce_ctx
->assoc_groups_num
+= 1;
712 static NTSTATUS
rpc_worker_assoc_group_find(
713 struct dcesrv_call_state
*call
,
716 struct rpc_worker
*w
= talloc_get_type_abort(
717 private_data
, struct rpc_worker
);
718 uint32_t assoc_group_id
= call
->pkt
.u
.bind
.assoc_group_id
;
720 if (assoc_group_id
!= 0) {
721 uint16_t worker_index
= (assoc_group_id
& 0xffff0000) >> 16;
722 if (worker_index
!= w
->status
.worker_index
) {
723 DBG_DEBUG("Wrong worker id %"PRIu16
", "
724 "expected %"PRIu32
"\n",
726 w
->status
.worker_index
);
727 return NT_STATUS_NOT_FOUND
;
729 call
->conn
->assoc_group
= rpc_worker_assoc_group_reference(
730 call
->conn
, assoc_group_id
);
732 call
->conn
->assoc_group
= rpc_worker_assoc_group_new(
733 call
->conn
, w
->status
.worker_index
);
736 if (call
->conn
->assoc_group
== NULL
) {
737 /* TODO Return correct status */
738 return NT_STATUS_UNSUCCESSFUL
;
744 static struct rpc_worker
*rpc_worker_new(
746 struct messaging_context
*msg_ctx
)
748 struct rpc_worker
*worker
= NULL
;
750 worker
= talloc_zero(mem_ctx
, struct rpc_worker
);
751 if (worker
== NULL
) {
755 worker
->rpc_host_pid
= (struct server_id
) { .pid
= 0 };
756 worker
->msg_ctx
= msg_ctx
;
758 worker
->cb
= (struct dcesrv_context_callbacks
) {
759 .log
.successful_authz
= dcesrv_log_successful_authz
,
760 .auth
.gensec_prepare
= dcesrv_auth_gensec_prepare
,
761 .auth
.become_root
= become_root
,
762 .auth
.unbecome_root
= unbecome_root
,
763 .assoc_group
.find
= rpc_worker_assoc_group_find
,
764 .assoc_group
.private_data
= worker
,
767 worker
->dce_ctx
= global_dcesrv_context();
768 if (worker
->dce_ctx
== NULL
) {
771 dcesrv_context_set_callbacks(worker
->dce_ctx
, &worker
->cb
);
779 static struct dcesrv_context
*rpc_worker_dce_ctx(struct rpc_worker
*w
)
784 struct rpc_worker_state
{
785 struct tevent_context
*ev
;
786 struct rpc_worker
*w
;
787 struct tevent_req
*new_client_req
;
788 struct tevent_req
*status_req
;
789 struct tevent_req
*finish_req
;
792 static void rpc_worker_done(struct tevent_req
*subreq
);
793 static void rpc_worker_shutdown(
794 struct messaging_context
*msg
,
797 struct server_id server_id
,
800 static struct tevent_req
*rpc_worker_send(
802 struct tevent_context
*ev
,
803 struct rpc_worker
*w
,
808 struct tevent_req
*req
= NULL
;
809 struct rpc_worker_state
*state
= NULL
;
812 req
= tevent_req_create(mem_ctx
, &state
, struct rpc_worker_state
);
819 if ((server_index
< 0) || ((unsigned)server_index
> UINT32_MAX
)) {
820 DBG_ERR("Invalid server index %d\n", server_index
);
821 tevent_req_error(req
, EINVAL
);
822 return tevent_req_post(req
, ev
);
824 if ((worker_index
< 0) || ((unsigned)worker_index
> UINT16_MAX
)) {
825 DBG_ERR("Invalid worker index %d\n", worker_index
);
826 tevent_req_error(req
, EINVAL
);
827 return tevent_req_post(req
, ev
);
829 w
->rpc_host_pid
= pid_to_procid(rpc_host_pid
);
831 w
->status
= (struct rpc_worker_status
) {
832 .server_index
= server_index
,
833 .worker_index
= worker_index
,
836 /* Wait for new client messages. */
837 state
->new_client_req
= messaging_filtered_read_send(
839 messaging_tevent_context(w
->msg_ctx
),
841 rpc_worker_new_client_filter
,
843 if (tevent_req_nomem(state
->new_client_req
, req
)) {
844 return tevent_req_post(req
, ev
);
847 /* Wait for report your status messages. */
848 state
->status_req
= messaging_filtered_read_send(
850 messaging_tevent_context(w
->msg_ctx
),
852 rpc_worker_status_filter
,
854 if (tevent_req_nomem(state
->status_req
, req
)) {
855 return tevent_req_post(req
, ev
);
858 /* Wait for shutdown messages. */
859 status
= messaging_register(
860 w
->msg_ctx
, req
, MSG_SHUTDOWN
, rpc_worker_shutdown
);
861 if (!NT_STATUS_IS_OK(status
)) {
862 DBG_DEBUG("messaging_register failed: %s\n",
864 tevent_req_error(req
, map_errno_from_nt_status(status
));
865 return tevent_req_post(req
, ev
);
868 state
->finish_req
= wait_for_read_send(state
, ev
, 0, false);
869 if (tevent_req_nomem(state
->finish_req
, req
)) {
870 return tevent_req_post(req
, ev
);
872 tevent_req_set_callback(state
->finish_req
, rpc_worker_done
, req
);
874 rpc_worker_report_status(w
);
879 static void rpc_worker_done(struct tevent_req
*subreq
)
881 struct tevent_req
*req
= tevent_req_callback_data(
882 subreq
, struct tevent_req
);
886 ok
= wait_for_read_recv(subreq
, &err
);
889 tevent_req_error(req
, err
);
892 tevent_req_done(req
);
895 static void rpc_worker_shutdown(
896 struct messaging_context
*msg
,
899 struct server_id server_id
,
902 struct tevent_req
*req
= talloc_get_type_abort(
903 private_data
, struct tevent_req
);
904 tevent_req_done(req
);
907 static int rpc_worker_recv(struct tevent_req
*req
)
909 return tevent_req_simple_recv_unix(req
);
912 static void sig_term_handler(
913 struct tevent_context
*ev
,
914 struct tevent_signal
*se
,
923 static void sig_hup_handler(
924 struct tevent_context
*ev
,
925 struct tevent_signal
*se
,
931 change_to_root_user();
932 lp_load_with_shares(get_dyn_CONFIGFILE());
935 static NTSTATUS
register_ep_server(
936 struct dcesrv_context
*dce_ctx
,
937 const struct dcesrv_endpoint_server
*ep_server
)
941 DBG_DEBUG("Registering server %s\n", ep_server
->name
);
943 status
= dcerpc_register_ep_server(ep_server
);
944 if (!NT_STATUS_IS_OK(status
) &&
945 !NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_COLLISION
)) {
946 DBG_ERR("Failed to register '%s' endpoint server: %s\n",
952 status
= dcesrv_init_ep_server(dce_ctx
, ep_server
->name
);
953 if (!NT_STATUS_IS_OK(status
)) {
954 DBG_ERR("dcesrv_init_ep_server(%s) failed: %s\n",
964 * @brief Main function for RPC server implementations
966 * This function provides all that is necessary to run a RPC server
967 * inside the samba-dcerpcd framework. Just pass argv and argc on to
970 * The get_interfaces() callback provides the information that is
971 * passed to samba-dcerpcd via --list-interfaces, it should not do any
972 * real RPC server initialization work. Quickly after this function is
973 * called by rpc_worker_main, the process exits again. It should
974 * return the number of interfaces provided.
976 * get_servers() is called when the process is about to do the real
977 * work. So more heavy-weight initialization should happen here. It
978 * should return NT_STATUS_OK and the number of server implementations provided.
980 * @param[in] argc argc from main()
981 * @param[in] argv argv from main()
982 * @param[in] get_interfaces List all interfaces that this server provides
983 * @param[in] get_servers Provide the RPC server implementations
984 * @param[in] private_data Passed to the callback functions
985 * @return 0 It should never return except on successful process exit
991 const char *daemon_config_name
,
994 size_t (*get_interfaces
)(
995 const struct ndr_interface_table
***ifaces
,
997 NTSTATUS (*get_servers
)(
998 struct dcesrv_context
*dce_ctx
,
999 const struct dcesrv_endpoint_server
***ep_servers
,
1000 size_t *num_ep_servers
,
1001 void *private_data
),
1004 const struct loadparm_substitution
*lp_sub
=
1005 loadparm_s3_global_substitution();
1006 const char *progname
= getprogname();
1007 TALLOC_CTX
*frame
= NULL
;
1008 struct tevent_context
*ev_ctx
= NULL
;
1009 struct tevent_req
*req
= NULL
;
1010 struct messaging_context
*msg_ctx
= NULL
;
1011 struct dcesrv_context
*dce_ctx
= NULL
;
1012 struct tevent_signal
*se
= NULL
;
1017 int worker_group
= -1;
1018 int worker_index
= -1;
1020 int list_interfaces
= 0;
1021 struct rpc_worker
*worker
= NULL
;
1022 const struct dcesrv_endpoint_server
**ep_servers
;
1023 size_t i
, num_servers
;
1026 struct poptOption long_options
[] = {
1029 .longName
= "list-interfaces",
1030 .argInfo
= POPT_ARG_NONE
,
1031 .arg
= &list_interfaces
,
1032 .descrip
= "List the interfaces provided",
1035 .longName
= "worker-group",
1036 .argInfo
= POPT_ARG_INT
,
1037 .arg
= &worker_group
,
1038 .descrip
= "Group index in status message",
1041 .longName
= "worker-index",
1042 .argInfo
= POPT_ARG_INT
,
1043 .arg
= &worker_index
,
1044 .descrip
= "Worker index in status message",
1049 static const struct smbd_shim smbd_shim_fns
= {
1050 .become_authenticated_pipe_user
=
1051 smbd_become_authenticated_pipe_user
,
1052 .unbecome_authenticated_pipe_user
=
1053 smbd_unbecome_authenticated_pipe_user
,
1054 .become_root
= smbd_become_root
,
1055 .unbecome_root
= smbd_unbecome_root
,
1059 talloc_enable_null_tracking();
1060 frame
= talloc_stackframe();
1064 ok
= samba_cmdline_init(frame
,
1065 SAMBA_CMDLINE_CONFIG_SERVER
,
1066 true /* require_smbconf */);
1068 DBG_ERR("Failed to init cmdline parser!\n");
1073 pc
= samba_popt_get_context(progname
, argc
, argv
, long_options
, 0);
1075 DBG_ERR("Failed to setup popt context!\n");
1080 while ((opt
= poptGetNextOpt(pc
)) != -1) {
1082 "\nInvalid option %s: %s\n\n",
1083 poptBadOption(pc
, 0),
1085 poptPrintUsage(pc
, stderr
, 0);
1089 poptFreeContext(pc
);
1091 if (list_interfaces
!= 0) {
1092 const struct ndr_interface_table
**ifaces
= NULL
;
1095 num_workers
= lp_parm_int(
1096 -1, daemon_config_name
, "num_workers", num_workers
);
1097 idle_seconds
= lp_parm_int(
1098 -1, daemon_config_name
, "idle_seconds", idle_seconds
);
1100 DBG_DEBUG("daemon=%s, num_workers=%d, idle_seconds=%d\n",
1105 fprintf(stdout
, "%d\n%d\n", num_workers
, idle_seconds
);
1107 num_ifaces
= get_interfaces(&ifaces
, private_data
);
1109 for (i
=0; i
<num_ifaces
; i
++) {
1110 rpc_worker_print_interface(stdout
, ifaces
[i
]);
1117 log_stdout
= (debug_get_log_type() == DEBUG_STDOUT
);
1118 if (log_stdout
!= 0) {
1119 setup_logging(argv
[0], DEBUG_STDOUT
);
1121 setup_logging(argv
[0], DEBUG_FILE
);
1124 set_smbd_shim(&smbd_shim_fns
);
1126 dump_core_setup(progname
, lp_logfile(talloc_tos(), lp_sub
));
1128 /* POSIX demands that signals are inherited. If the invoking
1129 * process has these signals masked, we will have problems, as
1130 * we won't receive them. */
1131 BlockSignals(False
, SIGHUP
);
1132 BlockSignals(False
, SIGUSR1
);
1133 BlockSignals(False
, SIGTERM
);
1136 /* we are never interested in SIGFPE */
1137 BlockSignals(True
,SIGFPE
);
1139 /* We no longer use USR2... */
1140 #if defined(SIGUSR2)
1141 BlockSignals(True
, SIGUSR2
);
1143 /* Ignore children - no zombies. */
1148 DBG_STARTUP_NOTICE("%s version %s started.\n%s\n",
1150 samba_version_string(),
1151 samba_copyright_string());
1153 msg_ctx
= global_messaging_context();
1154 if (msg_ctx
== NULL
) {
1155 DBG_ERR("global_messaging_context() failed\n");
1159 ev_ctx
= messaging_tevent_context(msg_ctx
);
1161 worker
= rpc_worker_new(ev_ctx
, msg_ctx
);
1162 if (worker
== NULL
) {
1163 DBG_ERR("rpc_worker_new failed\n");
1164 global_messaging_context_free();
1168 dce_ctx
= rpc_worker_dce_ctx(worker
);
1170 se
= tevent_add_signal(
1171 ev_ctx
, ev_ctx
, SIGTERM
, 0, sig_term_handler
, NULL
);
1173 DBG_ERR("tevent_add_signal failed\n");
1174 global_messaging_context_free();
1178 BlockSignals(false, SIGTERM
);
1180 se
= tevent_add_signal(
1181 ev_ctx
, ev_ctx
, SIGHUP
, 0, sig_hup_handler
, NULL
);
1183 DBG_ERR("tevent_add_signal failed\n");
1184 global_messaging_context_free();
1188 BlockSignals(false, SIGHUP
);
1190 (void)winbind_off();
1191 ok
= init_guest_session_info(NULL
);
1194 DBG_WARNING("init_guest_session_info failed\n");
1195 global_messaging_context_free();
1200 status
= init_system_session_info(NULL
);
1201 if (!NT_STATUS_IS_OK(status
)) {
1202 DBG_WARNING("init_system_session_info failed: %s\n",
1204 global_messaging_context_free();
1209 DBG_INFO("Initializing DCE/RPC registered endpoint servers\n");
1211 status
= get_servers(dce_ctx
,
1215 if (!NT_STATUS_IS_OK(status
)) {
1216 DBG_ERR("get_servers failed: %s\n", nt_errstr(status
));
1217 global_messaging_context_free();
1222 DBG_DEBUG("get_servers() returned %zu servers\n", num_servers
);
1224 for (i
=0; i
<num_servers
; i
++) {
1225 status
= register_ep_server(dce_ctx
, ep_servers
[i
]);
1226 if (!NT_STATUS_IS_OK(status
)) {
1227 DBG_ERR("register_ep_server failed: %s\n",
1229 global_messaging_context_free();
1235 req
= rpc_worker_send(
1236 ev_ctx
, ev_ctx
, worker
, getppid(), worker_group
, worker_index
);
1238 DBG_ERR("rpc_worker_send failed\n");
1239 global_messaging_context_free();
1244 DBG_DEBUG("%s worker running\n", progname
);
1246 while (tevent_req_is_in_progress(req
)) {
1247 TALLOC_CTX
*loop_frame
= NULL
;
1249 loop_frame
= talloc_stackframe();
1251 ret
= tevent_loop_once(ev_ctx
);
1253 TALLOC_FREE(loop_frame
);
1256 DBG_WARNING("tevent_req_once() failed: %s\n",
1258 global_messaging_context_free();
1264 status
= dcesrv_shutdown_registered_ep_servers(dce_ctx
);
1265 if (!NT_STATUS_IS_OK(status
)) {
1266 DBG_DEBUG("Shutdown failed with: %s\n",
1270 ret
= rpc_worker_recv(req
);
1272 DBG_DEBUG("rpc_worker_recv returned %s\n", strerror(ret
));
1273 global_messaging_context_free();