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/>.
26 #include "lib/id_cache.h"
28 #include "../lib/tsocket/tsocket.h"
29 #include "lib/server_prefork.h"
30 #include "lib/server_prefork_util.h"
31 #include "librpc/rpc/dcerpc_ep.h"
32 #include "librpc/rpc/dcesrv_core.h"
34 #include "rpc_server/rpc_server.h"
35 #include "rpc_server/rpc_service_setup.h"
36 #include "rpc_server/rpc_ep_register.h"
37 #include "rpc_server/rpc_sock_helper.h"
38 #include "rpc_server/rpc_modules.h"
40 #include "librpc/gen_ndr/srv_mdssvc.h"
41 #include "rpc_server/mdssvc/srv_mdssvc_nt.h"
42 #include "rpc_server/mdssd.h"
45 #define DBGC_CLASS DBGC_RPC_SRV
47 #define DAEMON_NAME "mdssd"
48 #define MDSSD_MAX_SOCKETS 64
50 static struct server_id parent_id
;
51 static struct prefork_pool
*mdssd_pool
= NULL
;
52 static int mdssd_child_id
= 0;
54 static struct pf_daemon_config default_pf_mdssd_cfg
= {
55 .prefork_status
= PFH_INIT
,
59 .max_allowed_clients
= 1000,
60 .child_min_life
= 60 /* 1 minute minimum life time */
62 static struct pf_daemon_config pf_mdssd_cfg
= { 0 };
64 static void mdssd_smb_conf_updated(struct messaging_context
*msg
,
67 struct server_id server_id
,
70 struct tevent_context
*ev_ctx
;
72 DEBUG(10, ("Got message saying smb.conf was updated. Reloading.\n"));
73 ev_ctx
= talloc_get_type_abort(private_data
, struct tevent_context
);
75 change_to_root_user();
76 lp_load_global(get_dyn_CONFIGFILE());
79 if (mdssd_child_id
== 0) {
80 pfh_daemon_config(DAEMON_NAME
,
82 &default_pf_mdssd_cfg
);
83 pfh_manage_pool(ev_ctx
, msg
, &pf_mdssd_cfg
, mdssd_pool
);
87 static void mdssd_sig_term_handler(struct tevent_context
*ev
,
88 struct tevent_signal
*se
,
94 exit_server_cleanly("termination signal");
97 static void mdssd_setup_sig_term_handler(struct tevent_context
*ev_ctx
)
99 struct tevent_signal
*se
;
101 se
= tevent_add_signal(ev_ctx
,
104 mdssd_sig_term_handler
,
107 exit_server("failed to setup SIGTERM handler");
111 static void mdssd_sig_hup_handler(struct tevent_context
*ev
,
112 struct tevent_signal
*se
,
119 change_to_root_user();
120 lp_load_global(get_dyn_CONFIGFILE());
123 pfh_daemon_config(DAEMON_NAME
,
125 &default_pf_mdssd_cfg
);
127 /* relay to all children */
128 prefork_send_signal_to_all(mdssd_pool
, SIGHUP
);
131 static void mdssd_setup_sig_hup_handler(struct tevent_context
*ev_ctx
)
133 struct tevent_signal
*se
;
135 se
= tevent_add_signal(ev_ctx
,
138 mdssd_sig_hup_handler
,
141 DEBUG(0, ("failed to setup SIGHUP handler\n"));
146 /**********************************************************
148 **********************************************************/
150 static void mdssd_chld_sig_hup_handler(struct tevent_context
*ev
,
151 struct tevent_signal
*se
,
157 change_to_root_user();
161 static bool mdssd_setup_chld_hup_handler(struct tevent_context
*ev_ctx
)
163 struct tevent_signal
*se
;
165 se
= tevent_add_signal(ev_ctx
,
168 mdssd_chld_sig_hup_handler
,
171 DEBUG(1, ("failed to setup SIGHUP handler"));
178 static void parent_ping(struct messaging_context
*msg_ctx
,
181 struct server_id server_id
,
185 * The fact we received this message is enough to let make the
186 * event loop if it was idle. mdssd_children_main will cycle
187 * through mdssd_next_client at least once. That function will
188 * take whatever action is necessary
190 DEBUG(10, ("Got message that the parent changed status.\n"));
194 static bool mdssd_child_init(struct tevent_context
*ev_ctx
,
196 struct pf_worker_data
*pf
)
199 struct messaging_context
*msg_ctx
= global_messaging_context();
202 status
= reinit_after_fork(msg_ctx
, ev_ctx
,
203 true, "mdssd-child");
204 if (!NT_STATUS_IS_OK(status
)) {
205 DEBUG(0,("reinit_after_fork() failed\n"));
206 smb_panic("reinit_after_fork() failed");
209 mdssd_child_id
= child_id
;
212 ok
= mdssd_setup_chld_hup_handler(ev_ctx
);
217 messaging_register(msg_ctx
, ev_ctx
,
218 MSG_SMB_CONF_UPDATED
, mdssd_smb_conf_updated
);
219 messaging_register(msg_ctx
, ev_ctx
,
220 MSG_PREFORK_PARENT_EVENT
, parent_ping
);
225 struct mdssd_children_data
{
226 struct tevent_context
*ev_ctx
;
227 struct messaging_context
*msg_ctx
;
228 struct dcesrv_context
*dce_ctx
;
229 struct pf_worker_data
*pf
;
231 struct pf_listen_fd
*listen_fds
;
234 static void mdssd_next_client(void *pvt
);
236 static int mdssd_children_main(struct tevent_context
*ev_ctx
,
237 struct messaging_context
*msg_ctx
,
238 struct pf_worker_data
*pf
,
241 struct pf_listen_fd
*listen_fds
,
244 struct mdssd_children_data
*data
;
247 struct dcesrv_context
*dce_ctx
= NULL
;
249 dce_ctx
= talloc_get_type_abort(private_data
, struct dcesrv_context
);
251 ok
= mdssd_child_init(ev_ctx
, child_id
, pf
);
256 data
= talloc(ev_ctx
, struct mdssd_children_data
);
261 data
->ev_ctx
= ev_ctx
;
262 data
->msg_ctx
= msg_ctx
;
263 data
->dce_ctx
= dce_ctx
;
264 data
->listen_fd_size
= listen_fd_size
;
265 data
->listen_fds
= listen_fds
;
267 /* loop until it is time to exit */
268 while (pf
->status
!= PF_WORKER_EXITING
) {
269 /* try to see if it is time to schedule the next client */
270 mdssd_next_client(data
);
272 ret
= tevent_loop_once(ev_ctx
);
274 DEBUG(0, ("tevent_loop_once() exited with %d: %s\n",
275 ret
, strerror(errno
)));
276 pf
->status
= PF_WORKER_EXITING
;
283 static void mdssd_client_terminated(struct dcesrv_connection
*conn
, void *pvt
)
285 struct mdssd_children_data
*data
;
287 data
= talloc_get_type_abort(pvt
, struct mdssd_children_data
);
289 pfh_client_terminated(data
->pf
);
291 mdssd_next_client(pvt
);
294 struct mdssd_new_client
{
295 struct mdssd_children_data
*data
;
298 static void mdssd_handle_client(struct tevent_req
*req
);
300 static void mdssd_next_client(void *pvt
)
302 struct tevent_req
*req
;
303 struct mdssd_children_data
*data
;
304 struct mdssd_new_client
*next
;
306 data
= talloc_get_type_abort(pvt
, struct mdssd_children_data
);
308 if (!pfh_child_allowed_to_accept(data
->pf
)) {
309 /* nothing to do for now we are already listening
310 * or we are not allowed to listen further */
314 next
= talloc_zero(data
, struct mdssd_new_client
);
316 DEBUG(1, ("Out of memory!?\n"));
321 req
= prefork_listen_send(next
,
324 data
->listen_fd_size
,
327 DEBUG(1, ("Failed to make listening request!?\n"));
331 tevent_req_set_callback(req
, mdssd_handle_client
, next
);
334 static void mdssd_handle_client(struct tevent_req
*req
)
336 struct mdssd_children_data
*data
;
337 struct mdssd_new_client
*client
;
338 const DATA_BLOB ping
= data_blob_null
;
342 struct tsocket_address
*srv_addr
;
343 struct tsocket_address
*cli_addr
;
344 void *listen_fd_data
= NULL
;
345 struct dcesrv_endpoint
*ep
= NULL
;
346 enum dcerpc_transport_t transport
;
347 dcerpc_ncacn_termination_fn term_fn
= NULL
;
348 void *term_fn_data
= NULL
;
350 client
= tevent_req_callback_data(req
, struct mdssd_new_client
);
353 tmp_ctx
= talloc_stackframe();
354 if (tmp_ctx
== NULL
) {
355 DEBUG(1, ("Failed to allocate stackframe!\n"));
359 rc
= prefork_listen_recv(req
,
366 /* this will free the request too */
370 DEBUG(6, ("No client connection was available after all!\n"));
374 ep
= talloc_get_type_abort(listen_fd_data
, struct dcesrv_endpoint
);
375 transport
= dcerpc_binding_get_transport(ep
->ep_description
);
376 if (transport
== NCACN_NP
) {
377 term_fn
= mdssd_client_terminated
;
381 /* Warn parent that our status changed */
382 messaging_send(data
->msg_ctx
, parent_id
,
383 MSG_PREFORK_CHILD_EVENT
, &ping
);
385 DBG_INFO("MDSSD preforked child %d got client connection on '%s'\n",
386 (int)(data
->pf
->pid
), dcerpc_binding_string(tmp_ctx
,
387 ep
->ep_description
));
389 dcerpc_ncacn_accept(data
->ev_ctx
,
400 talloc_free(tmp_ctx
);
407 static void child_ping(struct messaging_context
*msg_ctx
,
410 struct server_id server_id
,
413 struct tevent_context
*ev_ctx
;
415 ev_ctx
= talloc_get_type_abort(private_data
, struct tevent_context
);
417 DEBUG(10, ("Got message that a child changed status.\n"));
418 pfh_manage_pool(ev_ctx
, msg_ctx
, &pf_mdssd_cfg
, mdssd_pool
);
421 static bool mdssd_schedule_check(struct tevent_context
*ev_ctx
,
422 struct messaging_context
*msg_ctx
,
423 struct timeval current_time
);
425 static void mdssd_check_children(struct tevent_context
*ev_ctx
,
426 struct tevent_timer
*te
,
427 struct timeval current_time
,
430 static void mdssd_sigchld_handler(struct tevent_context
*ev_ctx
,
431 struct prefork_pool
*pfp
,
434 struct messaging_context
*msg_ctx
;
436 msg_ctx
= talloc_get_type_abort(pvt
, struct messaging_context
);
438 /* run pool management so we can fork/retire or increase
439 * the allowed connections per child based on load */
440 pfh_manage_pool(ev_ctx
, msg_ctx
, &pf_mdssd_cfg
, mdssd_pool
);
443 static bool mdssd_setup_children_monitor(struct tevent_context
*ev_ctx
,
444 struct messaging_context
*msg_ctx
)
448 /* add our oun sigchld callback */
449 prefork_set_sigchld_callback(mdssd_pool
, mdssd_sigchld_handler
, msg_ctx
);
451 ok
= mdssd_schedule_check(ev_ctx
, msg_ctx
, tevent_timeval_current());
456 static bool mdssd_schedule_check(struct tevent_context
*ev_ctx
,
457 struct messaging_context
*msg_ctx
,
458 struct timeval current_time
)
460 struct tevent_timer
*te
;
461 struct timeval next_event
;
463 /* check situation again in 10 seconds */
464 next_event
= tevent_timeval_current_ofs(10, 0);
466 /* TODO: check when the socket becomes readable, so that children
467 * are checked only when there is some activity ? */
468 te
= tevent_add_timer(ev_ctx
, mdssd_pool
, next_event
,
469 mdssd_check_children
, msg_ctx
);
471 DEBUG(2, ("Failed to set up children monitoring!\n"));
478 static void mdssd_check_children(struct tevent_context
*ev_ctx
,
479 struct tevent_timer
*te
,
480 struct timeval current_time
,
483 struct messaging_context
*msg_ctx
;
485 msg_ctx
= talloc_get_type_abort(pvt
, struct messaging_context
);
487 pfh_manage_pool(ev_ctx
, msg_ctx
, &pf_mdssd_cfg
, mdssd_pool
);
489 mdssd_schedule_check(ev_ctx
, msg_ctx
, current_time
);
496 static NTSTATUS
mdssd_create_sockets(struct tevent_context
*ev_ctx
,
497 struct messaging_context
*msg_ctx
,
498 struct dcesrv_context
*dce_ctx
,
499 struct pf_listen_fd
*listen_fd
,
506 struct dcesrv_endpoint
*e
= NULL
;
508 DBG_INFO("Initializing DCE/RPC connection endpoints\n");
510 for (e
= dce_ctx
->endpoint_list
; e
; e
= e
->next
) {
511 status
= dcesrv_create_endpoint_sockets(ev_ctx
,
517 if (!NT_STATUS_IS_OK(status
)) {
518 char *ep_string
= dcerpc_binding_string(
519 dce_ctx
, e
->ep_description
);
520 DBG_ERR("Failed to create endpoint '%s': %s\n",
521 ep_string
, nt_errstr(status
));
522 TALLOC_FREE(ep_string
);
527 for (i
= 0; i
< *listen_fd_size
; i
++) {
528 rc
= listen(listen_fd
[i
].fd
, pf_mdssd_cfg
.max_allowed_clients
);
530 char *ep_string
= dcerpc_binding_string(
531 dce_ctx
, e
->ep_description
);
532 DBG_ERR("Failed to listen on endpoint '%s': %s\n",
533 ep_string
, strerror(errno
));
534 status
= map_nt_error_from_unix(errno
);
535 TALLOC_FREE(ep_string
);
540 for (e
= dce_ctx
->endpoint_list
; e
; e
= e
->next
) {
541 struct dcesrv_if_list
*ifl
= NULL
;
542 for (ifl
= e
->interface_list
; ifl
; ifl
= ifl
->next
) {
543 status
= rpc_ep_register(ev_ctx
,
547 if (!NT_STATUS_IS_OK(status
)) {
548 DBG_ERR("Failed to register interface in "
549 "endpoint mapper: %s",
556 status
= NT_STATUS_OK
;
564 void start_mdssd(struct tevent_context
*ev_ctx
,
565 struct messaging_context
*msg_ctx
,
566 struct dcesrv_context
*dce_ctx
)
569 struct pf_listen_fd listen_fd
[MDSSD_MAX_SOCKETS
];
570 int listen_fd_size
= 0;
575 DEBUG(1, ("Forking Metadata Service Daemon\n"));
578 * Block signals before forking child as it will have to
579 * set its own handlers. Child will re-enable SIGHUP as
580 * soon as the handlers are set up.
582 BlockSignals(true, SIGTERM
);
583 BlockSignals(true, SIGHUP
);
587 DEBUG(0, ("Failed to fork mdssd [%s], aborting ...\n",
592 /* parent or error */
595 /* Re-enable SIGHUP before returnig */
596 BlockSignals(false, SIGTERM
);
597 BlockSignals(false, SIGHUP
);
602 status
= smbd_reinit_after_fork(msg_ctx
, ev_ctx
, true, "mdssd-master");
603 if (!NT_STATUS_IS_OK(status
)) {
604 DEBUG(0,("reinit_after_fork() failed\n"));
605 smb_panic("reinit_after_fork() failed");
610 /* save the parent process id so the children can use it later */
611 parent_id
= messaging_server_id(msg_ctx
);
613 pfh_daemon_config(DAEMON_NAME
,
615 &default_pf_mdssd_cfg
);
617 mdssd_setup_sig_term_handler(ev_ctx
);
618 mdssd_setup_sig_hup_handler(ev_ctx
);
620 BlockSignals(false, SIGTERM
);
621 BlockSignals(false, SIGHUP
);
623 /* The module setup function will register the endpoint server,
624 * necessary to setup the endpoints below. It is not possible to
625 * register it here because MDS service is built as a module.
627 ok
= setup_rpc_module(ev_ctx
, msg_ctx
, "mdssvc");
629 DBG_ERR("Failed to setup DCE/RPC module\n");
633 DBG_INFO("Reinitializing DCE/RPC server context\n");
635 status
= dcesrv_reinit_context(dce_ctx
);
636 if (!NT_STATUS_IS_OK(status
)) {
637 DBG_ERR("Failed to reinit DCE/RPC context: %s\n",
642 DBG_INFO("Initializing DCE/RPC registered endpoint servers\n");
644 /* Init ep servers */
645 status
= dcesrv_init_ep_server(dce_ctx
, "mdssvc");
646 if (!NT_STATUS_IS_OK(status
)) {
647 DBG_ERR("Failed to init DCE/RPC endpoint server: %s\n",
652 status
= mdssd_create_sockets(ev_ctx
,
657 if (!NT_STATUS_IS_OK(status
)) {
661 /* start children before any more initialization is done */
662 ok
= prefork_create_pool(ev_ctx
, /* mem_ctx */
667 pf_mdssd_cfg
.min_children
,
668 pf_mdssd_cfg
.max_children
,
669 &mdssd_children_main
,
676 messaging_register(msg_ctx
,
678 MSG_SMB_CONF_UPDATED
,
679 mdssd_smb_conf_updated
);
680 messaging_register(msg_ctx
, ev_ctx
,
681 MSG_PREFORK_CHILD_EVENT
, child_ping
);
683 ok
= mdssd_setup_children_monitor(ev_ctx
, msg_ctx
);
688 DEBUG(1, ("mdssd Daemon Started (%u)\n", (unsigned int)getpid()));
691 rc
= tevent_loop_wait(ev_ctx
);
693 /* should not be reached */
694 DEBUG(0,("mdssd: tevent_loop_wait() exited with %d - %s\n",
695 rc
, (rc
== 0) ? "out of events" : strerror(errno
)));