2 * Unix SMB/CIFS implementation.
6 * Copyright (c) 2014 Ralph Boehme <rb@sernet.de>
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/>.
27 #include "lib/util/util_process.h"
29 #include "lib/id_cache.h"
31 #include "../lib/tsocket/tsocket.h"
32 #include "lib/server_prefork.h"
33 #include "lib/server_prefork_util.h"
34 #include "librpc/rpc/dcerpc_ep.h"
36 #include "rpc_server/rpc_server.h"
37 #include "rpc_server/rpc_ep_register.h"
38 #include "rpc_server/rpc_sock_helper.h"
40 #include "librpc/gen_ndr/srv_mdssvc.h"
41 #include "rpc_server/mdssvc/srv_mdssvc_nt.h"
44 #define DBGC_CLASS DBGC_RPC_SRV
46 #define DAEMON_NAME "mdssd"
47 #define MDSSD_MAX_SOCKETS 64
49 static struct server_id parent_id
;
50 static struct prefork_pool
*mdssd_pool
= NULL
;
51 static int mdssd_child_id
= 0;
53 static struct pf_daemon_config default_pf_mdssd_cfg
= {
54 .prefork_status
= PFH_INIT
,
58 .max_allowed_clients
= 1000,
59 .child_min_life
= 60 /* 1 minute minimum life time */
61 static struct pf_daemon_config pf_mdssd_cfg
= { 0 };
63 void start_mdssd(struct tevent_context
*ev_ctx
,
64 struct messaging_context
*msg_ctx
);
66 static void mdssd_smb_conf_updated(struct messaging_context
*msg
,
69 struct server_id server_id
,
72 struct tevent_context
*ev_ctx
;
74 DEBUG(10, ("Got message saying smb.conf was updated. Reloading.\n"));
75 ev_ctx
= talloc_get_type_abort(private_data
, struct tevent_context
);
77 change_to_root_user();
78 lp_load_global(get_dyn_CONFIGFILE());
81 if (mdssd_child_id
== 0) {
82 pfh_daemon_config(DAEMON_NAME
,
84 &default_pf_mdssd_cfg
);
85 pfh_manage_pool(ev_ctx
, msg
, &pf_mdssd_cfg
, mdssd_pool
);
89 static void mdssd_sig_term_handler(struct tevent_context
*ev
,
90 struct tevent_signal
*se
,
96 rpc_mdssvc_shutdown();
98 DEBUG(0, ("termination signal\n"));
102 static void mdssd_setup_sig_term_handler(struct tevent_context
*ev_ctx
)
104 struct tevent_signal
*se
;
106 se
= tevent_add_signal(ev_ctx
,
109 mdssd_sig_term_handler
,
112 DEBUG(0, ("failed to setup SIGTERM handler\n"));
117 static void mdssd_sig_hup_handler(struct tevent_context
*ev
,
118 struct tevent_signal
*se
,
125 change_to_root_user();
126 lp_load_global(get_dyn_CONFIGFILE());
129 pfh_daemon_config(DAEMON_NAME
,
131 &default_pf_mdssd_cfg
);
133 /* relay to all children */
134 prefork_send_signal_to_all(mdssd_pool
, SIGHUP
);
137 static void mdssd_setup_sig_hup_handler(struct tevent_context
*ev_ctx
)
139 struct tevent_signal
*se
;
141 se
= tevent_add_signal(ev_ctx
,
144 mdssd_sig_hup_handler
,
147 DEBUG(0, ("failed to setup SIGHUP handler\n"));
152 /**********************************************************
154 **********************************************************/
156 static void mdssd_chld_sig_hup_handler(struct tevent_context
*ev
,
157 struct tevent_signal
*se
,
163 change_to_root_user();
167 static bool mdssd_setup_chld_hup_handler(struct tevent_context
*ev_ctx
)
169 struct tevent_signal
*se
;
171 se
= tevent_add_signal(ev_ctx
,
174 mdssd_chld_sig_hup_handler
,
177 DEBUG(1, ("failed to setup SIGHUP handler"));
184 static void parent_ping(struct messaging_context
*msg_ctx
,
187 struct server_id server_id
,
191 * The fact we received this message is enough to let make the
192 * event loop if it was idle. mdssd_children_main will cycle
193 * through mdssd_next_client at least once. That function will
194 * take whatever action is necessary
196 DEBUG(10, ("Got message that the parent changed status.\n"));
200 static bool mdssd_child_init(struct tevent_context
*ev_ctx
,
202 struct pf_worker_data
*pf
)
205 struct messaging_context
*msg_ctx
= server_messaging_context();
208 status
= reinit_after_fork(msg_ctx
, ev_ctx
,
210 if (!NT_STATUS_IS_OK(status
)) {
211 DEBUG(0,("reinit_after_fork() failed\n"));
212 smb_panic("reinit_after_fork() failed");
215 prctl_set_comment("mdssd-child");
217 mdssd_child_id
= child_id
;
220 ok
= mdssd_setup_chld_hup_handler(ev_ctx
);
225 if (!serverid_register(messaging_server_id(msg_ctx
),
230 messaging_register(msg_ctx
, ev_ctx
,
231 MSG_SMB_CONF_UPDATED
, mdssd_smb_conf_updated
);
232 messaging_register(msg_ctx
, ev_ctx
,
233 MSG_PREFORK_PARENT_EVENT
, parent_ping
);
235 status
= rpc_mdssvc_init(NULL
);
236 if (!NT_STATUS_IS_OK(status
)) {
237 DEBUG(0, ("Failed to intialize RPC: %s\n",
245 struct mdssd_children_data
{
246 struct tevent_context
*ev_ctx
;
247 struct messaging_context
*msg_ctx
;
248 struct pf_worker_data
*pf
;
253 static void mdssd_next_client(void *pvt
);
255 static int mdssd_children_main(struct tevent_context
*ev_ctx
,
256 struct messaging_context
*msg_ctx
,
257 struct pf_worker_data
*pf
,
263 struct mdssd_children_data
*data
;
267 ok
= mdssd_child_init(ev_ctx
, child_id
, pf
);
272 data
= talloc(ev_ctx
, struct mdssd_children_data
);
277 data
->ev_ctx
= ev_ctx
;
278 data
->msg_ctx
= msg_ctx
;
279 data
->listen_fd_size
= listen_fd_size
;
280 data
->listen_fds
= listen_fds
;
282 /* loop until it is time to exit */
283 while (pf
->status
!= PF_WORKER_EXITING
) {
284 /* try to see if it is time to schedule the next client */
285 mdssd_next_client(data
);
287 ret
= tevent_loop_once(ev_ctx
);
289 DEBUG(0, ("tevent_loop_once() exited with %d: %s\n",
290 ret
, strerror(errno
)));
291 pf
->status
= PF_WORKER_EXITING
;
298 static void mdssd_client_terminated(void *pvt
)
300 struct mdssd_children_data
*data
;
302 data
= talloc_get_type_abort(pvt
, struct mdssd_children_data
);
304 pfh_client_terminated(data
->pf
);
306 mdssd_next_client(pvt
);
309 struct mdssd_new_client
{
310 struct mdssd_children_data
*data
;
313 static void mdssd_handle_client(struct tevent_req
*req
);
315 static void mdssd_next_client(void *pvt
)
317 struct tevent_req
*req
;
318 struct mdssd_children_data
*data
;
319 struct mdssd_new_client
*next
;
321 data
= talloc_get_type_abort(pvt
, struct mdssd_children_data
);
323 if (!pfh_child_allowed_to_accept(data
->pf
)) {
324 /* nothing to do for now we are already listening
325 * or we are not allowed to listen further */
329 next
= talloc_zero(data
, struct mdssd_new_client
);
331 DEBUG(1, ("Out of memory!?\n"));
336 req
= prefork_listen_send(next
,
339 data
->listen_fd_size
,
342 DEBUG(1, ("Failed to make listening request!?\n"));
346 tevent_req_set_callback(req
, mdssd_handle_client
, next
);
349 static void mdssd_handle_client(struct tevent_req
*req
)
351 struct mdssd_children_data
*data
;
352 struct mdssd_new_client
*client
;
353 const DATA_BLOB ping
= data_blob_null
;
357 struct tsocket_address
*srv_addr
;
358 struct tsocket_address
*cli_addr
;
360 client
= tevent_req_callback_data(req
, struct mdssd_new_client
);
363 tmp_ctx
= talloc_stackframe();
364 if (tmp_ctx
== NULL
) {
365 DEBUG(1, ("Failed to allocate stackframe!\n"));
369 rc
= prefork_listen_recv(req
,
375 /* this will free the request too */
379 DEBUG(6, ("No client connection was available after all!\n"));
383 /* Warn parent that our status changed */
384 messaging_send(data
->msg_ctx
, parent_id
,
385 MSG_PREFORK_CHILD_EVENT
, &ping
);
387 DEBUG(2, ("mdssd preforked child %d got client connection!\n",
388 (int)(data
->pf
->pid
)));
390 if (tsocket_address_is_inet(srv_addr
, "ip")) {
391 DEBUG(3, ("Got a tcpip client connection from %s on inteface %s\n",
392 tsocket_address_string(cli_addr
, tmp_ctx
),
393 tsocket_address_string(srv_addr
, tmp_ctx
)));
395 dcerpc_ncacn_accept(data
->ev_ctx
,
403 } else if (tsocket_address_is_unix(srv_addr
)) {
407 p
= tsocket_address_unix_path(srv_addr
, tmp_ctx
);
409 talloc_free(tmp_ctx
);
420 if (strstr(p
, "/np/")) {
421 named_pipe_accept_function(data
->ev_ctx
,
425 mdssd_client_terminated
,
428 dcerpc_ncacn_accept(data
->ev_ctx
,
438 DEBUG(0, ("ERROR: Unsupported socket!\n"));
442 talloc_free(tmp_ctx
);
449 static void child_ping(struct messaging_context
*msg_ctx
,
452 struct server_id server_id
,
455 struct tevent_context
*ev_ctx
;
457 ev_ctx
= talloc_get_type_abort(private_data
, struct tevent_context
);
459 DEBUG(10, ("Got message that a child changed status.\n"));
460 pfh_manage_pool(ev_ctx
, msg_ctx
, &pf_mdssd_cfg
, mdssd_pool
);
463 static bool mdssd_schedule_check(struct tevent_context
*ev_ctx
,
464 struct messaging_context
*msg_ctx
,
465 struct timeval current_time
);
467 static void mdssd_check_children(struct tevent_context
*ev_ctx
,
468 struct tevent_timer
*te
,
469 struct timeval current_time
,
472 static void mdssd_sigchld_handler(struct tevent_context
*ev_ctx
,
473 struct prefork_pool
*pfp
,
476 struct messaging_context
*msg_ctx
;
478 msg_ctx
= talloc_get_type_abort(pvt
, struct messaging_context
);
480 /* run pool management so we can fork/retire or increase
481 * the allowed connections per child based on load */
482 pfh_manage_pool(ev_ctx
, msg_ctx
, &pf_mdssd_cfg
, mdssd_pool
);
485 static bool mdssd_setup_children_monitor(struct tevent_context
*ev_ctx
,
486 struct messaging_context
*msg_ctx
)
490 /* add our oun sigchld callback */
491 prefork_set_sigchld_callback(mdssd_pool
, mdssd_sigchld_handler
, msg_ctx
);
493 ok
= mdssd_schedule_check(ev_ctx
, msg_ctx
, tevent_timeval_current());
498 static bool mdssd_schedule_check(struct tevent_context
*ev_ctx
,
499 struct messaging_context
*msg_ctx
,
500 struct timeval current_time
)
502 struct tevent_timer
*te
;
503 struct timeval next_event
;
505 /* check situation again in 10 seconds */
506 next_event
= tevent_timeval_current_ofs(10, 0);
508 /* TODO: check when the socket becomes readable, so that children
509 * are checked only when there is some activity ? */
510 te
= tevent_add_timer(ev_ctx
, mdssd_pool
, next_event
,
511 mdssd_check_children
, msg_ctx
);
513 DEBUG(2, ("Failed to set up children monitoring!\n"));
520 static void mdssd_check_children(struct tevent_context
*ev_ctx
,
521 struct tevent_timer
*te
,
522 struct timeval current_time
,
525 struct messaging_context
*msg_ctx
;
527 msg_ctx
= talloc_get_type_abort(pvt
, struct messaging_context
);
529 pfh_manage_pool(ev_ctx
, msg_ctx
, &pf_mdssd_cfg
, mdssd_pool
);
531 mdssd_schedule_check(ev_ctx
, msg_ctx
, current_time
);
538 static bool mdssd_create_sockets(struct tevent_context
*ev_ctx
,
539 struct messaging_context
*msg_ctx
,
543 struct dcerpc_binding_vector
*v
, *v_orig
;
550 tmp_ctx
= talloc_stackframe();
551 if (tmp_ctx
== NULL
) {
555 status
= dcerpc_binding_vector_new(tmp_ctx
, &v_orig
);
556 if (!NT_STATUS_IS_OK(status
)) {
561 fd
= create_named_pipe_socket("mdssvc");
566 rc
= listen(fd
, pf_mdssd_cfg
.max_allowed_clients
);
570 listen_fd
[*listen_fd_size
] = fd
;
573 fd
= create_dcerpc_ncalrpc_socket("mdssvc");
578 rc
= listen(fd
, pf_mdssd_cfg
.max_allowed_clients
);
582 listen_fd
[*listen_fd_size
] = fd
;
586 v
= dcerpc_binding_vector_dup(tmp_ctx
, v_orig
);
591 status
= dcerpc_binding_vector_replace_iface(&ndr_table_mdssvc
, v
);
592 if (!NT_STATUS_IS_OK(status
)) {
596 status
= dcerpc_binding_vector_add_np_default(&ndr_table_mdssvc
, v
);
597 if (!NT_STATUS_IS_OK(status
)) {
601 status
= dcerpc_binding_vector_add_unix(&ndr_table_mdssvc
, v
, "mdssvc");
602 if (!NT_STATUS_IS_OK(status
)) {
611 talloc_free(tmp_ctx
);
615 static bool mdssvc_init_cb(void *ptr
)
617 struct messaging_context
*msg_ctx
=
618 talloc_get_type_abort(ptr
, struct messaging_context
);
621 ok
= init_service_mdssvc(msg_ctx
);
629 static bool mdssvc_shutdown_cb(void *ptr
)
631 shutdown_service_mdssvc();
636 void start_mdssd(struct tevent_context
*ev_ctx
,
637 struct messaging_context
*msg_ctx
)
640 int listen_fd
[MDSSD_MAX_SOCKETS
];
641 int listen_fd_size
= 0;
645 struct rpc_srv_callbacks mdssvc_cb
;
647 DEBUG(1, ("Forking Metadata Service Daemon\n"));
650 * Block signals before forking child as it will have to
651 * set its own handlers. Child will re-enable SIGHUP as
652 * soon as the handlers are set up.
654 BlockSignals(true, SIGTERM
);
655 BlockSignals(true, SIGHUP
);
659 DEBUG(0, ("Failed to fork mdssd [%s], aborting ...\n",
664 /* parent or error */
667 /* Re-enable SIGHUP before returnig */
668 BlockSignals(false, SIGTERM
);
669 BlockSignals(false, SIGHUP
);
674 status
= reinit_after_fork(msg_ctx
,
677 if (!NT_STATUS_IS_OK(status
)) {
678 DEBUG(0,("reinit_after_fork() failed\n"));
679 smb_panic("reinit_after_fork() failed");
682 prctl_set_comment("mdssd-master");
685 /* save the parent process id so the children can use it later */
686 parent_id
= messaging_server_id(msg_ctx
);
688 pfh_daemon_config(DAEMON_NAME
,
690 &default_pf_mdssd_cfg
);
692 mdssd_setup_sig_term_handler(ev_ctx
);
693 mdssd_setup_sig_hup_handler(ev_ctx
);
695 BlockSignals(false, SIGTERM
);
696 BlockSignals(false, SIGHUP
);
698 ok
= mdssd_create_sockets(ev_ctx
, msg_ctx
, listen_fd
, &listen_fd_size
);
703 /* start children before any more initialization is done */
704 ok
= prefork_create_pool(ev_ctx
, /* mem_ctx */
709 pf_mdssd_cfg
.min_children
,
710 pf_mdssd_cfg
.max_children
,
711 &mdssd_children_main
,
718 if (!serverid_register(messaging_server_id(msg_ctx
),
723 messaging_register(msg_ctx
,
725 MSG_SMB_CONF_UPDATED
,
726 mdssd_smb_conf_updated
);
727 messaging_register(msg_ctx
, ev_ctx
,
728 MSG_PREFORK_CHILD_EVENT
, child_ping
);
730 mdssvc_cb
.init
= mdssvc_init_cb
;
731 mdssvc_cb
.shutdown
= mdssvc_shutdown_cb
;
732 mdssvc_cb
.private_data
= msg_ctx
;
734 status
= rpc_mdssvc_init(&mdssvc_cb
);
735 if (!NT_STATUS_IS_OK(status
)) {
739 ok
= mdssd_setup_children_monitor(ev_ctx
, msg_ctx
);
744 DEBUG(1, ("mdssd Daemon Started (%u)\n", (unsigned int)getpid()));
747 rc
= tevent_loop_wait(ev_ctx
);
749 /* should not be reached */
750 DEBUG(0,("mdssd: tevent_loop_wait() exited with %d - %s\n",
751 rc
, (rc
== 0) ? "out of events" : strerror(errno
)));