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 "rpc_server.h"
28 #include "rpc_pipes.h"
29 #include "source3/smbd/proto.h"
30 #include "source3/lib/smbd_shim.h"
31 #include "source3/lib/global_contexts.h"
32 #include "source3/lib/util_procid.h"
33 #include "lib/tsocket/tsocket.h"
34 #include "libcli/named_pipe_auth/npa_tstream.h"
35 #include "libcli/smb/smb_constants.h"
36 #include "lib/param/param.h"
37 #include "lib/util/idtree_random.h"
38 #include "lib/util/tevent_unix.h"
39 #include "lib/async_req/async_sock.h"
40 #include "lib/util/dlinklist.h"
41 #include "source3/include/auth.h"
42 #include "nsswitch/winbind_client.h"
43 #include "source3/include/messages.h"
44 #include "libcli/security/security_token.h"
47 * This is the generic code that becomes the
48 * template that all rpcd_* instances that
49 * serve DCERPC can use to provide services to samba-dcerpcd.
51 * The external entry point is:
52 * rpc_worker_main() which takes an argc/argv list
55 * get_interfaces() - List all interfaces that this server provides
56 * get_servers() - Provide the RPC server implementations
58 * Each rpcd_* service needs only to provide
59 * the implementations of get_interfaces() and get_servers()
60 * and call rpc_worker_main() from their main() function
61 * to provide services that can be connected to from samba-dcerpcd.
65 struct dcerpc_ncacn_conn *conns;
66 struct server_id rpc_host_pid;
67 struct messaging_context *msg_ctx;
68 struct dcesrv_context *dce_ctx;
70 struct dcesrv_context_callbacks cb;
72 struct rpc_worker_status status;
77 static void rpc_worker_print_interface(
78 FILE *f, const struct ndr_interface_table *t)
80 const struct ndr_interface_string_array *endpoints = t->endpoints;
82 struct ndr_syntax_id_buf id_buf;
86 ndr_syntax_id_buf_string(&t->syntax_id, &id_buf),
89 for (i=0; i<endpoints->count; i++) {
90 fprintf(f, " %s\n", endpoints->names[i]);
94 static NTSTATUS rpc_worker_report_status(struct rpc_worker *worker)
97 DATA_BLOB blob = { .data = buf, .length = sizeof(buf), };
98 enum ndr_err_code ndr_err;
101 if (DEBUGLEVEL >= 10) {
102 NDR_PRINT_DEBUG(rpc_worker_status, &worker->status);
105 ndr_err = ndr_push_struct_into_fixed_blob(
108 (ndr_push_flags_fn_t)ndr_push_rpc_worker_status);
109 SMB_ASSERT(NDR_ERR_CODE_IS_SUCCESS(ndr_err));
111 status = messaging_send(
113 worker->rpc_host_pid,
114 MSG_RPC_WORKER_STATUS,
119 static void rpc_worker_connection_terminated(
120 struct dcesrv_connection *conn, void *private_data)
122 struct rpc_worker *worker = talloc_get_type_abort(
123 private_data, struct rpc_worker);
124 struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
125 conn->transport.private_data, struct dcerpc_ncacn_conn);
126 struct dcerpc_ncacn_conn *w = NULL;
130 SMB_ASSERT(worker->status.num_clients > 0);
132 for (w = worker->conns; w != NULL; w = w->next) {
133 if (w == ncacn_conn) {
140 DLIST_REMOVE(worker->conns, ncacn_conn);
142 worker->status.num_clients -= 1;
144 status = rpc_worker_report_status(worker);
145 if (!NT_STATUS_IS_OK(status)) {
146 DBG_DEBUG("rpc_worker_report_status returned %s\n",
151 static int dcesrv_connection_destructor(struct dcesrv_connection *conn)
153 struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
154 conn->transport.private_data,
155 struct dcerpc_ncacn_conn);
157 if (ncacn_conn->termination_fn != NULL) {
158 ncacn_conn->termination_fn(conn, ncacn_conn->termination_data);
165 * A new client has been passed to us from samba-dcerpcd.
167 static void rpc_worker_new_client(
168 struct rpc_worker *worker,
169 struct rpc_host_client *client,
172 struct dcesrv_context *dce_ctx = worker->dce_ctx;
173 struct named_pipe_auth_req_info5 *info5 = client->npa_info5;
174 struct dcerpc_binding *b = NULL;
175 enum dcerpc_transport_t transport;
176 struct dcesrv_endpoint *ep = NULL;
177 struct dcerpc_ncacn_conn *ncacn_conn = NULL;
178 struct dcesrv_connection *dcesrv_conn = NULL;
179 DATA_BLOB buffer = { .data = NULL };
180 struct ncacn_packet *pkt = NULL;
184 DBG_DEBUG("Got new conn sock %d for binding %s\n",
188 status = dcerpc_parse_binding(client, client->binding, &b);
189 if (!NT_STATUS_IS_OK(status)) {
190 DBG_DEBUG("dcerpc_parse_binding(%s) failed: %s\n",
195 transport = dcerpc_binding_get_transport(b);
197 status = dcesrv_find_endpoint(dce_ctx, b, &ep);
199 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND) &&
200 ((transport == NCACN_IP_TCP) || (transport == NCALRPC)) &&
201 (dcerpc_binding_get_string_option(b, "endpoint") != NULL)) {
203 * We have two kinds of servers: Those who explicitly
204 * bind to a port (e.g. 135 for epmapper) and those
205 * who just specify a transport. The client specified
206 * a port (or socket name), but we did not find this
207 * in the list of servers having specified a
208 * port. Retry just matching for the transport,
209 * catching the servers that did not explicitly
212 * This is not fully correct, what we should do is
213 * that once the port the server listens on has been
214 * finalized we should mark this in the server list,
215 * but for now it works. We don't have the same RPC
216 * interface listening twice on different ports.
218 struct dcerpc_binding *b_without_port = dcerpc_binding_dup(
220 if (b_without_port == NULL) {
221 status = NT_STATUS_NO_MEMORY;
225 status = dcerpc_binding_set_string_option(
226 b_without_port, "endpoint", NULL);
227 if (!NT_STATUS_IS_OK(status)) {
228 DBG_DEBUG("Could not delete endpoint: %s\n",
230 TALLOC_FREE(b_without_port);
234 status = dcesrv_find_endpoint(dce_ctx, b_without_port, &ep);
236 TALLOC_FREE(b_without_port);
239 if (!NT_STATUS_IS_OK(status)) {
240 DBG_DEBUG("Could not find endpoint for %s: %s\n",
246 status = dcerpc_ncacn_conn_init(
248 global_event_context(),
249 global_messaging_context(),
252 rpc_worker_connection_terminated,
255 if (!NT_STATUS_IS_OK(status)) {
256 DBG_DEBUG("dcerpc_ncacn_conn_init() failed: %s\n",
260 ncacn_conn->sock = sock;
262 if (transport == NCALRPC) {
263 ret = tsocket_address_unix_from_path(
265 info5->remote_client_addr,
266 &ncacn_conn->remote_client_addr);
268 DBG_DEBUG("tsocket_address_unix_from_path"
270 info5->remote_client_addr,
275 ncacn_conn->remote_client_name = talloc_strdup(
276 ncacn_conn, info5->remote_client_name);
277 if (ncacn_conn->remote_client_name == NULL) {
278 DBG_DEBUG("talloc_strdup(%s) failed\n",
279 info5->remote_client_name);
283 ret = tsocket_address_unix_from_path(
285 info5->local_server_addr,
286 &ncacn_conn->local_server_addr);
288 DBG_DEBUG("tsocket_address_unix_from_path"
290 info5->local_server_addr,
295 ncacn_conn->local_server_name = talloc_strdup(
296 ncacn_conn, info5->local_server_name);
297 if (ncacn_conn->local_server_name == NULL) {
298 DBG_DEBUG("talloc_strdup(%s) failed\n",
299 info5->local_server_name);
303 ret = tsocket_address_inet_from_strings(
306 info5->remote_client_addr,
307 info5->remote_client_port,
308 &ncacn_conn->remote_client_addr);
310 DBG_DEBUG("tsocket_address_inet_from_strings"
311 "(%s, %"PRIu16") failed: %s\n",
312 info5->remote_client_addr,
313 info5->remote_client_port,
317 ncacn_conn->remote_client_name = talloc_strdup(
318 ncacn_conn, info5->remote_client_name);
319 if (ncacn_conn->remote_client_name == NULL) {
320 DBG_DEBUG("talloc_strdup(%s) failed\n",
321 info5->remote_client_name);
325 ret = tsocket_address_inet_from_strings(
328 info5->local_server_addr,
329 info5->local_server_port,
330 &ncacn_conn->local_server_addr);
332 DBG_DEBUG("tsocket_address_inet_from_strings"
333 "(%s, %"PRIu16") failed: %s\n",
334 info5->local_server_addr,
335 info5->local_server_port,
339 ncacn_conn->local_server_name = talloc_strdup(
340 ncacn_conn, info5->local_server_name);
341 if (ncacn_conn->local_server_name == NULL) {
342 DBG_DEBUG("talloc_strdup(%s) failed\n",
343 info5->local_server_name);
348 if (transport == NCACN_NP) {
349 ret = tstream_npa_existing_socket(
352 FILE_TYPE_MESSAGE_MODE_PIPE,
353 &ncacn_conn->tstream);
355 DBG_DEBUG("tstream_npa_existing_socket failed: %s\n",
361 * "transport" so far is implicitly assigned by the
362 * socket that the client connected to, passed in from
363 * samba-dcerpcd via the binding. For NCACN_NP (root
364 * only by unix permissions) we got a
365 * named_pipe_auth_req_info5 where the transport can
368 transport = info5->transport;
370 ret = tstream_bsd_existing_socket(
371 ncacn_conn, sock, &ncacn_conn->tstream);
373 DBG_DEBUG("tstream_bsd_existing_socket failed: %s\n",
380 ncacn_conn->session_info = talloc_move(
381 ncacn_conn, &info5->session_info->session_info);
383 if (security_token_is_system(
384 ncacn_conn->session_info->security_token) &&
385 (transport != NCALRPC)) {
386 DBG_DEBUG("System token only allowed on NCALRPC\n");
390 ret = make_base_pipes_struct(
395 ncacn_conn->remote_client_addr,
396 ncacn_conn->local_server_addr,
399 DBG_DEBUG("make_base_pipes_struct failed: %s\n",
404 status = dcesrv_endpoint_connect(
408 ncacn_conn->session_info,
409 global_event_context(),
410 DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
412 if (!NT_STATUS_IS_OK(status)) {
413 DBG_DEBUG("Failed to connect to endpoint: %s\n",
418 talloc_set_destructor(dcesrv_conn, dcesrv_connection_destructor);
420 dcesrv_conn->transport.private_data = ncacn_conn;
421 dcesrv_conn->transport.report_output_data =
422 dcesrv_sock_report_output_data;
423 dcesrv_conn->transport.terminate_connection =
424 dcesrv_transport_terminate_connection;
426 dcesrv_conn->send_queue = tevent_queue_create(
427 dcesrv_conn, "dcesrv send queue");
428 if (dcesrv_conn->send_queue == NULL) {
429 DBG_DEBUG("tevent_queue_create failed\n");
433 dcesrv_conn->stream = talloc_move(dcesrv_conn, &ncacn_conn->tstream);
434 dcesrv_conn->local_address = ncacn_conn->local_server_addr;
435 dcesrv_conn->remote_address = ncacn_conn->remote_client_addr;
437 if (client->bind_packet.length == 0) {
438 DBG_DEBUG("Expected bind packet\n");
442 buffer = (DATA_BLOB) {
443 .data = talloc_move(dcesrv_conn, &client->bind_packet.data),
444 .length = client->bind_packet.length,
447 pkt = talloc(dcesrv_conn, struct ncacn_packet);
449 DBG_DEBUG("talloc failed\n");
453 status = dcerpc_pull_ncacn_packet(pkt, &buffer, pkt);
454 if (!NT_STATUS_IS_OK(status)) {
455 DBG_DEBUG("dcerpc_pull_ncacn_packet failed: %s\n",
462 DLIST_ADD(worker->conns, ncacn_conn);
463 worker->status.num_clients += 1;
465 dcesrv_loop_next_packet(dcesrv_conn, pkt, buffer);
469 TALLOC_FREE(ncacn_conn);
470 TALLOC_FREE(dcesrv_conn);
477 * Parent thinks it successfully sent us a client. Tell it
480 status = rpc_worker_report_status(worker);
481 if (!NT_STATUS_IS_OK(status)) {
482 DBG_DEBUG("rpc_worker_report_status returned %s\n",
488 * New client message processing.
490 static bool rpc_worker_new_client_filter(
491 struct messaging_rec *rec, void *private_data)
493 struct rpc_worker *worker = talloc_get_type_abort(
494 private_data, struct rpc_worker);
495 struct dcesrv_context *dce_ctx = worker->dce_ctx;
496 struct rpc_host_client *client = NULL;
497 enum ndr_err_code ndr_err;
500 if (rec->msg_type != MSG_RPC_HOST_NEW_CLIENT) {
504 if (rec->num_fds != 1) {
505 DBG_DEBUG("Got %"PRIu8" fds\n", rec->num_fds);
509 client = talloc(dce_ctx, struct rpc_host_client);
510 if (client == NULL) {
511 DBG_DEBUG("talloc failed\n");
515 ndr_err = ndr_pull_struct_blob_all(
519 (ndr_pull_flags_fn_t)ndr_pull_rpc_host_client);
520 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
521 DBG_DEBUG("ndr_pull_rpc_host_client failed: %s\n",
522 ndr_errstr(ndr_err));
527 if (DEBUGLEVEL >= 10) {
528 NDR_PRINT_DEBUG(rpc_host_client, client);
534 rpc_worker_new_client(worker, client, sock);
540 * Return your status message processing.
542 static bool rpc_worker_status_filter(
543 struct messaging_rec *rec, void *private_data)
545 struct rpc_worker *worker = talloc_get_type_abort(
546 private_data, struct rpc_worker);
547 struct dcerpc_ncacn_conn *conn = NULL;
551 if (rec->msg_type != MSG_RPC_DUMP_STATUS) {
555 if (rec->num_fds != 1) {
556 DBG_DEBUG("Got %"PRIu8" fds\n", rec->num_fds);
560 fd = dup(rec->fds[0]);
562 DBG_DEBUG("dup(%"PRIi64") failed: %s\n",
570 DBG_DEBUG("fdopen failed: %s\n", strerror(errno));
575 for (conn = worker->conns; conn != NULL; conn = conn->next) {
576 char *endpoint = NULL;
578 endpoint = dcerpc_binding_string(
579 conn, conn->endpoint->ep_description);
582 "endpoint=%s client=%s server=%s\n",
583 endpoint ? endpoint : "UNKNOWN",
584 conn->remote_client_name,
585 conn->local_server_name);
586 TALLOC_FREE(endpoint);
595 take a reference to an existing association group
597 static struct dcesrv_assoc_group *rpc_worker_assoc_group_reference(
598 struct dcesrv_connection *conn,
601 const struct dcesrv_endpoint *endpoint = conn->endpoint;
602 enum dcerpc_transport_t transport = dcerpc_binding_get_transport(
603 endpoint->ep_description);
604 struct dcesrv_assoc_group *assoc_group = NULL;
607 /* find an association group given a assoc_group_id */
608 id_ptr = idr_find(conn->dce_ctx->assoc_groups_idr, id & 0xffffff);
609 if (id_ptr == NULL) {
610 DBG_NOTICE("Failed to find assoc_group 0x%08x\n", id);
613 assoc_group = talloc_get_type_abort(id_ptr, struct dcesrv_assoc_group);
615 if (assoc_group->transport != transport) {
616 const char *at = derpc_transport_string_by_transport(
617 assoc_group->transport);
618 const char *ct = derpc_transport_string_by_transport(
621 DBG_NOTICE("assoc_group 0x%08x (transport %s) "
622 "is not available on transport %s",
628 * Yes, this is a talloc_reference: The assoc group must be
629 * removed when all connections go. This should be replaced by
630 * adding a linked list of dcesrv_connection structs to the
633 return talloc_reference(conn, assoc_group);
636 static int rpc_worker_assoc_group_destructor(
637 struct dcesrv_assoc_group *assoc_group)
642 assoc_group->dce_ctx->assoc_groups_idr,
643 assoc_group->id & 0xffffff);
645 DBG_WARNING("Failed to remove assoc_group 0x%08x\n",
652 allocate a new association group
654 static struct dcesrv_assoc_group *rpc_worker_assoc_group_new(
655 struct dcesrv_connection *conn, uint8_t worker_index)
657 struct dcesrv_context *dce_ctx = conn->dce_ctx;
658 const struct dcesrv_endpoint *endpoint = conn->endpoint;
659 enum dcerpc_transport_t transport = dcerpc_binding_get_transport(
660 endpoint->ep_description);
661 struct dcesrv_assoc_group *assoc_group = NULL;
664 assoc_group = talloc_zero(conn, struct dcesrv_assoc_group);
665 if (assoc_group == NULL) {
669 id = idr_get_new_random(
670 dce_ctx->assoc_groups_idr, assoc_group, UINT16_MAX);
672 talloc_free(assoc_group);
673 DBG_WARNING("Out of association groups!\n");
676 assoc_group->id = (worker_index << 24) + id;
677 assoc_group->transport = transport;
678 assoc_group->dce_ctx = dce_ctx;
680 talloc_set_destructor(assoc_group, rpc_worker_assoc_group_destructor);
685 static NTSTATUS rpc_worker_assoc_group_find(
686 struct dcesrv_call_state *call,
689 struct rpc_worker *w = talloc_get_type_abort(
690 private_data, struct rpc_worker);
691 uint32_t assoc_group_id = call->pkt.u.bind.assoc_group_id;
693 if (assoc_group_id != 0) {
694 uint8_t worker_index = (assoc_group_id & 0xff000000) >> 24;
695 if (worker_index != w->status.worker_index) {
696 DBG_DEBUG("Wrong worker id %"PRIu8", "
697 "expected %"PRIu8"\n",
699 w->status.worker_index);
700 return NT_STATUS_NOT_FOUND;
702 call->conn->assoc_group = rpc_worker_assoc_group_reference(
703 call->conn, assoc_group_id);
705 call->conn->assoc_group = rpc_worker_assoc_group_new(
706 call->conn, w->status.worker_index);
709 if (call->conn->assoc_group == NULL) {
710 /* TODO Return correct status */
711 return NT_STATUS_UNSUCCESSFUL;
717 static struct rpc_worker *rpc_worker_new(
719 struct messaging_context *msg_ctx)
721 struct rpc_worker *worker = NULL;
723 worker = talloc_zero(mem_ctx, struct rpc_worker);
724 if (worker == NULL) {
728 worker->rpc_host_pid = (struct server_id) { .pid = 0 };
729 worker->msg_ctx = msg_ctx;
731 worker->cb = (struct dcesrv_context_callbacks) {
732 .log.successful_authz = dcesrv_log_successful_authz,
733 .auth.gensec_prepare = dcesrv_auth_gensec_prepare,
734 .assoc_group.find = rpc_worker_assoc_group_find,
735 .assoc_group.private_data = worker,
738 worker->dce_ctx = global_dcesrv_context();
739 if (worker->dce_ctx == NULL) {
742 dcesrv_context_set_callbacks(worker->dce_ctx, &worker->cb);
750 static struct dcesrv_context *rpc_worker_dce_ctx(struct rpc_worker *w)
755 struct rpc_worker_state {
756 struct tevent_context *ev;
757 struct rpc_worker *w;
758 struct tevent_req *new_client_req;
759 struct tevent_req *status_req;
760 struct tevent_req *finish_req;
763 static void rpc_worker_done(struct tevent_req *subreq);
764 static void rpc_worker_shutdown(
765 struct messaging_context *msg,
768 struct server_id server_id,
771 static struct tevent_req *rpc_worker_send(
773 struct tevent_context *ev,
774 struct rpc_worker *w,
779 struct tevent_req *req = NULL;
780 struct rpc_worker_state *state = NULL;
783 req = tevent_req_create(mem_ctx, &state, struct rpc_worker_state);
790 if ((server_index < 0) || ((unsigned)server_index > UINT32_MAX)) {
791 DBG_ERR("Invalid server index %d\n", server_index);
792 tevent_req_error(req, EINVAL);
793 return tevent_req_post(req, ev);
795 if ((worker_index < 0) || ((unsigned)worker_index > UINT32_MAX)) {
796 DBG_ERR("Invalid worker index %d\n", worker_index);
797 tevent_req_error(req, EINVAL);
798 return tevent_req_post(req, ev);
800 w->rpc_host_pid = pid_to_procid(rpc_host_pid);
802 w->status = (struct rpc_worker_status) {
803 .server_index = server_index,
804 .worker_index = worker_index,
807 /* Wait for new client messages. */
808 state->new_client_req = messaging_filtered_read_send(
810 messaging_tevent_context(w->msg_ctx),
812 rpc_worker_new_client_filter,
814 if (tevent_req_nomem(state->new_client_req, req)) {
815 return tevent_req_post(req, ev);
818 /* Wait for report your status messages. */
819 state->status_req = messaging_filtered_read_send(
821 messaging_tevent_context(w->msg_ctx),
823 rpc_worker_status_filter,
825 if (tevent_req_nomem(state->status_req, req)) {
826 return tevent_req_post(req, ev);
829 /* Wait for shutdown messages. */
830 status = messaging_register(
831 w->msg_ctx, req, MSG_SHUTDOWN, rpc_worker_shutdown);
832 if (!NT_STATUS_IS_OK(status)) {
833 DBG_DEBUG("messaging_register failed: %s\n",
835 tevent_req_error(req, map_errno_from_nt_status(status));
836 return tevent_req_post(req, ev);
839 state->finish_req = wait_for_read_send(state, ev, 0, false);
840 if (tevent_req_nomem(state->finish_req, req)) {
841 return tevent_req_post(req, ev);
843 tevent_req_set_callback(state->finish_req, rpc_worker_done, req);
845 rpc_worker_report_status(w);
850 static void rpc_worker_done(struct tevent_req *subreq)
852 struct tevent_req *req = tevent_req_callback_data(
853 subreq, struct tevent_req);
857 ok = wait_for_read_recv(subreq, &err);
860 tevent_req_error(req, err);
863 tevent_req_done(req);
866 static void rpc_worker_shutdown(
867 struct messaging_context *msg,
870 struct server_id server_id,
873 struct tevent_req *req = talloc_get_type_abort(
874 private_data, struct tevent_req);
875 tevent_req_done(req);
878 static int rpc_worker_recv(struct tevent_req *req)
880 return tevent_req_simple_recv_unix(req);
883 static void sig_term_handler(
884 struct tevent_context *ev,
885 struct tevent_signal *se,
894 static void sig_hup_handler(
895 struct tevent_context *ev,
896 struct tevent_signal *se,
902 change_to_root_user();
903 lp_load_with_shares(get_dyn_CONFIGFILE());
906 static NTSTATUS register_ep_server(
907 struct dcesrv_context *dce_ctx,
908 const struct dcesrv_endpoint_server *ep_server)
912 DBG_DEBUG("Registering server %s\n", ep_server->name);
914 status = dcerpc_register_ep_server(ep_server);
915 if (!NT_STATUS_IS_OK(status) &&
916 !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
917 DBG_ERR("Failed to register '%s' endpoint server: %s\n",
923 status = dcesrv_init_ep_server(dce_ctx, ep_server->name);
924 if (!NT_STATUS_IS_OK(status)) {
925 DBG_ERR("dcesrv_init_ep_server(%s) failed: %s\n",
935 * @brief Main function for RPC server implementations
937 * This function provides all that is necessary to run a RPC server
938 * inside the samba-dcerpcd framework. Just pass argv and argc on to
941 * The get_interfaces() callback provides the information that is
942 * passed to samba-dcerpcd via --list-interfaces, it should not do any
943 * real RPC server initialization work. Quickly after this function is
944 * called by rpc_worker_main, the process exits again. It should
945 * return the number of interfaces provided.
947 * get_servers() is called when the process is about to do the real
948 * work. So more heavy-weight initialization should happen here. It
949 * should return the number of server implementations provided.
951 * @param[in] argc argc from main()
952 * @param[in] argv argv from main()
953 * @param[in] get_interfaces List all interfaces that this server provides
954 * @param[in] get_servers Provide the RPC server implementations
955 * @param[in] private_data Passed to the callback functions
956 * @return 0 It should never return except on successful process exit
962 const char *daemon_config_name,
965 size_t (*get_interfaces)(
966 const struct ndr_interface_table ***ifaces,
968 size_t (*get_servers)(
969 struct dcesrv_context *dce_ctx,
970 const struct dcesrv_endpoint_server ***ep_servers,
974 const struct loadparm_substitution *lp_sub =
975 loadparm_s3_global_substitution();
976 const char *progname = getprogname();
977 TALLOC_CTX *frame = NULL;
978 struct tevent_context *ev_ctx = NULL;
979 struct tevent_req *req = NULL;
980 struct messaging_context *msg_ctx = NULL;
981 struct dcesrv_context *dce_ctx = NULL;
982 struct tevent_signal *se = NULL;
987 int worker_group = -1;
988 int worker_index = -1;
990 int list_interfaces = 0;
991 struct rpc_worker *worker = NULL;
992 const struct dcesrv_endpoint_server **ep_servers;
993 size_t i, num_servers;
996 struct poptOption long_options[] = {
999 .longName = "list-interfaces",
1000 .argInfo = POPT_ARG_NONE,
1001 .arg = &list_interfaces,
1002 .descrip = "List the interfaces provided",
1005 .longName = "worker-group",
1006 .argInfo = POPT_ARG_INT,
1007 .arg = &worker_group,
1008 .descrip = "Group index in status message",
1011 .longName = "worker-index",
1012 .argInfo = POPT_ARG_INT,
1013 .arg = &worker_index,
1014 .descrip = "Worker index in status message",
1019 static const struct smbd_shim smbd_shim_fns = {
1020 .become_authenticated_pipe_user =
1021 smbd_become_authenticated_pipe_user,
1022 .unbecome_authenticated_pipe_user =
1023 smbd_unbecome_authenticated_pipe_user,
1024 .become_root = smbd_become_root,
1025 .unbecome_root = smbd_unbecome_root,
1029 talloc_enable_null_tracking();
1030 frame = talloc_stackframe();
1034 ok = samba_cmdline_init(frame,
1035 SAMBA_CMDLINE_CONFIG_SERVER,
1036 true /* require_smbconf */);
1038 DBG_ERR("Failed to init cmdline parser!\n");
1043 pc = samba_popt_get_context(progname, argc, argv, long_options, 0);
1045 DBG_ERR("Failed to setup popt context!\n");
1050 while ((opt = poptGetNextOpt(pc)) != -1) {
1052 "\nInvalid option %s: %s\n\n",
1053 poptBadOption(pc, 0),
1055 poptPrintUsage(pc, stderr, 0);
1059 poptFreeContext(pc);
1061 if (list_interfaces != 0) {
1062 const struct ndr_interface_table **ifaces = NULL;
1065 num_workers = lp_parm_int(
1066 -1, daemon_config_name, "num_workers", num_workers);
1067 idle_seconds = lp_parm_int(
1068 -1, daemon_config_name, "idle_seconds", idle_seconds);
1070 DBG_DEBUG("daemon=%s, num_workers=%d, idle_seconds=%d\n",
1075 fprintf(stdout, "%d\n%d\n", num_workers, idle_seconds);
1077 num_ifaces = get_interfaces(&ifaces, private_data);
1079 for (i=0; i<num_ifaces; i++) {
1080 rpc_worker_print_interface(stdout, ifaces[i]);
1087 log_stdout = (debug_get_log_type() == DEBUG_STDOUT);
1088 if (log_stdout != 0) {
1089 setup_logging(argv[0], DEBUG_STDOUT);
1091 setup_logging(argv[0], DEBUG_FILE);
1094 set_smbd_shim(&smbd_shim_fns);
1096 dump_core_setup(progname, lp_logfile(talloc_tos(), lp_sub));
1098 /* POSIX demands that signals are inherited. If the invoking
1099 * process has these signals masked, we will have problems, as
1100 * we won't receive them. */
1101 BlockSignals(False, SIGHUP);
1102 BlockSignals(False, SIGUSR1);
1103 BlockSignals(False, SIGTERM);
1106 /* we are never interested in SIGFPE */
1107 BlockSignals(True,SIGFPE);
1109 /* We no longer use USR2... */
1110 #if defined(SIGUSR2)
1111 BlockSignals(True, SIGUSR2);
1113 /* Ignore children - no zombies. */
1116 DEBUG(0, ("%s version %s started.\n",
1118 samba_version_string()));
1119 DEBUGADD(0,("%s\n", COPYRIGHT_STARTUP_MESSAGE));
1121 msg_ctx = global_messaging_context();
1122 if (msg_ctx == NULL) {
1123 DBG_ERR("global_messaging_context() failed\n");
1127 ev_ctx = messaging_tevent_context(msg_ctx);
1129 worker = rpc_worker_new(ev_ctx, msg_ctx);
1130 if (worker == NULL) {
1131 DBG_ERR("rpc_worker_new failed\n");
1132 global_messaging_context_free();
1136 dce_ctx = rpc_worker_dce_ctx(worker);
1138 se = tevent_add_signal(
1139 ev_ctx, ev_ctx, SIGTERM, 0, sig_term_handler, NULL);
1141 DBG_ERR("tevent_add_signal failed\n");
1142 global_messaging_context_free();
1146 BlockSignals(false, SIGTERM);
1148 se = tevent_add_signal(
1149 ev_ctx, ev_ctx, SIGHUP, 0, sig_hup_handler, NULL);
1151 DBG_ERR("tevent_add_signal failed\n");
1152 global_messaging_context_free();
1156 BlockSignals(false, SIGHUP);
1158 (void)winbind_off();
1159 ok = init_guest_session_info(NULL);
1162 DBG_WARNING("init_guest_session_info failed\n");
1163 global_messaging_context_free();
1168 status = init_system_session_info(NULL);
1169 if (!NT_STATUS_IS_OK(status)) {
1170 DBG_WARNING("init_system_session_info failed: %s\n",
1172 global_messaging_context_free();
1177 DBG_INFO("Initializing DCE/RPC registered endpoint servers\n");
1179 num_servers = get_servers(dce_ctx, &ep_servers, private_data);
1181 DBG_DEBUG("get_servers() returned %zu servers\n", num_servers);
1183 for (i=0; i<num_servers; i++) {
1184 status = register_ep_server(dce_ctx, ep_servers[i]);
1185 if (!NT_STATUS_IS_OK(status)) {
1186 DBG_DEBUG("register_ep_server failed: %s\n",
1188 global_messaging_context_free();
1194 req = rpc_worker_send(
1195 ev_ctx, ev_ctx, worker, getppid(), worker_group, worker_index);
1197 DBG_ERR("rpc_worker_send failed\n");
1198 global_messaging_context_free();
1203 DBG_DEBUG("%s worker running\n", progname);
1205 while (tevent_req_is_in_progress(req)) {
1206 TALLOC_CTX *loop_frame = NULL;
1208 loop_frame = talloc_stackframe();
1210 ret = tevent_loop_once(ev_ctx);
1212 TALLOC_FREE(loop_frame);
1215 DBG_WARNING("tevent_req_once() failed: %s\n",
1217 global_messaging_context_free();
1223 status = dcesrv_shutdown_registered_ep_servers(dce_ctx);
1224 if (!NT_STATUS_IS_OK(status)) {
1225 DBG_DEBUG("Shutdown failed with: %s\n",
1229 ret = rpc_worker_recv(req);
1231 DBG_DEBUG("rpc_worker_recv returned %s\n", strerror(ret));
1232 global_messaging_context_free();