rpc_server: Give mdssd its header file
[sfrench/samba-autobuild/.git] / source3 / rpc_server / mdssd.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *
4  *  mds service daemon
5  *
6  *  Copyright (c) 2014      Ralph Boehme <rb@sernet.de>
7  *
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.
12  *
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.
17  *
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/>.
20  */
21
22 #include "includes.h"
23 #include "messages.h"
24 #include "ntdomain.h"
25
26 #include "lib/id_cache.h"
27
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
33 #include "rpc_server/rpc_server.h"
34 #include "rpc_server/rpc_ep_register.h"
35 #include "rpc_server/rpc_sock_helper.h"
36 #include "rpc_server/rpc_modules.h"
37
38 #include "librpc/gen_ndr/srv_mdssvc.h"
39 #include "rpc_server/mdssvc/srv_mdssvc_nt.h"
40 #include "rpc_server/mdssd.h"
41
42 #undef DBGC_CLASS
43 #define DBGC_CLASS DBGC_RPC_SRV
44
45 #define DAEMON_NAME "mdssd"
46 #define MDSSD_MAX_SOCKETS 64
47
48 static struct server_id parent_id;
49 static struct prefork_pool *mdssd_pool = NULL;
50 static int mdssd_child_id = 0;
51
52 static struct pf_daemon_config default_pf_mdssd_cfg = {
53         .prefork_status = PFH_INIT,
54         .min_children = 5,
55         .max_children = 25,
56         .spawn_rate = 5,
57         .max_allowed_clients = 1000,
58         .child_min_life = 60 /* 1 minute minimum life time */
59 };
60 static struct pf_daemon_config pf_mdssd_cfg = { 0 };
61
62 void start_mdssd(struct tevent_context *ev_ctx,
63                  struct messaging_context *msg_ctx);
64
65 static void mdssd_smb_conf_updated(struct messaging_context *msg,
66                                    void *private_data,
67                                    uint32_t msg_type,
68                                    struct server_id server_id,
69                                    DATA_BLOB *data)
70 {
71         struct tevent_context *ev_ctx;
72
73         DEBUG(10, ("Got message saying smb.conf was updated. Reloading.\n"));
74         ev_ctx = talloc_get_type_abort(private_data, struct tevent_context);
75
76         change_to_root_user();
77         lp_load_global(get_dyn_CONFIGFILE());
78
79         reopen_logs();
80         if (mdssd_child_id == 0) {
81                 pfh_daemon_config(DAEMON_NAME,
82                                   &pf_mdssd_cfg,
83                                   &default_pf_mdssd_cfg);
84                 pfh_manage_pool(ev_ctx, msg, &pf_mdssd_cfg, mdssd_pool);
85         }
86 }
87
88 static void mdssd_sig_term_handler(struct tevent_context *ev,
89                                    struct tevent_signal *se,
90                                    int signum,
91                                    int count,
92                                    void *siginfo,
93                                    void *private_data)
94 {
95         shutdown_rpc_module("mdssvc");
96
97         DEBUG(0, ("termination signal\n"));
98         exit(0);
99 }
100
101 static void mdssd_setup_sig_term_handler(struct tevent_context *ev_ctx)
102 {
103         struct tevent_signal *se;
104
105         se = tevent_add_signal(ev_ctx,
106                                ev_ctx,
107                                SIGTERM, 0,
108                                mdssd_sig_term_handler,
109                                NULL);
110         if (!se) {
111                 DEBUG(0, ("failed to setup SIGTERM handler\n"));
112                 exit(1);
113         }
114 }
115
116 static void mdssd_sig_hup_handler(struct tevent_context *ev,
117                                   struct tevent_signal *se,
118                                   int signum,
119                                   int count,
120                                   void *siginfo,
121                                   void *pvt)
122 {
123
124         change_to_root_user();
125         lp_load_global(get_dyn_CONFIGFILE());
126
127         reopen_logs();
128         pfh_daemon_config(DAEMON_NAME,
129                           &pf_mdssd_cfg,
130                           &default_pf_mdssd_cfg);
131
132         /* relay to all children */
133         prefork_send_signal_to_all(mdssd_pool, SIGHUP);
134 }
135
136 static void mdssd_setup_sig_hup_handler(struct tevent_context *ev_ctx)
137 {
138         struct tevent_signal *se;
139
140         se = tevent_add_signal(ev_ctx,
141                                ev_ctx,
142                                SIGHUP, 0,
143                                mdssd_sig_hup_handler,
144                                NULL);
145         if (!se) {
146                 DEBUG(0, ("failed to setup SIGHUP handler\n"));
147                 exit(1);
148         }
149 }
150
151 /**********************************************************
152  * Children
153  **********************************************************/
154
155 static void mdssd_chld_sig_hup_handler(struct tevent_context *ev,
156                                        struct tevent_signal *se,
157                                        int signum,
158                                        int count,
159                                        void *siginfo,
160                                        void *pvt)
161 {
162         change_to_root_user();
163         reopen_logs();
164 }
165
166 static bool mdssd_setup_chld_hup_handler(struct tevent_context *ev_ctx)
167 {
168         struct tevent_signal *se;
169
170         se = tevent_add_signal(ev_ctx,
171                                ev_ctx,
172                                SIGHUP, 0,
173                                mdssd_chld_sig_hup_handler,
174                                NULL);
175         if (!se) {
176                 DEBUG(1, ("failed to setup SIGHUP handler"));
177                 return false;
178         }
179
180         return true;
181 }
182
183 static void parent_ping(struct messaging_context *msg_ctx,
184                         void *private_data,
185                         uint32_t msg_type,
186                         struct server_id server_id,
187                         DATA_BLOB *data)
188 {
189         /*
190          * The fact we received this message is enough to let make the
191          * event loop if it was idle. mdssd_children_main will cycle
192          * through mdssd_next_client at least once. That function will
193          * take whatever action is necessary
194          */
195         DEBUG(10, ("Got message that the parent changed status.\n"));
196         return;
197 }
198
199 static bool mdssd_child_init(struct tevent_context *ev_ctx,
200                              int child_id,
201                              struct pf_worker_data *pf)
202 {
203         NTSTATUS status;
204         struct messaging_context *msg_ctx = global_messaging_context();
205         bool ok;
206
207         status = reinit_after_fork(msg_ctx, ev_ctx,
208                                    true, "mdssd-child");
209         if (!NT_STATUS_IS_OK(status)) {
210                 DEBUG(0,("reinit_after_fork() failed\n"));
211                 smb_panic("reinit_after_fork() failed");
212         }
213
214         mdssd_child_id = child_id;
215         reopen_logs();
216
217         ok = mdssd_setup_chld_hup_handler(ev_ctx);
218         if (!ok) {
219                 return false;
220         }
221
222         messaging_register(msg_ctx, ev_ctx,
223                            MSG_SMB_CONF_UPDATED, mdssd_smb_conf_updated);
224         messaging_register(msg_ctx, ev_ctx,
225                            MSG_PREFORK_PARENT_EVENT, parent_ping);
226
227         ok = init_rpc_module("mdssvc", NULL);
228         if (!ok) {
229                 DBG_ERR("Failed to de-intialize RPC\n");
230                 return false;
231         }
232
233         return true;
234 }
235
236 struct mdssd_children_data {
237         struct tevent_context *ev_ctx;
238         struct messaging_context *msg_ctx;
239         struct pf_worker_data *pf;
240         int listen_fd_size;
241         int *listen_fds;
242 };
243
244 static void mdssd_next_client(void *pvt);
245
246 static int mdssd_children_main(struct tevent_context *ev_ctx,
247                                struct messaging_context *msg_ctx,
248                                struct pf_worker_data *pf,
249                                int child_id,
250                                int listen_fd_size,
251                                int *listen_fds,
252                                void *private_data)
253 {
254         struct mdssd_children_data *data;
255         bool ok;
256         int ret = 0;
257
258         ok = mdssd_child_init(ev_ctx, child_id, pf);
259         if (!ok) {
260                 return 1;
261         }
262
263         data = talloc(ev_ctx, struct mdssd_children_data);
264         if (!data) {
265                 return 1;
266         }
267         data->pf = pf;
268         data->ev_ctx = ev_ctx;
269         data->msg_ctx = msg_ctx;
270         data->listen_fd_size = listen_fd_size;
271         data->listen_fds = listen_fds;
272
273         /* loop until it is time to exit */
274         while (pf->status != PF_WORKER_EXITING) {
275                 /* try to see if it is time to schedule the next client */
276                 mdssd_next_client(data);
277
278                 ret = tevent_loop_once(ev_ctx);
279                 if (ret != 0) {
280                         DEBUG(0, ("tevent_loop_once() exited with %d: %s\n",
281                                   ret, strerror(errno)));
282                         pf->status = PF_WORKER_EXITING;
283                 }
284         }
285
286         return ret;
287 }
288
289 static void mdssd_client_terminated(void *pvt)
290 {
291         struct mdssd_children_data *data;
292
293         data = talloc_get_type_abort(pvt, struct mdssd_children_data);
294
295         pfh_client_terminated(data->pf);
296
297         mdssd_next_client(pvt);
298 }
299
300 struct mdssd_new_client {
301         struct mdssd_children_data *data;
302 };
303
304 static void mdssd_handle_client(struct tevent_req *req);
305
306 static void mdssd_next_client(void *pvt)
307 {
308         struct tevent_req *req;
309         struct mdssd_children_data *data;
310         struct mdssd_new_client *next;
311
312         data = talloc_get_type_abort(pvt, struct mdssd_children_data);
313
314         if (!pfh_child_allowed_to_accept(data->pf)) {
315                 /* nothing to do for now we are already listening
316                  * or we are not allowed to listen further */
317                 return;
318         }
319
320         next = talloc_zero(data, struct mdssd_new_client);
321         if (!next) {
322                 DEBUG(1, ("Out of memory!?\n"));
323                 return;
324         }
325         next->data = data;
326
327         req = prefork_listen_send(next,
328                                   data->ev_ctx,
329                                   data->pf,
330                                   data->listen_fd_size,
331                                   data->listen_fds);
332         if (!req) {
333                 DEBUG(1, ("Failed to make listening request!?\n"));
334                 talloc_free(next);
335                 return;
336         }
337         tevent_req_set_callback(req, mdssd_handle_client, next);
338 }
339
340 static void mdssd_handle_client(struct tevent_req *req)
341 {
342         struct mdssd_children_data *data;
343         struct mdssd_new_client *client;
344         const DATA_BLOB ping = data_blob_null;
345         int rc;
346         int sd;
347         TALLOC_CTX *tmp_ctx;
348         struct tsocket_address *srv_addr;
349         struct tsocket_address *cli_addr;
350
351         client = tevent_req_callback_data(req, struct mdssd_new_client);
352         data = client->data;
353
354         tmp_ctx = talloc_stackframe();
355         if (tmp_ctx == NULL) {
356                 DEBUG(1, ("Failed to allocate stackframe!\n"));
357                 return;
358         }
359
360         rc = prefork_listen_recv(req,
361                                  tmp_ctx,
362                                  &sd,
363                                  &srv_addr,
364                                  &cli_addr);
365
366         /* this will free the request too */
367         talloc_free(client);
368
369         if (rc != 0) {
370                 DEBUG(6, ("No client connection was available after all!\n"));
371                 goto done;
372         }
373
374         /* Warn parent that our status changed */
375         messaging_send(data->msg_ctx, parent_id,
376                         MSG_PREFORK_CHILD_EVENT, &ping);
377
378         DEBUG(2, ("mdssd preforked child %d got client connection!\n",
379                   (int)(data->pf->pid)));
380
381         if (tsocket_address_is_inet(srv_addr, "ip")) {
382                 DEBUG(3, ("Got a tcpip client connection from %s on inteface %s\n",
383                            tsocket_address_string(cli_addr, tmp_ctx),
384                            tsocket_address_string(srv_addr, tmp_ctx)));
385
386                 dcerpc_ncacn_accept(data->ev_ctx,
387                                     data->msg_ctx,
388                                     NCACN_IP_TCP,
389                                     "IP",
390                                     cli_addr,
391                                     srv_addr,
392                                     sd,
393                                     NULL);
394         } else if (tsocket_address_is_unix(srv_addr)) {
395                 const char *p;
396                 const char *b;
397
398                 p = tsocket_address_unix_path(srv_addr, tmp_ctx);
399                 if (p == NULL) {
400                         talloc_free(tmp_ctx);
401                         return;
402                 }
403
404                 b = strrchr(p, '/');
405                 if (b != NULL) {
406                         b++;
407                 } else {
408                         b = p;
409                 }
410
411                 if (strstr(p, "/np/")) {
412                         named_pipe_accept_function(data->ev_ctx,
413                                                    data->msg_ctx,
414                                                    b,
415                                                    sd,
416                                                    mdssd_client_terminated,
417                                                    data);
418                 } else {
419                         dcerpc_ncacn_accept(data->ev_ctx,
420                                             data->msg_ctx,
421                                             NCALRPC,
422                                             b,
423                                             cli_addr,
424                                             srv_addr,
425                                             sd,
426                                             NULL);
427                 }
428         } else {
429                 DEBUG(0, ("ERROR: Unsupported socket!\n"));
430         }
431
432 done:
433         talloc_free(tmp_ctx);
434 }
435
436 /*
437  * MAIN
438  */
439
440 static void child_ping(struct messaging_context *msg_ctx,
441                         void *private_data,
442                         uint32_t msg_type,
443                         struct server_id server_id,
444                         DATA_BLOB *data)
445 {
446         struct tevent_context *ev_ctx;
447
448         ev_ctx = talloc_get_type_abort(private_data, struct tevent_context);
449
450         DEBUG(10, ("Got message that a child changed status.\n"));
451         pfh_manage_pool(ev_ctx, msg_ctx, &pf_mdssd_cfg, mdssd_pool);
452 }
453
454 static bool mdssd_schedule_check(struct tevent_context *ev_ctx,
455                                  struct messaging_context *msg_ctx,
456                                  struct timeval current_time);
457
458 static void mdssd_check_children(struct tevent_context *ev_ctx,
459                                     struct tevent_timer *te,
460                                     struct timeval current_time,
461                                     void *pvt);
462
463 static void mdssd_sigchld_handler(struct tevent_context *ev_ctx,
464                                   struct prefork_pool *pfp,
465                                   void *pvt)
466 {
467         struct messaging_context *msg_ctx;
468
469         msg_ctx = talloc_get_type_abort(pvt, struct messaging_context);
470
471         /* run pool management so we can fork/retire or increase
472          * the allowed connections per child based on load */
473         pfh_manage_pool(ev_ctx, msg_ctx, &pf_mdssd_cfg, mdssd_pool);
474 }
475
476 static bool mdssd_setup_children_monitor(struct tevent_context *ev_ctx,
477                                          struct messaging_context *msg_ctx)
478 {
479         bool ok;
480
481         /* add our oun sigchld callback */
482         prefork_set_sigchld_callback(mdssd_pool, mdssd_sigchld_handler, msg_ctx);
483
484         ok = mdssd_schedule_check(ev_ctx, msg_ctx, tevent_timeval_current());
485
486         return ok;
487 }
488
489 static bool mdssd_schedule_check(struct tevent_context *ev_ctx,
490                                  struct messaging_context *msg_ctx,
491                                  struct timeval current_time)
492 {
493         struct tevent_timer *te;
494         struct timeval next_event;
495
496         /* check situation again in 10 seconds */
497         next_event = tevent_timeval_current_ofs(10, 0);
498
499         /* TODO: check when the socket becomes readable, so that children
500          * are checked only when there is some activity ? */
501         te = tevent_add_timer(ev_ctx, mdssd_pool, next_event,
502                               mdssd_check_children, msg_ctx);
503         if (!te) {
504                 DEBUG(2, ("Failed to set up children monitoring!\n"));
505                 return false;
506         }
507
508         return true;
509 }
510
511 static void mdssd_check_children(struct tevent_context *ev_ctx,
512                                  struct tevent_timer *te,
513                                  struct timeval current_time,
514                                  void *pvt)
515 {
516         struct messaging_context *msg_ctx;
517
518         msg_ctx = talloc_get_type_abort(pvt, struct messaging_context);
519
520         pfh_manage_pool(ev_ctx, msg_ctx, &pf_mdssd_cfg, mdssd_pool);
521
522         mdssd_schedule_check(ev_ctx, msg_ctx, current_time);
523 }
524
525 /*
526  * start it up
527  */
528
529 static bool mdssd_create_sockets(struct tevent_context *ev_ctx,
530                                  struct messaging_context *msg_ctx,
531                                  int *listen_fd,
532                                  int *listen_fd_size)
533 {
534         struct dcerpc_binding_vector *v, *v_orig;
535         TALLOC_CTX *tmp_ctx;
536         NTSTATUS status;
537         int fd = -1;
538         int rc;
539         bool ok = false;
540
541         tmp_ctx = talloc_stackframe();
542         if (tmp_ctx == NULL) {
543                 return false;
544         }
545
546         status = dcerpc_binding_vector_new(tmp_ctx, &v_orig);
547         if (!NT_STATUS_IS_OK(status)) {
548                 goto done;
549         }
550
551         /* mdssvc */
552         fd = create_named_pipe_socket("mdssvc");
553         if (fd < 0) {
554                 goto done;
555         }
556
557         rc = listen(fd, pf_mdssd_cfg.max_allowed_clients);
558         if (rc == -1) {
559                 goto done;
560         }
561         listen_fd[*listen_fd_size] = fd;
562         (*listen_fd_size)++;
563
564         fd = create_dcerpc_ncalrpc_socket("mdssvc");
565         if (fd < 0) {
566                 goto done;
567         }
568
569         rc = listen(fd, pf_mdssd_cfg.max_allowed_clients);
570         if (rc == -1) {
571                 goto done;
572         }
573         listen_fd[*listen_fd_size] = fd;
574         (*listen_fd_size)++;
575         fd = -1;
576
577         v = dcerpc_binding_vector_dup(tmp_ctx, v_orig);
578         if (v == NULL) {
579                 goto done;
580         }
581
582         status = dcerpc_binding_vector_replace_iface(&ndr_table_mdssvc, v);
583         if (!NT_STATUS_IS_OK(status)) {
584                 goto done;
585         }
586
587         status = dcerpc_binding_vector_add_np_default(&ndr_table_mdssvc, v);
588         if (!NT_STATUS_IS_OK(status)) {
589                 goto done;
590         }
591
592         status = dcerpc_binding_vector_add_unix(&ndr_table_mdssvc, v, "mdssvc");
593         if (!NT_STATUS_IS_OK(status)) {
594                 goto done;
595         }
596
597         ok = true;
598 done:
599         if (fd != -1) {
600                 close(fd);
601         }
602         talloc_free(tmp_ctx);
603         return ok;
604 }
605
606 void start_mdssd(struct tevent_context *ev_ctx,
607                  struct messaging_context *msg_ctx)
608 {
609         NTSTATUS status;
610         int listen_fd[MDSSD_MAX_SOCKETS];
611         int listen_fd_size = 0;
612         pid_t pid;
613         int rc;
614         bool ok;
615
616         DEBUG(1, ("Forking Metadata Service Daemon\n"));
617
618         /*
619          * Block signals before forking child as it will have to
620          * set its own handlers. Child will re-enable SIGHUP as
621          * soon as the handlers are set up.
622          */
623         BlockSignals(true, SIGTERM);
624         BlockSignals(true, SIGHUP);
625
626         pid = fork();
627         if (pid == -1) {
628                 DEBUG(0, ("Failed to fork mdssd [%s], aborting ...\n",
629                            strerror(errno)));
630                 exit(1);
631         }
632
633         /* parent or error */
634         if (pid != 0) {
635
636                 /* Re-enable SIGHUP before returnig */
637                 BlockSignals(false, SIGTERM);
638                 BlockSignals(false, SIGHUP);
639
640                 return;
641         }
642
643         status = smbd_reinit_after_fork(msg_ctx, ev_ctx, true, "mdssd-master");
644         if (!NT_STATUS_IS_OK(status)) {
645                 DEBUG(0,("reinit_after_fork() failed\n"));
646                 smb_panic("reinit_after_fork() failed");
647         }
648
649         reopen_logs();
650
651         /* save the parent process id so the children can use it later */
652         parent_id = messaging_server_id(msg_ctx);
653
654         pfh_daemon_config(DAEMON_NAME,
655                           &pf_mdssd_cfg,
656                           &default_pf_mdssd_cfg);
657
658         mdssd_setup_sig_term_handler(ev_ctx);
659         mdssd_setup_sig_hup_handler(ev_ctx);
660
661         BlockSignals(false, SIGTERM);
662         BlockSignals(false, SIGHUP);
663
664         ok = mdssd_create_sockets(ev_ctx, msg_ctx, listen_fd, &listen_fd_size);
665         if (!ok) {
666                 exit(1);
667         }
668
669         /* start children before any more initialization is done */
670         ok = prefork_create_pool(ev_ctx, /* mem_ctx */
671                                  ev_ctx,
672                                  msg_ctx,
673                                  listen_fd_size,
674                                  listen_fd,
675                                  pf_mdssd_cfg.min_children,
676                                  pf_mdssd_cfg.max_children,
677                                  &mdssd_children_main,
678                                  NULL,
679                                  &mdssd_pool);
680         if (!ok) {
681                 exit(1);
682         }
683
684         messaging_register(msg_ctx,
685                            ev_ctx,
686                            MSG_SMB_CONF_UPDATED,
687                            mdssd_smb_conf_updated);
688         messaging_register(msg_ctx, ev_ctx,
689                            MSG_PREFORK_CHILD_EVENT, child_ping);
690
691         ok = setup_rpc_module(ev_ctx, msg_ctx, "mdssvc");
692         if (!ok) {
693                 exit(1);
694         }
695
696         ok = mdssd_setup_children_monitor(ev_ctx, msg_ctx);
697         if (!ok) {
698                 exit(1);
699         }
700
701         DEBUG(1, ("mdssd Daemon Started (%u)\n", (unsigned int)getpid()));
702
703         /* loop forever */
704         rc = tevent_loop_wait(ev_ctx);
705
706         /* should not be reached */
707         DEBUG(0,("mdssd: tevent_loop_wait() exited with %d - %s\n",
708                  rc, (rc == 0) ? "out of events" : strerror(errno)));
709         exit(1);
710 }