2 Unix SMB/Netbios implementation.
4 Copyright (C) Simo Sorce 2010
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "smbd/smbd.h"
24 #include "include/printing.h"
25 #include "printing/nt_printing_migrate_internal.h"
27 #include "librpc/gen_ndr/srv_winreg.h"
28 #include "librpc/gen_ndr/srv_spoolss.h"
29 #include "rpc_server/rpc_server.h"
30 #include "rpc_server/rpc_ep_register.h"
31 #include "rpc_server/spoolss/srv_spoolss_nt.h"
32 #include "librpc/rpc/dcerpc_ep.h"
33 #include "lib/server_prefork.h"
35 #define SPOOLSS_PIPE_NAME "spoolss"
36 #define DAEMON_NAME "spoolssd"
38 #define SPOOLSS_MIN_CHILDREN 5
39 #define SPOOLSS_MAX_CHILDREN 25
40 #define SPOOLSS_SPAWN_RATE 5
41 #define SPOOLSS_MIN_LIFE 60 /* 1 minute minimum life time */
43 void start_spoolssd(struct tevent_context
*ev_ctx
,
44 struct messaging_context
*msg_ctx
);
46 static void spoolss_reopen_logs(void)
48 char *lfile
= lp_logfile();
51 if (lfile
== NULL
|| lfile
[0] == '\0') {
52 rc
= asprintf(&lfile
, "%s/log.%s", get_dyn_LOGFILEBASE(), DAEMON_NAME
);
54 lp_set_logfile(lfile
);
58 if (strstr(lfile
, DAEMON_NAME
) == NULL
) {
59 rc
= asprintf(&lfile
, "%s.%s", lp_logfile(), DAEMON_NAME
);
61 lp_set_logfile(lfile
);
70 static void smb_conf_updated(struct messaging_context
*msg
,
73 struct server_id server_id
,
76 struct tevent_context
*ev_ctx
= talloc_get_type_abort(private_data
,
77 struct tevent_context
);
79 DEBUG(10, ("Got message saying smb.conf was updated. Reloading.\n"));
80 change_to_root_user();
81 reload_printers(ev_ctx
, msg
);
82 spoolss_reopen_logs();
85 static void spoolss_sig_term_handler(struct tevent_context
*ev
,
86 struct tevent_signal
*se
,
92 exit_server_cleanly("termination signal");
95 static void spoolss_setup_sig_term_handler(struct tevent_context
*ev_ctx
)
97 struct tevent_signal
*se
;
99 se
= tevent_add_signal(ev_ctx
,
102 spoolss_sig_term_handler
,
105 exit_server("failed to setup SIGTERM handler");
109 static void spoolss_sig_hup_handler(struct tevent_context
*ev
,
110 struct tevent_signal
*se
,
116 struct messaging_context
*msg_ctx
;
118 msg_ctx
= talloc_get_type_abort(pvt
, struct messaging_context
);
120 change_to_root_user();
121 DEBUG(1,("Reloading printers after SIGHUP\n"));
122 reload_printers(ev
, msg_ctx
);
123 spoolss_reopen_logs();
126 static void spoolss_setup_sig_hup_handler(struct tevent_context
*ev_ctx
,
127 struct messaging_context
*msg_ctx
)
129 struct tevent_signal
*se
;
131 se
= tevent_add_signal(ev_ctx
,
134 spoolss_sig_hup_handler
,
137 exit_server("failed to setup SIGHUP handler");
141 static bool spoolss_init_cb(void *ptr
)
143 struct messaging_context
*msg_ctx
= talloc_get_type_abort(
144 ptr
, struct messaging_context
);
146 return nt_printing_tdb_migrate(msg_ctx
);
149 static bool spoolss_shutdown_cb(void *ptr
)
151 srv_spoolss_cleanup();
158 struct spoolss_chld_sig_hup_ctx
{
159 struct messaging_context
*msg_ctx
;
160 struct pf_worker_data
*pf
;
163 static void spoolss_chld_sig_hup_handler(struct tevent_context
*ev
,
164 struct tevent_signal
*se
,
170 struct spoolss_chld_sig_hup_ctx
*shc
;
172 shc
= talloc_get_type_abort(pvt
, struct spoolss_chld_sig_hup_ctx
);
174 /* avoid wasting CPU cycles if we are going to exit soon anyways */
175 if (shc
->pf
!= NULL
&&
176 shc
->pf
->cmds
== PF_SRV_MSG_EXIT
) {
180 change_to_root_user();
181 DEBUG(1,("Reloading printers after SIGHUP\n"));
182 reload_printers(ev
, shc
->msg_ctx
);
183 spoolss_reopen_logs();
186 static bool spoolss_setup_chld_hup_handler(struct tevent_context
*ev_ctx
,
187 struct pf_worker_data
*pf
,
188 struct messaging_context
*msg_ctx
)
190 struct spoolss_chld_sig_hup_ctx
*shc
;
191 struct tevent_signal
*se
;
193 shc
= talloc(ev_ctx
, struct spoolss_chld_sig_hup_ctx
);
195 DEBUG(1, ("failed to setup SIGHUP handler"));
199 shc
->msg_ctx
= msg_ctx
;
201 se
= tevent_add_signal(ev_ctx
,
204 spoolss_chld_sig_hup_handler
,
207 DEBUG(1, ("failed to setup SIGHUP handler"));
214 static bool spoolss_child_init(struct tevent_context
*ev_ctx
,
215 struct pf_worker_data
*pf
)
218 struct rpc_srv_callbacks spoolss_cb
;
219 struct messaging_context
*msg_ctx
= server_messaging_context();
222 status
= reinit_after_fork(msg_ctx
, ev_ctx
,
223 procid_self(), true);
224 if (!NT_STATUS_IS_OK(status
)) {
225 DEBUG(0,("reinit_after_fork() failed\n"));
226 smb_panic("reinit_after_fork() failed");
229 spoolss_reopen_logs();
231 ok
= spoolss_setup_chld_hup_handler(ev_ctx
, pf
, msg_ctx
);
236 if (!serverid_register(procid_self(), FLAG_MSG_GENERAL
)) {
240 if (!locking_init()) {
244 messaging_register(msg_ctx
, ev_ctx
,
245 MSG_SMB_CONF_UPDATED
, smb_conf_updated
);
247 /* try to reinit rpc queues */
248 spoolss_cb
.init
= spoolss_init_cb
;
249 spoolss_cb
.shutdown
= spoolss_shutdown_cb
;
250 spoolss_cb
.private_data
= msg_ctx
;
252 status
= rpc_winreg_init(NULL
);
253 if (!NT_STATUS_IS_OK(status
)) {
254 DEBUG(0, ("Failed to register winreg rpc inteface! (%s)\n",
259 status
= rpc_spoolss_init(&spoolss_cb
);
260 if (!NT_STATUS_IS_OK(status
)) {
261 DEBUG(0, ("Failed to register spoolss rpc inteface! (%s)\n",
266 reload_printers(ev_ctx
, msg_ctx
);
271 struct spoolss_children_data
{
272 struct tevent_context
*ev_ctx
;
273 struct messaging_context
*msg_ctx
;
274 struct pf_worker_data
*pf
;
279 static void spoolss_schedule_loop(void *pvt
);
280 static void spoolss_children_loop(struct tevent_context
*ev_ctx
,
281 struct tevent_immediate
*im
,
284 static int spoolss_children_main(struct tevent_context
*ev_ctx
,
285 struct pf_worker_data
*pf
,
286 int listen_fd
, int lock_fd
,
289 struct messaging_context
*msg_ctx
= server_messaging_context();
290 struct spoolss_children_data
*data
;
294 ok
= spoolss_child_init(ev_ctx
, pf
);
299 data
= talloc(ev_ctx
, struct spoolss_children_data
);
304 data
->ev_ctx
= ev_ctx
;
305 data
->msg_ctx
= msg_ctx
;
306 data
->lock_fd
= lock_fd
;
307 data
->listen_fd
= listen_fd
;
309 spoolss_schedule_loop(data
);
311 /* loop until it is time to exit */
312 while (pf
->status
!= PF_WORKER_EXITING
) {
313 ret
= tevent_loop_once(ev_ctx
);
315 DEBUG(0, ("tevent_loop_once() exited with %d: %s\n",
316 ret
, strerror(errno
)));
317 pf
->status
= PF_WORKER_EXITING
;
324 static void spoolss_client_terminated(void *pvt
)
326 struct spoolss_children_data
*data
;
328 data
= talloc_get_type_abort(pvt
, struct spoolss_children_data
);
330 if (data
->pf
->num_clients
) {
331 data
->pf
->num_clients
--;
333 DEBUG(2, ("Invalid num clients, aborting!\n"));
334 data
->pf
->status
= PF_WORKER_EXITING
;
338 spoolss_schedule_loop(pvt
);
341 static void spoolss_schedule_loop(void *pvt
)
343 struct spoolss_children_data
*data
;
344 struct tevent_immediate
*im
;
346 data
= talloc_get_type_abort(pvt
, struct spoolss_children_data
);
348 if (data
->pf
->num_clients
== 0) {
349 data
->pf
->status
= PF_WORKER_IDLE
;
352 if (data
->pf
->cmds
== PF_SRV_MSG_EXIT
) {
353 DEBUG(2, ("Parent process commands we terminate!\n"));
357 im
= tevent_create_immediate(data
);
359 DEBUG(1, ("Failed to create immediate event!\n"));
363 tevent_schedule_immediate(im
, data
->ev_ctx
,
364 spoolss_children_loop
, data
);
367 static void spoolss_children_loop(struct tevent_context
*ev_ctx
,
368 struct tevent_immediate
*im
,
371 struct spoolss_children_data
*data
;
372 struct sockaddr_un sunaddr
;
373 socklen_t addrlen
= sizeof(sunaddr
);
377 data
= talloc_get_type_abort(pvt
, struct spoolss_children_data
);
380 /* FIXME: this call is blocking. */
381 ret
= prefork_wait_for_client(data
->pf
, data
->lock_fd
, data
->listen_fd
,
382 (struct sockaddr
*)(void *)&sunaddr
,
385 DEBUG(1, ("Failed to accept connection!\n"));
390 DEBUG(1, ("Server asks us to die!\n"));
391 data
->pf
->status
= PF_WORKER_EXITING
;
395 DEBUG(2, ("Spoolss preforked child %d activated!\n",
396 (int)(data
->pf
->pid
)));
398 named_pipe_accept_function(data
->ev_ctx
, data
->msg_ctx
,
399 SPOOLSS_PIPE_NAME
, sd
,
400 spoolss_client_terminated
, data
);
403 /* ==== Main Process Functions ==== */
405 static void spoolssd_sig_chld_handler(struct tevent_context
*ev_ctx
,
406 struct tevent_signal
*se
,
407 int signum
, int count
,
408 void *siginfo
, void *pvt
)
410 struct prefork_pool
*pfp
;
417 pfp
= talloc_get_type_abort(pvt
, struct prefork_pool
);
419 while ((pid
= sys_waitpid(-1, &status
, WNOHANG
)) > 0) {
420 ok
= prefork_mark_pid_dead(pfp
, pid
);
422 DEBUG(1, ("Pid %d was not found in children pool!\n",
427 /* now check we do not descent below the minimum */
428 active
= prefork_count_active_children(pfp
, &total
);
431 if (total
< SPOOLSS_MIN_CHILDREN
) {
432 n
= total
- SPOOLSS_MIN_CHILDREN
;
433 } else if (total
- active
< (total
/ 4)) {
434 n
= SPOOLSS_MIN_CHILDREN
;
438 r
= prefork_add_children(ev_ctx
, pfp
, n
);
440 DEBUG(10, ("Tried to start %d children but only,"
441 "%d were actually started.!\n", n
, r
));
448 static bool spoolssd_setup_sig_chld_handler(struct tevent_context
*ev_ctx
,
449 struct prefork_pool
*pfp
)
451 struct tevent_signal
*se
;
453 se
= tevent_add_signal(ev_ctx
, ev_ctx
, SIGCHLD
, 0,
454 spoolssd_sig_chld_handler
, pfp
);
456 DEBUG(0, ("Failed to setup SIGCHLD handler!\n"));
463 static bool spoolssd_schedule_check(struct tevent_context
*ev_ctx
,
464 struct prefork_pool
*pfp
,
465 struct timeval current_time
);
466 static void spoolssd_check_children(struct tevent_context
*ev_ctx
,
467 struct tevent_timer
*te
,
468 struct timeval current_time
,
471 static bool spoolssd_setup_children_monitor(struct tevent_context
*ev_ctx
,
472 struct prefork_pool
*pfp
)
476 ok
= spoolssd_setup_sig_chld_handler(ev_ctx
, pfp
);
481 ok
= spoolssd_schedule_check(ev_ctx
, pfp
, tevent_timeval_current());
485 static bool spoolssd_schedule_check(struct tevent_context
*ev_ctx
,
486 struct prefork_pool
*pfp
,
487 struct timeval current_time
)
489 struct tevent_timer
*te
;
490 struct timeval next_event
;
492 /* check situation again in 10 seconds */
493 next_event
= tevent_timeval_current_ofs(10, 0);
495 /* check when the socket becomes readable, so that children
496 * are checked only when there is some activity */
497 te
= tevent_add_timer(ev_ctx
, pfp
, next_event
,
498 spoolssd_check_children
, pfp
);
500 DEBUG(2, ("Failed to set up children monitoring!\n"));
507 static void spoolssd_check_children(struct tevent_context
*ev_ctx
,
508 struct tevent_timer
*te
,
509 struct timeval current_time
,
512 struct prefork_pool
*pfp
;
516 pfp
= talloc_get_type_abort(pvt
, struct prefork_pool
);
518 active
= prefork_count_active_children(pfp
, &total
);
520 if (total
- active
< SPOOLSS_SPAWN_RATE
) {
521 n
= prefork_add_children(ev_ctx
, pfp
, SPOOLSS_SPAWN_RATE
);
522 if (n
< SPOOLSS_SPAWN_RATE
) {
523 DEBUG(10, ("Tried to start 5 children but only,"
524 "%d were actually started.!\n", n
));
528 if (total
- active
> SPOOLSS_MIN_CHILDREN
) {
529 if ((total
- SPOOLSS_MIN_CHILDREN
) >= SPOOLSS_SPAWN_RATE
) {
530 prefork_retire_children(pfp
, SPOOLSS_SPAWN_RATE
,
531 time(NULL
) - SPOOLSS_MIN_LIFE
);
535 ret
= spoolssd_schedule_check(ev_ctx
, pfp
, current_time
);
538 void start_spoolssd(struct tevent_context
*ev_ctx
,
539 struct messaging_context
*msg_ctx
)
541 struct prefork_pool
*pool
;
542 struct rpc_srv_callbacks spoolss_cb
;
543 struct dcerpc_binding_vector
*v
;
551 DEBUG(1, ("Forking SPOOLSS Daemon\n"));
556 DEBUG(0, ("Failed to fork SPOOLSS [%s], aborting ...\n",
567 close_low_fds(false);
569 status
= reinit_after_fork(msg_ctx
,
571 procid_self(), true);
572 if (!NT_STATUS_IS_OK(status
)) {
573 DEBUG(0,("reinit_after_fork() failed\n"));
574 smb_panic("reinit_after_fork() failed");
577 spoolss_reopen_logs();
579 /* the listening fd must be created before the children are actually
581 listen_fd
= create_named_pipe_socket(SPOOLSS_PIPE_NAME
);
582 if (listen_fd
== -1) {
586 ret
= listen(listen_fd
, SPOOLSS_MAX_CHILDREN
);
588 DEBUG(0, ("Failed to listen on spoolss pipe - %s\n",
594 /* start children before any more initialization is done */
595 ok
= prefork_create_pool(ev_ctx
, ev_ctx
, listen_fd
,
596 SPOOLSS_MIN_CHILDREN
,
597 SPOOLSS_MAX_CHILDREN
,
598 &spoolss_children_main
, NULL
,
601 spoolss_setup_sig_term_handler(ev_ctx
);
602 spoolss_setup_sig_hup_handler(ev_ctx
, msg_ctx
);
604 if (!serverid_register(procid_self(),
605 FLAG_MSG_GENERAL
|FLAG_MSG_SMBD
606 |FLAG_MSG_PRINT_GENERAL
)) {
610 if (!locking_init()) {
614 messaging_register(msg_ctx
, NULL
,
615 MSG_PRINTER_UPDATE
, print_queue_receive
);
616 messaging_register(msg_ctx
, ev_ctx
,
617 MSG_SMB_CONF_UPDATED
, smb_conf_updated
);
619 mem_ctx
= talloc_new(NULL
);
620 if (mem_ctx
== NULL
) {
625 * Initialize spoolss with an init function to convert printers first.
626 * static_init_rpc will try to initialize the spoolss server too but you
627 * can't register it twice.
629 spoolss_cb
.init
= spoolss_init_cb
;
630 spoolss_cb
.shutdown
= spoolss_shutdown_cb
;
631 spoolss_cb
.private_data
= msg_ctx
;
633 status
= rpc_winreg_init(NULL
);
634 if (!NT_STATUS_IS_OK(status
)) {
635 DEBUG(0, ("Failed to register winreg rpc inteface! (%s)\n",
640 status
= rpc_spoolss_init(&spoolss_cb
);
641 if (!NT_STATUS_IS_OK(status
)) {
642 DEBUG(0, ("Failed to register spoolss rpc inteface! (%s)\n",
647 status
= dcerpc_binding_vector_new(mem_ctx
, &v
);
648 if (!NT_STATUS_IS_OK(status
)) {
649 DEBUG(0, ("Failed to create binding vector (%s)\n",
654 status
= dcerpc_binding_vector_add_np_default(&ndr_table_spoolss
, v
);
655 if (!NT_STATUS_IS_OK(status
)) {
656 DEBUG(0, ("Failed to add np to binding vector (%s)\n",
661 status
= rpc_ep_register(ev_ctx
, msg_ctx
, &ndr_table_spoolss
, v
);
662 if (!NT_STATUS_IS_OK(status
)) {
663 DEBUG(0, ("Failed to register spoolss endpoint! (%s)\n",
668 talloc_free(mem_ctx
);
670 ok
= spoolssd_setup_children_monitor(ev_ctx
, pool
);
672 DEBUG(0, ("Failed to setup children monitoring!\n"));
676 reload_printers(ev_ctx
, msg_ctx
);
678 DEBUG(1, ("SPOOLSS Daemon Started (%d)\n", getpid()));
681 ret
= tevent_loop_wait(ev_ctx
);
683 /* should not be reached */
684 DEBUG(0,("background_queue: tevent_loop_wait() exited with %d - %s\n",
685 ret
, (ret
== 0) ? "out of events" : strerror(errno
)));