s4-torture: add test for clusapi_QueryValue.
[Samba.git] / source3 / rpc_server / mdssd.c
blobfac386bd9f69158d30e4c004f7cf83f15d9eda1f
1 /*
2 * Unix SMB/CIFS implementation.
4 * mds service daemon
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/>.
22 #include "includes.h"
23 #include "serverid.h"
24 #include "messages.h"
25 #include "ntdomain.h"
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"
43 #undef DBGC_CLASS
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,
55 .min_children = 5,
56 .max_children = 25,
57 .spawn_rate = 5,
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,
67 void *private_data,
68 uint32_t msg_type,
69 struct server_id server_id,
70 DATA_BLOB *data)
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());
80 reopen_logs();
81 if (mdssd_child_id == 0) {
82 pfh_daemon_config(DAEMON_NAME,
83 &pf_mdssd_cfg,
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,
91 int signum,
92 int count,
93 void *siginfo,
94 void *private_data)
96 rpc_mdssvc_shutdown();
98 DEBUG(0, ("termination signal\n"));
99 exit(0);
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,
107 ev_ctx,
108 SIGTERM, 0,
109 mdssd_sig_term_handler,
110 NULL);
111 if (!se) {
112 DEBUG(0, ("failed to setup SIGTERM handler\n"));
113 exit(1);
117 static void mdssd_sig_hup_handler(struct tevent_context *ev,
118 struct tevent_signal *se,
119 int signum,
120 int count,
121 void *siginfo,
122 void *pvt)
125 change_to_root_user();
126 lp_load_global(get_dyn_CONFIGFILE());
128 reopen_logs();
129 pfh_daemon_config(DAEMON_NAME,
130 &pf_mdssd_cfg,
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,
142 ev_ctx,
143 SIGHUP, 0,
144 mdssd_sig_hup_handler,
145 NULL);
146 if (!se) {
147 DEBUG(0, ("failed to setup SIGHUP handler\n"));
148 exit(1);
152 /**********************************************************
153 * Children
154 **********************************************************/
156 static void mdssd_chld_sig_hup_handler(struct tevent_context *ev,
157 struct tevent_signal *se,
158 int signum,
159 int count,
160 void *siginfo,
161 void *pvt)
163 change_to_root_user();
164 reopen_logs();
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,
172 ev_ctx,
173 SIGHUP, 0,
174 mdssd_chld_sig_hup_handler,
175 NULL);
176 if (!se) {
177 DEBUG(1, ("failed to setup SIGHUP handler"));
178 return false;
181 return true;
184 static void parent_ping(struct messaging_context *msg_ctx,
185 void *private_data,
186 uint32_t msg_type,
187 struct server_id server_id,
188 DATA_BLOB *data)
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"));
197 return;
200 static bool mdssd_child_init(struct tevent_context *ev_ctx,
201 int child_id,
202 struct pf_worker_data *pf)
204 NTSTATUS status;
205 struct messaging_context *msg_ctx = server_messaging_context();
206 bool ok;
208 status = reinit_after_fork(msg_ctx, ev_ctx,
209 true);
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;
218 reopen_logs();
220 ok = mdssd_setup_chld_hup_handler(ev_ctx);
221 if (!ok) {
222 return false;
225 if (!serverid_register(messaging_server_id(msg_ctx),
226 FLAG_MSG_GENERAL)) {
227 return false;
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",
238 nt_errstr(status)));
239 return false;
242 return true;
245 struct mdssd_children_data {
246 struct tevent_context *ev_ctx;
247 struct messaging_context *msg_ctx;
248 struct pf_worker_data *pf;
249 int listen_fd_size;
250 int *listen_fds;
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,
258 int child_id,
259 int listen_fd_size,
260 int *listen_fds,
261 void *private_data)
263 struct mdssd_children_data *data;
264 bool ok;
265 int ret = 0;
267 ok = mdssd_child_init(ev_ctx, child_id, pf);
268 if (!ok) {
269 return 1;
272 data = talloc(ev_ctx, struct mdssd_children_data);
273 if (!data) {
274 return 1;
276 data->pf = pf;
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);
288 if (ret != 0) {
289 DEBUG(0, ("tevent_loop_once() exited with %d: %s\n",
290 ret, strerror(errno)));
291 pf->status = PF_WORKER_EXITING;
295 return ret;
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 */
326 return;
329 next = talloc_zero(data, struct mdssd_new_client);
330 if (!next) {
331 DEBUG(1, ("Out of memory!?\n"));
332 return;
334 next->data = data;
336 req = prefork_listen_send(next,
337 data->ev_ctx,
338 data->pf,
339 data->listen_fd_size,
340 data->listen_fds);
341 if (!req) {
342 DEBUG(1, ("Failed to make listening request!?\n"));
343 talloc_free(next);
344 return;
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;
354 int rc;
355 int sd;
356 TALLOC_CTX *tmp_ctx;
357 struct tsocket_address *srv_addr;
358 struct tsocket_address *cli_addr;
360 client = tevent_req_callback_data(req, struct mdssd_new_client);
361 data = client->data;
363 tmp_ctx = talloc_stackframe();
364 if (tmp_ctx == NULL) {
365 DEBUG(1, ("Failed to allocate stackframe!\n"));
366 return;
369 rc = prefork_listen_recv(req,
370 tmp_ctx,
371 &sd,
372 &srv_addr,
373 &cli_addr);
375 /* this will free the request too */
376 talloc_free(client);
378 if (rc != 0) {
379 DEBUG(6, ("No client connection was available after all!\n"));
380 goto done;
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,
396 data->msg_ctx,
397 NCACN_IP_TCP,
398 "IP",
399 cli_addr,
400 srv_addr,
402 NULL);
403 } else if (tsocket_address_is_unix(srv_addr)) {
404 const char *p;
405 const char *b;
407 p = tsocket_address_unix_path(srv_addr, tmp_ctx);
408 if (p == NULL) {
409 talloc_free(tmp_ctx);
410 return;
413 b = strrchr(p, '/');
414 if (b != NULL) {
415 b++;
416 } else {
417 b = p;
420 if (strstr(p, "/np/")) {
421 named_pipe_accept_function(data->ev_ctx,
422 data->msg_ctx,
425 mdssd_client_terminated,
426 data);
427 } else {
428 dcerpc_ncacn_accept(data->ev_ctx,
429 data->msg_ctx,
430 NCALRPC,
432 cli_addr,
433 srv_addr,
435 NULL);
437 } else {
438 DEBUG(0, ("ERROR: Unsupported socket!\n"));
441 done:
442 talloc_free(tmp_ctx);
446 * MAIN
449 static void child_ping(struct messaging_context *msg_ctx,
450 void *private_data,
451 uint32_t msg_type,
452 struct server_id server_id,
453 DATA_BLOB *data)
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,
470 void *pvt);
472 static void mdssd_sigchld_handler(struct tevent_context *ev_ctx,
473 struct prefork_pool *pfp,
474 void *pvt)
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)
488 bool ok;
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());
495 return ok;
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);
512 if (!te) {
513 DEBUG(2, ("Failed to set up children monitoring!\n"));
514 return false;
517 return true;
520 static void mdssd_check_children(struct tevent_context *ev_ctx,
521 struct tevent_timer *te,
522 struct timeval current_time,
523 void *pvt)
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);
535 * start it up
538 static bool mdssd_create_sockets(struct tevent_context *ev_ctx,
539 struct messaging_context *msg_ctx,
540 int *listen_fd,
541 int *listen_fd_size)
543 struct dcerpc_binding_vector *v, *v_orig;
544 TALLOC_CTX *tmp_ctx;
545 NTSTATUS status;
546 int fd = -1;
547 int rc;
548 bool ok = false;
550 tmp_ctx = talloc_stackframe();
551 if (tmp_ctx == NULL) {
552 return false;
555 status = dcerpc_binding_vector_new(tmp_ctx, &v_orig);
556 if (!NT_STATUS_IS_OK(status)) {
557 goto done;
560 /* mdssvc */
561 fd = create_named_pipe_socket("mdssvc");
562 if (fd < 0) {
563 goto done;
566 rc = listen(fd, pf_mdssd_cfg.max_allowed_clients);
567 if (rc == -1) {
568 goto done;
570 listen_fd[*listen_fd_size] = fd;
571 (*listen_fd_size)++;
573 fd = create_dcerpc_ncalrpc_socket("mdssvc");
574 if (fd < 0) {
575 goto done;
578 rc = listen(fd, pf_mdssd_cfg.max_allowed_clients);
579 if (rc == -1) {
580 goto done;
582 listen_fd[*listen_fd_size] = fd;
583 (*listen_fd_size)++;
584 fd = -1;
586 v = dcerpc_binding_vector_dup(tmp_ctx, v_orig);
587 if (v == NULL) {
588 goto done;
591 status = dcerpc_binding_vector_replace_iface(&ndr_table_mdssvc, v);
592 if (!NT_STATUS_IS_OK(status)) {
593 goto done;
596 status = dcerpc_binding_vector_add_np_default(&ndr_table_mdssvc, v);
597 if (!NT_STATUS_IS_OK(status)) {
598 goto done;
601 status = dcerpc_binding_vector_add_unix(&ndr_table_mdssvc, v, "mdssvc");
602 if (!NT_STATUS_IS_OK(status)) {
603 goto done;
606 ok = true;
607 done:
608 if (fd != -1) {
609 close(fd);
611 talloc_free(tmp_ctx);
612 return ok;
615 static bool mdssvc_init_cb(void *ptr)
617 struct messaging_context *msg_ctx =
618 talloc_get_type_abort(ptr, struct messaging_context);
619 bool ok;
621 ok = init_service_mdssvc(msg_ctx);
622 if (!ok) {
623 return false;
626 return true;
629 static bool mdssvc_shutdown_cb(void *ptr)
631 shutdown_service_mdssvc();
633 return true;
636 void start_mdssd(struct tevent_context *ev_ctx,
637 struct messaging_context *msg_ctx)
639 NTSTATUS status;
640 int listen_fd[MDSSD_MAX_SOCKETS];
641 int listen_fd_size = 0;
642 pid_t pid;
643 int rc;
644 bool ok;
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);
657 pid = fork();
658 if (pid == -1) {
659 DEBUG(0, ("Failed to fork mdssd [%s], aborting ...\n",
660 strerror(errno)));
661 exit(1);
664 /* parent or error */
665 if (pid != 0) {
667 /* Re-enable SIGHUP before returnig */
668 BlockSignals(false, SIGTERM);
669 BlockSignals(false, SIGHUP);
671 return;
674 status = reinit_after_fork(msg_ctx,
675 ev_ctx,
676 true);
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");
683 reopen_logs();
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,
689 &pf_mdssd_cfg,
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);
699 if (!ok) {
700 exit(1);
703 /* start children before any more initialization is done */
704 ok = prefork_create_pool(ev_ctx, /* mem_ctx */
705 ev_ctx,
706 msg_ctx,
707 listen_fd_size,
708 listen_fd,
709 pf_mdssd_cfg.min_children,
710 pf_mdssd_cfg.max_children,
711 &mdssd_children_main,
712 NULL,
713 &mdssd_pool);
714 if (!ok) {
715 exit(1);
718 if (!serverid_register(messaging_server_id(msg_ctx),
719 FLAG_MSG_GENERAL)) {
720 exit(1);
723 messaging_register(msg_ctx,
724 ev_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)) {
736 exit(1);
739 ok = mdssd_setup_children_monitor(ev_ctx, msg_ctx);
740 if (!ok) {
741 exit(1);
744 DEBUG(1, ("mdssd Daemon Started (%u)\n", (unsigned int)getpid()));
746 /* loop forever */
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)));
752 exit(1);