spoolss: rename spoolss_RpcDeleteJobNamedProperty to spoolss_DeleteJobNamedProperty
[amitay/samba.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 "serverid.h"
24 #include "messages.h"
25 #include "ntdomain.h"
26
27 #include "lib/id_cache.h"
28
29 #include "../lib/tsocket/tsocket.h"
30 #include "lib/server_prefork.h"
31 #include "lib/server_prefork_util.h"
32 #include "librpc/rpc/dcerpc_ep.h"
33
34 #include "rpc_server/rpc_server.h"
35 #include "rpc_server/rpc_ep_register.h"
36 #include "rpc_server/rpc_sock_helper.h"
37 #include "rpc_server/rpc_modules.h"
38
39 #include "librpc/gen_ndr/srv_mdssvc.h"
40 #include "rpc_server/mdssvc/srv_mdssvc_nt.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 = server_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         if (!serverid_register(messaging_server_id(msg_ctx),
223                                FLAG_MSG_GENERAL)) {
224                 return false;
225         }
226
227         messaging_register(msg_ctx, ev_ctx,
228                            MSG_SMB_CONF_UPDATED, mdssd_smb_conf_updated);
229         messaging_register(msg_ctx, ev_ctx,
230                            MSG_PREFORK_PARENT_EVENT, parent_ping);
231
232         ok = init_rpc_module("mdssvc", NULL);
233         if (!ok) {
234                 DBG_ERR("Failed to de-intialize RPC\n");
235                 return false;
236         }
237
238         return true;
239 }
240
241 struct mdssd_children_data {
242         struct tevent_context *ev_ctx;
243         struct messaging_context *msg_ctx;
244         struct pf_worker_data *pf;
245         int listen_fd_size;
246         int *listen_fds;
247 };
248
249 static void mdssd_next_client(void *pvt);
250
251 static int mdssd_children_main(struct tevent_context *ev_ctx,
252                                struct messaging_context *msg_ctx,
253                                struct pf_worker_data *pf,
254                                int child_id,
255                                int listen_fd_size,
256                                int *listen_fds,
257                                void *private_data)
258 {
259         struct mdssd_children_data *data;
260         bool ok;
261         int ret = 0;
262
263         ok = mdssd_child_init(ev_ctx, child_id, pf);
264         if (!ok) {
265                 return 1;
266         }
267
268         data = talloc(ev_ctx, struct mdssd_children_data);
269         if (!data) {
270                 return 1;
271         }
272         data->pf = pf;
273         data->ev_ctx = ev_ctx;
274         data->msg_ctx = msg_ctx;
275         data->listen_fd_size = listen_fd_size;
276         data->listen_fds = listen_fds;
277
278         /* loop until it is time to exit */
279         while (pf->status != PF_WORKER_EXITING) {
280                 /* try to see if it is time to schedule the next client */
281                 mdssd_next_client(data);
282
283                 ret = tevent_loop_once(ev_ctx);
284                 if (ret != 0) {
285                         DEBUG(0, ("tevent_loop_once() exited with %d: %s\n",
286                                   ret, strerror(errno)));
287                         pf->status = PF_WORKER_EXITING;
288                 }
289         }
290
291         return ret;
292 }
293
294 static void mdssd_client_terminated(void *pvt)
295 {
296         struct mdssd_children_data *data;
297
298         data = talloc_get_type_abort(pvt, struct mdssd_children_data);
299
300         pfh_client_terminated(data->pf);
301
302         mdssd_next_client(pvt);
303 }
304
305 struct mdssd_new_client {
306         struct mdssd_children_data *data;
307 };
308
309 static void mdssd_handle_client(struct tevent_req *req);
310
311 static void mdssd_next_client(void *pvt)
312 {
313         struct tevent_req *req;
314         struct mdssd_children_data *data;
315         struct mdssd_new_client *next;
316
317         data = talloc_get_type_abort(pvt, struct mdssd_children_data);
318
319         if (!pfh_child_allowed_to_accept(data->pf)) {
320                 /* nothing to do for now we are already listening
321                  * or we are not allowed to listen further */
322                 return;
323         }
324
325         next = talloc_zero(data, struct mdssd_new_client);
326         if (!next) {
327                 DEBUG(1, ("Out of memory!?\n"));
328                 return;
329         }
330         next->data = data;
331
332         req = prefork_listen_send(next,
333                                   data->ev_ctx,
334                                   data->pf,
335                                   data->listen_fd_size,
336                                   data->listen_fds);
337         if (!req) {
338                 DEBUG(1, ("Failed to make listening request!?\n"));
339                 talloc_free(next);
340                 return;
341         }
342         tevent_req_set_callback(req, mdssd_handle_client, next);
343 }
344
345 static void mdssd_handle_client(struct tevent_req *req)
346 {
347         struct mdssd_children_data *data;
348         struct mdssd_new_client *client;
349         const DATA_BLOB ping = data_blob_null;
350         int rc;
351         int sd;
352         TALLOC_CTX *tmp_ctx;
353         struct tsocket_address *srv_addr;
354         struct tsocket_address *cli_addr;
355
356         client = tevent_req_callback_data(req, struct mdssd_new_client);
357         data = client->data;
358
359         tmp_ctx = talloc_stackframe();
360         if (tmp_ctx == NULL) {
361                 DEBUG(1, ("Failed to allocate stackframe!\n"));
362                 return;
363         }
364
365         rc = prefork_listen_recv(req,
366                                  tmp_ctx,
367                                  &sd,
368                                  &srv_addr,
369                                  &cli_addr);
370
371         /* this will free the request too */
372         talloc_free(client);
373
374         if (rc != 0) {
375                 DEBUG(6, ("No client connection was available after all!\n"));
376                 goto done;
377         }
378
379         /* Warn parent that our status changed */
380         messaging_send(data->msg_ctx, parent_id,
381                         MSG_PREFORK_CHILD_EVENT, &ping);
382
383         DEBUG(2, ("mdssd preforked child %d got client connection!\n",
384                   (int)(data->pf->pid)));
385
386         if (tsocket_address_is_inet(srv_addr, "ip")) {
387                 DEBUG(3, ("Got a tcpip client connection from %s on inteface %s\n",
388                            tsocket_address_string(cli_addr, tmp_ctx),
389                            tsocket_address_string(srv_addr, tmp_ctx)));
390
391                 dcerpc_ncacn_accept(data->ev_ctx,
392                                     data->msg_ctx,
393                                     NCACN_IP_TCP,
394                                     "IP",
395                                     cli_addr,
396                                     srv_addr,
397                                     sd,
398                                     NULL);
399         } else if (tsocket_address_is_unix(srv_addr)) {
400                 const char *p;
401                 const char *b;
402
403                 p = tsocket_address_unix_path(srv_addr, tmp_ctx);
404                 if (p == NULL) {
405                         talloc_free(tmp_ctx);
406                         return;
407                 }
408
409                 b = strrchr(p, '/');
410                 if (b != NULL) {
411                         b++;
412                 } else {
413                         b = p;
414                 }
415
416                 if (strstr(p, "/np/")) {
417                         named_pipe_accept_function(data->ev_ctx,
418                                                    data->msg_ctx,
419                                                    b,
420                                                    sd,
421                                                    mdssd_client_terminated,
422                                                    data);
423                 } else {
424                         dcerpc_ncacn_accept(data->ev_ctx,
425                                             data->msg_ctx,
426                                             NCALRPC,
427                                             b,
428                                             cli_addr,
429                                             srv_addr,
430                                             sd,
431                                             NULL);
432                 }
433         } else {
434                 DEBUG(0, ("ERROR: Unsupported socket!\n"));
435         }
436
437 done:
438         talloc_free(tmp_ctx);
439 }
440
441 /*
442  * MAIN
443  */
444
445 static void child_ping(struct messaging_context *msg_ctx,
446                         void *private_data,
447                         uint32_t msg_type,
448                         struct server_id server_id,
449                         DATA_BLOB *data)
450 {
451         struct tevent_context *ev_ctx;
452
453         ev_ctx = talloc_get_type_abort(private_data, struct tevent_context);
454
455         DEBUG(10, ("Got message that a child changed status.\n"));
456         pfh_manage_pool(ev_ctx, msg_ctx, &pf_mdssd_cfg, mdssd_pool);
457 }
458
459 static bool mdssd_schedule_check(struct tevent_context *ev_ctx,
460                                  struct messaging_context *msg_ctx,
461                                  struct timeval current_time);
462
463 static void mdssd_check_children(struct tevent_context *ev_ctx,
464                                     struct tevent_timer *te,
465                                     struct timeval current_time,
466                                     void *pvt);
467
468 static void mdssd_sigchld_handler(struct tevent_context *ev_ctx,
469                                   struct prefork_pool *pfp,
470                                   void *pvt)
471 {
472         struct messaging_context *msg_ctx;
473
474         msg_ctx = talloc_get_type_abort(pvt, struct messaging_context);
475
476         /* run pool management so we can fork/retire or increase
477          * the allowed connections per child based on load */
478         pfh_manage_pool(ev_ctx, msg_ctx, &pf_mdssd_cfg, mdssd_pool);
479 }
480
481 static bool mdssd_setup_children_monitor(struct tevent_context *ev_ctx,
482                                          struct messaging_context *msg_ctx)
483 {
484         bool ok;
485
486         /* add our oun sigchld callback */
487         prefork_set_sigchld_callback(mdssd_pool, mdssd_sigchld_handler, msg_ctx);
488
489         ok = mdssd_schedule_check(ev_ctx, msg_ctx, tevent_timeval_current());
490
491         return ok;
492 }
493
494 static bool mdssd_schedule_check(struct tevent_context *ev_ctx,
495                                  struct messaging_context *msg_ctx,
496                                  struct timeval current_time)
497 {
498         struct tevent_timer *te;
499         struct timeval next_event;
500
501         /* check situation again in 10 seconds */
502         next_event = tevent_timeval_current_ofs(10, 0);
503
504         /* TODO: check when the socket becomes readable, so that children
505          * are checked only when there is some activity ? */
506         te = tevent_add_timer(ev_ctx, mdssd_pool, next_event,
507                               mdssd_check_children, msg_ctx);
508         if (!te) {
509                 DEBUG(2, ("Failed to set up children monitoring!\n"));
510                 return false;
511         }
512
513         return true;
514 }
515
516 static void mdssd_check_children(struct tevent_context *ev_ctx,
517                                  struct tevent_timer *te,
518                                  struct timeval current_time,
519                                  void *pvt)
520 {
521         struct messaging_context *msg_ctx;
522
523         msg_ctx = talloc_get_type_abort(pvt, struct messaging_context);
524
525         pfh_manage_pool(ev_ctx, msg_ctx, &pf_mdssd_cfg, mdssd_pool);
526
527         mdssd_schedule_check(ev_ctx, msg_ctx, current_time);
528 }
529
530 /*
531  * start it up
532  */
533
534 static bool mdssd_create_sockets(struct tevent_context *ev_ctx,
535                                  struct messaging_context *msg_ctx,
536                                  int *listen_fd,
537                                  int *listen_fd_size)
538 {
539         struct dcerpc_binding_vector *v, *v_orig;
540         TALLOC_CTX *tmp_ctx;
541         NTSTATUS status;
542         int fd = -1;
543         int rc;
544         bool ok = false;
545
546         tmp_ctx = talloc_stackframe();
547         if (tmp_ctx == NULL) {
548                 return false;
549         }
550
551         status = dcerpc_binding_vector_new(tmp_ctx, &v_orig);
552         if (!NT_STATUS_IS_OK(status)) {
553                 goto done;
554         }
555
556         /* mdssvc */
557         fd = create_named_pipe_socket("mdssvc");
558         if (fd < 0) {
559                 goto done;
560         }
561
562         rc = listen(fd, pf_mdssd_cfg.max_allowed_clients);
563         if (rc == -1) {
564                 goto done;
565         }
566         listen_fd[*listen_fd_size] = fd;
567         (*listen_fd_size)++;
568
569         fd = create_dcerpc_ncalrpc_socket("mdssvc");
570         if (fd < 0) {
571                 goto done;
572         }
573
574         rc = listen(fd, pf_mdssd_cfg.max_allowed_clients);
575         if (rc == -1) {
576                 goto done;
577         }
578         listen_fd[*listen_fd_size] = fd;
579         (*listen_fd_size)++;
580         fd = -1;
581
582         v = dcerpc_binding_vector_dup(tmp_ctx, v_orig);
583         if (v == NULL) {
584                 goto done;
585         }
586
587         status = dcerpc_binding_vector_replace_iface(&ndr_table_mdssvc, v);
588         if (!NT_STATUS_IS_OK(status)) {
589                 goto done;
590         }
591
592         status = dcerpc_binding_vector_add_np_default(&ndr_table_mdssvc, v);
593         if (!NT_STATUS_IS_OK(status)) {
594                 goto done;
595         }
596
597         status = dcerpc_binding_vector_add_unix(&ndr_table_mdssvc, v, "mdssvc");
598         if (!NT_STATUS_IS_OK(status)) {
599                 goto done;
600         }
601
602         ok = true;
603 done:
604         if (fd != -1) {
605                 close(fd);
606         }
607         talloc_free(tmp_ctx);
608         return ok;
609 }
610
611 void start_mdssd(struct tevent_context *ev_ctx,
612                  struct messaging_context *msg_ctx)
613 {
614         NTSTATUS status;
615         int listen_fd[MDSSD_MAX_SOCKETS];
616         int listen_fd_size = 0;
617         pid_t pid;
618         int rc;
619         bool ok;
620
621         DEBUG(1, ("Forking Metadata Service Daemon\n"));
622
623         /*
624          * Block signals before forking child as it will have to
625          * set its own handlers. Child will re-enable SIGHUP as
626          * soon as the handlers are set up.
627          */
628         BlockSignals(true, SIGTERM);
629         BlockSignals(true, SIGHUP);
630
631         pid = fork();
632         if (pid == -1) {
633                 DEBUG(0, ("Failed to fork mdssd [%s], aborting ...\n",
634                            strerror(errno)));
635                 exit(1);
636         }
637
638         /* parent or error */
639         if (pid != 0) {
640
641                 /* Re-enable SIGHUP before returnig */
642                 BlockSignals(false, SIGTERM);
643                 BlockSignals(false, SIGHUP);
644
645                 return;
646         }
647
648         status = smbd_reinit_after_fork(msg_ctx, ev_ctx, true, "mdssd-master");
649         if (!NT_STATUS_IS_OK(status)) {
650                 DEBUG(0,("reinit_after_fork() failed\n"));
651                 smb_panic("reinit_after_fork() failed");
652         }
653
654         reopen_logs();
655
656         /* save the parent process id so the children can use it later */
657         parent_id = messaging_server_id(msg_ctx);
658
659         pfh_daemon_config(DAEMON_NAME,
660                           &pf_mdssd_cfg,
661                           &default_pf_mdssd_cfg);
662
663         mdssd_setup_sig_term_handler(ev_ctx);
664         mdssd_setup_sig_hup_handler(ev_ctx);
665
666         BlockSignals(false, SIGTERM);
667         BlockSignals(false, SIGHUP);
668
669         ok = mdssd_create_sockets(ev_ctx, msg_ctx, listen_fd, &listen_fd_size);
670         if (!ok) {
671                 exit(1);
672         }
673
674         /* start children before any more initialization is done */
675         ok = prefork_create_pool(ev_ctx, /* mem_ctx */
676                                  ev_ctx,
677                                  msg_ctx,
678                                  listen_fd_size,
679                                  listen_fd,
680                                  pf_mdssd_cfg.min_children,
681                                  pf_mdssd_cfg.max_children,
682                                  &mdssd_children_main,
683                                  NULL,
684                                  &mdssd_pool);
685         if (!ok) {
686                 exit(1);
687         }
688
689         if (!serverid_register(messaging_server_id(msg_ctx),
690                                FLAG_MSG_GENERAL)) {
691                 exit(1);
692         }
693
694         messaging_register(msg_ctx,
695                            ev_ctx,
696                            MSG_SMB_CONF_UPDATED,
697                            mdssd_smb_conf_updated);
698         messaging_register(msg_ctx, ev_ctx,
699                            MSG_PREFORK_CHILD_EVENT, child_ping);
700
701         ok = setup_rpc_module(ev_ctx, msg_ctx, "mdssvc");
702         if (!ok) {
703                 exit(1);
704         }
705
706         ok = mdssd_setup_children_monitor(ev_ctx, msg_ctx);
707         if (!ok) {
708                 exit(1);
709         }
710
711         DEBUG(1, ("mdssd Daemon Started (%u)\n", (unsigned int)getpid()));
712
713         /* loop forever */
714         rc = tevent_loop_wait(ev_ctx);
715
716         /* should not be reached */
717         DEBUG(0,("mdssd: tevent_loop_wait() exited with %d - %s\n",
718                  rc, (rc == 0) ? "out of events" : strerror(errno)));
719         exit(1);
720 }