2010-05-20 16:48:18 +04:00
/*
Unix SMB / Netbios implementation .
SPOOLSS Daemon
2011-08-12 23:25:48 +04:00
Copyright ( C ) Simo Sorce < idra @ samba . org > 2010 - 2011
2010-05-20 16:48:18 +04:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
2011-03-24 12:22:57 +03:00
# include "serverid.h"
2011-03-23 01:49:17 +03:00
# include "smbd/smbd.h"
2011-03-24 12:22:57 +03:00
2011-03-24 17:31:06 +03:00
# include "messages.h"
2010-05-20 16:48:18 +04:00
# include "include/printing.h"
2011-07-01 16:57:32 +04:00
# include "printing/nt_printing_migrate_internal.h"
2011-05-18 19:24:30 +04:00
# include "printing/queue_process.h"
2011-08-04 01:04:50 +04:00
# include "printing/pcap.h"
2011-08-10 17:20:24 +04:00
# include "printing/load.h"
2011-05-02 15:21:53 +04:00
# include "ntdomain.h"
2010-06-16 02:39:27 +04:00
# include "librpc/gen_ndr/srv_winreg.h"
# include "librpc/gen_ndr/srv_spoolss.h"
2010-05-20 16:48:18 +04:00
# include "rpc_server/rpc_server.h"
2011-06-06 13:10:02 +04:00
# include "rpc_server/rpc_ep_register.h"
2014-02-27 12:58:27 +04:00
# include "rpc_server/rpc_config.h"
2011-04-30 01:47:25 +04:00
# include "rpc_server/spoolss/srv_spoolss_nt.h"
2011-07-01 20:40:38 +04:00
# include "librpc/rpc/dcerpc_ep.h"
2011-04-21 23:06:18 +04:00
# include "lib/server_prefork.h"
2011-08-12 23:25:48 +04:00
# include "lib/server_prefork_util.h"
2010-05-20 16:48:18 +04:00
# define SPOOLSS_PIPE_NAME "spoolss"
2010-08-25 12:15:47 +04:00
# define DAEMON_NAME "spoolssd"
2010-06-16 02:38:44 +04:00
2011-08-17 00:36:43 +04:00
static struct server_id parent_id ;
2011-08-12 23:25:48 +04:00
static struct prefork_pool * spoolss_pool = NULL ;
2011-08-10 00:44:52 +04:00
static int spoolss_child_id = 0 ;
2011-05-09 12:38:06 +04:00
2011-08-12 23:25:48 +04:00
static struct pf_daemon_config default_pf_spoolss_cfg = {
. prefork_status = PFH_INIT ,
. min_children = 5 ,
. max_children = 25 ,
. spawn_rate = 5 ,
. max_allowed_clients = 100 ,
. child_min_life = 60 /* 1 minute minimum life time */
} ;
static struct pf_daemon_config pf_spoolss_cfg = { 0 } ;
2011-08-10 14:48:30 +04:00
pid_t start_spoolssd ( struct tevent_context * ev_ctx ,
struct messaging_context * msg_ctx ) ;
2011-05-09 12:38:06 +04:00
2011-08-05 18:08:23 +04:00
static void spoolss_reopen_logs ( int child_id )
2010-06-16 02:38:44 +04:00
{
2012-07-18 09:37:23 +04:00
char * lfile = lp_logfile ( talloc_tos ( ) ) ;
2011-08-05 23:14:26 +04:00
char * ext ;
2010-08-25 12:15:47 +04:00
int rc ;
2010-06-16 02:38:44 +04:00
2011-08-05 18:08:23 +04:00
if ( child_id ) {
2011-08-11 22:23:19 +04:00
rc = asprintf ( & ext , " %s.%d " , DAEMON_NAME , child_id ) ;
2011-08-05 18:08:23 +04:00
} else {
2011-08-11 22:23:19 +04:00
rc = asprintf ( & ext , " %s " , DAEMON_NAME ) ;
2011-08-05 18:08:23 +04:00
}
if ( rc = = - 1 ) {
2011-08-11 22:23:19 +04:00
return ;
2011-08-05 18:08:23 +04:00
}
2011-08-05 23:14:26 +04:00
rc = 0 ;
2011-03-28 16:30:29 +04:00
if ( lfile = = NULL | | lfile [ 0 ] = = ' \0 ' ) {
2011-08-11 22:23:19 +04:00
rc = asprintf ( & lfile , " %s/log.%s " ,
get_dyn_LOGFILEBASE ( ) , ext ) ;
2011-03-28 16:30:29 +04:00
} else {
2011-08-11 22:23:19 +04:00
if ( strstr ( lfile , ext ) = = NULL ) {
if ( child_id ) {
2011-08-05 23:14:26 +04:00
rc = asprintf ( & lfile , " %s.%d " ,
2012-07-18 09:37:23 +04:00
lp_logfile ( talloc_tos ( ) ) ,
child_id ) ;
2011-08-11 22:23:19 +04:00
} else {
rc = asprintf ( & lfile , " %s.%s " ,
2012-07-18 09:37:23 +04:00
lp_logfile ( talloc_tos ( ) ) ,
ext ) ;
2011-03-28 16:30:29 +04:00
}
2011-08-05 18:08:23 +04:00
}
2011-08-05 23:14:26 +04:00
}
2011-08-05 18:08:23 +04:00
2011-08-05 23:14:26 +04:00
if ( rc > 0 ) {
lp_set_logfile ( lfile ) ;
SAFE_FREE ( lfile ) ;
2010-06-16 02:38:44 +04:00
}
2011-03-28 16:30:29 +04:00
2011-08-05 23:14:26 +04:00
SAFE_FREE ( ext ) ;
2011-08-05 18:08:23 +04:00
2010-06-16 02:38:44 +04:00
reopen_logs ( ) ;
}
2011-05-09 16:50:11 +04:00
static void update_conf ( struct tevent_context * ev ,
struct messaging_context * msg )
{
change_to_root_user ( ) ;
2014-07-30 18:41:22 +04:00
lp_load_global ( get_dyn_CONFIGFILE ( ) ) ;
2011-09-01 16:25:07 +04:00
load_printers ( ev , msg ) ;
2011-05-09 16:50:11 +04:00
2011-08-10 00:44:52 +04:00
spoolss_reopen_logs ( spoolss_child_id ) ;
if ( spoolss_child_id = = 0 ) {
2011-08-12 23:25:48 +04:00
pfh_daemon_config ( DAEMON_NAME ,
& pf_spoolss_cfg ,
& default_pf_spoolss_cfg ) ;
pfh_manage_pool ( ev , msg , & pf_spoolss_cfg , spoolss_pool ) ;
2011-08-10 00:44:52 +04:00
}
2011-05-09 16:50:11 +04:00
}
2010-06-16 23:36:06 +04:00
static void smb_conf_updated ( struct messaging_context * msg ,
void * private_data ,
uint32_t msg_type ,
struct server_id server_id ,
DATA_BLOB * data )
{
2011-01-20 20:59:40 +03:00
struct tevent_context * ev_ctx = talloc_get_type_abort ( private_data ,
struct tevent_context ) ;
2010-06-16 23:36:06 +04:00
DEBUG ( 10 , ( " Got message saying smb.conf was updated. Reloading. \n " ) ) ;
2011-05-09 16:50:11 +04:00
update_conf ( ev_ctx , msg ) ;
2010-06-16 23:36:06 +04:00
}
2010-06-16 21:03:32 +04:00
static void spoolss_sig_term_handler ( struct tevent_context * ev ,
struct tevent_signal * se ,
int signum ,
int count ,
void * siginfo ,
void * private_data )
{
exit_server_cleanly ( " termination signal " ) ;
}
2011-01-20 20:59:40 +03:00
static void spoolss_setup_sig_term_handler ( struct tevent_context * ev_ctx )
2010-06-16 21:03:32 +04:00
{
struct tevent_signal * se ;
2011-01-20 20:59:40 +03:00
se = tevent_add_signal ( ev_ctx ,
ev_ctx ,
2010-06-16 21:03:32 +04:00
SIGTERM , 0 ,
spoolss_sig_term_handler ,
NULL ) ;
if ( ! se ) {
exit_server ( " failed to setup SIGTERM handler " ) ;
}
}
static void spoolss_sig_hup_handler ( struct tevent_context * ev ,
struct tevent_signal * se ,
int signum ,
int count ,
void * siginfo ,
2011-04-21 23:06:18 +04:00
void * pvt )
2010-06-16 21:03:32 +04:00
{
2011-08-08 22:15:14 +04:00
struct messaging_context * msg_ctx ;
2011-04-21 23:06:18 +04:00
2011-08-08 22:15:14 +04:00
msg_ctx = talloc_get_type_abort ( pvt , struct messaging_context ) ;
2011-01-20 20:59:40 +03:00
2010-06-16 21:03:32 +04:00
DEBUG ( 1 , ( " Reloading printers after SIGHUP \n " ) ) ;
2011-08-08 22:15:14 +04:00
update_conf ( ev , msg_ctx ) ;
2011-05-09 16:50:11 +04:00
/* relay to all children */
2011-08-08 22:15:14 +04:00
if ( spoolss_pool ) {
prefork_send_signal_to_all ( spoolss_pool , SIGHUP ) ;
}
2010-06-16 21:03:32 +04:00
}
2011-01-20 20:59:40 +03:00
static void spoolss_setup_sig_hup_handler ( struct tevent_context * ev_ctx ,
struct messaging_context * msg_ctx )
2010-06-16 21:03:32 +04:00
{
struct tevent_signal * se ;
2011-01-20 20:59:40 +03:00
se = tevent_add_signal ( ev_ctx ,
ev_ctx ,
2010-06-16 21:03:32 +04:00
SIGHUP , 0 ,
spoolss_sig_hup_handler ,
2011-08-08 22:15:14 +04:00
msg_ctx ) ;
2010-06-16 21:03:32 +04:00
if ( ! se ) {
exit_server ( " failed to setup SIGHUP handler " ) ;
}
}
2010-06-16 02:39:27 +04:00
static bool spoolss_init_cb ( void * ptr )
{
2011-01-20 20:59:40 +03:00
struct messaging_context * msg_ctx = talloc_get_type_abort (
ptr , struct messaging_context ) ;
return nt_printing_tdb_migrate ( msg_ctx ) ;
}
static bool spoolss_shutdown_cb ( void * ptr )
{
srv_spoolss_cleanup ( ) ;
return true ;
2010-06-16 02:39:27 +04:00
}
2011-05-20 07:56:02 +04:00
/* Children */
2011-04-21 23:06:18 +04:00
static void spoolss_chld_sig_hup_handler ( struct tevent_context * ev ,
struct tevent_signal * se ,
int signum ,
int count ,
void * siginfo ,
void * pvt )
{
2011-08-18 18:39:13 +04:00
struct messaging_context * msg_ctx ;
2011-04-21 23:06:18 +04:00
2011-08-18 18:39:13 +04:00
msg_ctx = talloc_get_type_abort ( pvt , struct messaging_context ) ;
2011-04-21 23:06:18 +04:00
change_to_root_user ( ) ;
DEBUG ( 1 , ( " Reloading printers after SIGHUP \n " ) ) ;
2011-09-01 16:25:07 +04:00
load_printers ( ev , msg_ctx ) ;
2011-08-10 00:44:52 +04:00
spoolss_reopen_logs ( spoolss_child_id ) ;
2011-04-21 23:06:18 +04:00
}
static bool spoolss_setup_chld_hup_handler ( struct tevent_context * ev_ctx ,
2011-08-05 18:08:23 +04:00
struct messaging_context * msg_ctx ,
2011-08-10 00:44:52 +04:00
struct pf_worker_data * pf )
2011-04-21 23:06:18 +04:00
{
struct tevent_signal * se ;
se = tevent_add_signal ( ev_ctx ,
ev_ctx ,
SIGHUP , 0 ,
spoolss_chld_sig_hup_handler ,
2011-08-18 18:39:13 +04:00
msg_ctx ) ;
2011-04-21 23:06:18 +04:00
if ( ! se ) {
DEBUG ( 1 , ( " failed to setup SIGHUP handler " ) ) ;
return false ;
}
return true ;
}
2011-08-18 00:17:10 +04:00
static void parent_ping ( struct messaging_context * msg_ctx ,
void * private_data ,
uint32_t msg_type ,
struct server_id server_id ,
DATA_BLOB * data )
{
/* The fact we received this message is enough to let make the event
* loop if it was idle . spoolss_children_main will cycle through
* spoolss_next_client at least once . That function will take whatever
* action is necessary */
DEBUG ( 10 , ( " Got message that the parent changed status. \n " ) ) ;
return ;
}
2011-04-21 23:06:18 +04:00
static bool spoolss_child_init ( struct tevent_context * ev_ctx ,
2011-08-05 18:08:23 +04:00
int child_id , struct pf_worker_data * pf )
2011-04-21 23:06:18 +04:00
{
NTSTATUS status ;
struct rpc_srv_callbacks spoolss_cb ;
2014-02-18 23:51:43 +04:00
struct messaging_context * msg_ctx = server_messaging_context ( ) ;
2011-04-21 23:06:18 +04:00
bool ok ;
2015-09-23 21:14:05 +03:00
status = reinit_after_fork ( msg_ctx , ev_ctx , true , " spoolssd-child " ) ;
2011-04-21 23:06:18 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " reinit_after_fork() failed \n " ) ) ;
smb_panic ( " reinit_after_fork() failed " ) ;
}
2011-08-10 00:44:52 +04:00
spoolss_child_id = child_id ;
2011-08-05 18:08:23 +04:00
spoolss_reopen_logs ( child_id ) ;
2011-04-21 23:06:18 +04:00
2011-08-10 00:44:52 +04:00
ok = spoolss_setup_chld_hup_handler ( ev_ctx , msg_ctx , pf ) ;
2011-04-21 23:06:18 +04:00
if ( ! ok ) {
return false ;
}
2012-10-19 09:15:31 +04:00
if ( ! serverid_register ( messaging_server_id ( msg_ctx ) ,
2011-08-10 00:46:21 +04:00
FLAG_MSG_GENERAL |
FLAG_MSG_PRINT_GENERAL ) ) {
2011-04-21 23:06:18 +04:00
return false ;
}
if ( ! locking_init ( ) ) {
return false ;
}
messaging_register ( msg_ctx , ev_ctx ,
MSG_SMB_CONF_UPDATED , smb_conf_updated ) ;
2011-08-18 00:17:10 +04:00
messaging_register ( msg_ctx , ev_ctx ,
MSG_PREFORK_PARENT_EVENT , parent_ping ) ;
2011-04-21 23:06:18 +04:00
2011-08-10 17:20:24 +04:00
/* As soon as messaging is up check if pcap has been loaded already.
* If so then we probably missed a message and should load_printers ( )
* ourselves . If pcap has not been loaded yet , then ignore , we will get
* a message as soon as the bq process completes the reload . */
2014-07-23 14:12:34 +04:00
if ( pcap_cache_loaded ( NULL ) ) {
2011-08-10 17:20:24 +04:00
load_printers ( ev_ctx , msg_ctx ) ;
}
2011-04-21 23:06:18 +04:00
/* try to reinit rpc queues */
spoolss_cb . init = spoolss_init_cb ;
spoolss_cb . shutdown = spoolss_shutdown_cb ;
spoolss_cb . private_data = msg_ctx ;
status = rpc_winreg_init ( NULL ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2015-06-03 14:33:00 +03:00
DEBUG ( 0 , ( " Failed to register winreg rpc interface! (%s) \n " ,
2011-04-21 23:06:18 +04:00
nt_errstr ( status ) ) ) ;
return false ;
}
status = rpc_spoolss_init ( & spoolss_cb ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2015-06-03 14:33:00 +03:00
DEBUG ( 0 , ( " Failed to register spoolss rpc interface! (%s) \n " ,
2011-04-21 23:06:18 +04:00
nt_errstr ( status ) ) ) ;
return false ;
}
return true ;
}
struct spoolss_children_data {
struct tevent_context * ev_ctx ;
struct messaging_context * msg_ctx ;
struct pf_worker_data * pf ;
2011-05-10 16:39:14 +04:00
int listen_fd_size ;
int * listen_fds ;
2011-04-21 23:06:18 +04:00
} ;
2011-05-06 01:59:00 +04:00
static void spoolss_next_client ( void * pvt ) ;
2011-04-21 23:06:18 +04:00
static int spoolss_children_main ( struct tevent_context * ev_ctx ,
2011-07-18 18:39:50 +04:00
struct messaging_context * msg_ctx ,
2011-04-21 23:06:18 +04:00
struct pf_worker_data * pf ,
2011-08-05 18:34:05 +04:00
int child_id ,
2011-05-10 16:39:14 +04:00
int listen_fd_size ,
int * listen_fds ,
2011-04-21 23:06:18 +04:00
void * private_data )
{
struct spoolss_children_data * data ;
bool ok ;
2013-12-10 20:49:18 +04:00
int ret = 0 ;
2011-04-21 23:06:18 +04:00
2011-08-05 18:08:23 +04:00
ok = spoolss_child_init ( ev_ctx , child_id , pf ) ;
2011-04-21 23:06:18 +04:00
if ( ! ok ) {
return 1 ;
}
data = talloc ( ev_ctx , struct spoolss_children_data ) ;
if ( ! data ) {
return 1 ;
}
data - > pf = pf ;
data - > ev_ctx = ev_ctx ;
data - > msg_ctx = msg_ctx ;
2011-05-10 16:39:14 +04:00
data - > listen_fd_size = listen_fd_size ;
data - > listen_fds = listen_fds ;
2011-04-21 23:06:18 +04:00
/* loop until it is time to exit */
while ( pf - > status ! = PF_WORKER_EXITING ) {
2011-05-06 01:59:00 +04:00
/* try to see if it is time to schedule the next client */
spoolss_next_client ( data ) ;
2011-04-21 23:06:18 +04:00
ret = tevent_loop_once ( ev_ctx ) ;
if ( ret ! = 0 ) {
DEBUG ( 0 , ( " tevent_loop_once() exited with %d: %s \n " ,
ret , strerror ( errno ) ) ) ;
pf - > status = PF_WORKER_EXITING ;
}
}
return ret ;
}
static void spoolss_client_terminated ( void * pvt )
{
struct spoolss_children_data * data ;
data = talloc_get_type_abort ( pvt , struct spoolss_children_data ) ;
2011-08-16 19:38:03 +04:00
pfh_client_terminated ( data - > pf ) ;
2011-04-21 23:06:18 +04:00
2011-05-06 01:59:00 +04:00
spoolss_next_client ( pvt ) ;
2011-04-21 23:06:18 +04:00
}
2011-05-06 01:59:00 +04:00
struct spoolss_new_client {
struct spoolss_children_data * data ;
2011-07-19 23:07:42 +04:00
struct tsocket_address * srv_addr ;
struct tsocket_address * cli_addr ;
2011-05-06 01:59:00 +04:00
} ;
static void spoolss_handle_client ( struct tevent_req * req ) ;
static void spoolss_next_client ( void * pvt )
2011-04-21 23:06:18 +04:00
{
2011-05-06 01:59:00 +04:00
struct tevent_req * req ;
2011-04-21 23:06:18 +04:00
struct spoolss_children_data * data ;
2011-05-06 01:59:00 +04:00
struct spoolss_new_client * next ;
2011-04-21 23:06:18 +04:00
data = talloc_get_type_abort ( pvt , struct spoolss_children_data ) ;
2011-08-16 19:38:03 +04:00
if ( ! pfh_child_allowed_to_accept ( data - > pf ) ) {
2011-05-06 01:59:00 +04:00
/* nothing to do for now we are already listening
2011-08-16 19:38:03 +04:00
* or we are not allowed to listen further */
2011-04-21 23:06:18 +04:00
return ;
}
2011-05-06 01:59:00 +04:00
next = talloc_zero ( data , struct spoolss_new_client ) ;
if ( ! next ) {
DEBUG ( 1 , ( " Out of memory!? \n " ) ) ;
return ;
}
next - > data = data ;
req = prefork_listen_send ( next , data - > ev_ctx , data - > pf ,
2011-05-10 16:39:14 +04:00
data - > listen_fd_size ,
2011-08-16 17:30:28 +04:00
data - > listen_fds ) ;
2011-05-06 01:59:00 +04:00
if ( ! req ) {
DEBUG ( 1 , ( " Failed to make listening request!? \n " ) ) ;
talloc_free ( next ) ;
return ;
}
tevent_req_set_callback ( req , spoolss_handle_client , next ) ;
2011-04-21 23:06:18 +04:00
}
2011-05-06 01:59:00 +04:00
static void spoolss_handle_client ( struct tevent_req * req )
2011-04-21 23:06:18 +04:00
{
struct spoolss_children_data * data ;
2011-05-06 01:59:00 +04:00
struct spoolss_new_client * client ;
2011-08-17 00:36:43 +04:00
const DATA_BLOB ping = data_blob_null ;
2011-04-21 23:06:18 +04:00
int ret ;
int sd ;
2011-05-06 01:59:00 +04:00
client = tevent_req_callback_data ( req , struct spoolss_new_client ) ;
data = client - > data ;
2011-04-21 23:06:18 +04:00
2011-07-19 23:07:42 +04:00
ret = prefork_listen_recv ( req , client , & sd ,
& client - > srv_addr , & client - > cli_addr ) ;
2011-05-06 01:59:00 +04:00
/* this will free the request too */
talloc_free ( client ) ;
2011-04-21 23:06:18 +04:00
2011-08-16 17:30:28 +04:00
if ( ret ! = 0 ) {
DEBUG ( 6 , ( " No client connection was available after all! \n " ) ) ;
2011-04-21 23:06:18 +04:00
return ;
}
2011-08-17 00:36:43 +04:00
/* Warn parent that our status changed */
messaging_send ( data - > msg_ctx , parent_id ,
MSG_PREFORK_CHILD_EVENT , & ping ) ;
2011-05-06 01:59:00 +04:00
DEBUG ( 2 , ( " Spoolss preforked child %d got client connection! \n " ,
2011-04-21 23:06:18 +04:00
( int ) ( data - > pf - > pid ) ) ) ;
named_pipe_accept_function ( data - > ev_ctx , data - > msg_ctx ,
SPOOLSS_PIPE_NAME , sd ,
spoolss_client_terminated , data ) ;
}
/* ==== Main Process Functions ==== */
2011-05-18 19:24:30 +04:00
extern pid_t background_lpq_updater_pid ;
2011-08-05 23:14:26 +04:00
static char * bq_logfile ;
2011-05-18 19:24:30 +04:00
2011-12-14 14:12:49 +04:00
static void check_updater_child ( struct tevent_context * ev_ctx ,
struct messaging_context * msg_ctx )
2011-05-18 19:24:30 +04:00
{
int status ;
pid_t pid ;
if ( background_lpq_updater_pid = = - 1 ) {
return ;
}
pid = sys_waitpid ( background_lpq_updater_pid , & status , WNOHANG ) ;
if ( pid > 0 ) {
DEBUG ( 2 , ( " The background queue child died... Restarting! \n " ) ) ;
2011-12-14 14:12:49 +04:00
pid = start_background_queue ( ev_ctx , msg_ctx , bq_logfile ) ;
2011-05-18 19:24:30 +04:00
background_lpq_updater_pid = pid ;
}
}
2011-08-17 00:36:43 +04:00
static void child_ping ( struct messaging_context * msg_ctx ,
void * private_data ,
uint32_t msg_type ,
struct server_id server_id ,
DATA_BLOB * data )
{
struct tevent_context * ev_ctx ;
ev_ctx = talloc_get_type_abort ( private_data , struct tevent_context ) ;
DEBUG ( 10 , ( " Got message that a child changed status. \n " ) ) ;
pfh_manage_pool ( ev_ctx , msg_ctx , & pf_spoolss_cfg , spoolss_pool ) ;
}
2011-05-20 07:56:02 +04:00
static bool spoolssd_schedule_check ( struct tevent_context * ev_ctx ,
2011-07-18 18:39:50 +04:00
struct messaging_context * msg_ctx ,
2011-05-20 07:56:02 +04:00
struct timeval current_time ) ;
static void spoolssd_check_children ( struct tevent_context * ev_ctx ,
struct tevent_timer * te ,
struct timeval current_time ,
void * pvt ) ;
static void spoolssd_sigchld_handler ( struct tevent_context * ev_ctx ,
struct prefork_pool * pfp ,
2011-07-18 18:39:50 +04:00
void * pvt )
2011-04-21 23:06:18 +04:00
{
2011-07-18 18:39:50 +04:00
struct messaging_context * msg_ctx ;
2011-04-21 23:06:18 +04:00
2011-07-18 18:39:50 +04:00
msg_ctx = talloc_get_type_abort ( pvt , struct messaging_context ) ;
2011-08-12 20:24:48 +04:00
/* run pool management so we can fork/retire or increase
* the allowed connections per child based on load */
2011-08-12 23:25:48 +04:00
pfh_manage_pool ( ev_ctx , msg_ctx , & pf_spoolss_cfg , spoolss_pool ) ;
2011-04-21 23:06:18 +04:00
2011-05-18 19:24:30 +04:00
/* also check if the updater child is alive and well */
2011-12-14 14:12:49 +04:00
check_updater_child ( ev_ctx , msg_ctx ) ;
2011-04-21 23:06:18 +04:00
}
static bool spoolssd_setup_children_monitor ( struct tevent_context * ev_ctx ,
2011-08-08 22:15:14 +04:00
struct messaging_context * msg_ctx )
2011-04-21 23:06:18 +04:00
{
bool ok ;
2011-05-20 07:56:02 +04:00
/* add our oun sigchld callback */
2011-08-08 22:15:14 +04:00
prefork_set_sigchld_callback ( spoolss_pool ,
spoolssd_sigchld_handler , msg_ctx ) ;
2011-04-21 23:06:18 +04:00
2011-08-08 22:15:14 +04:00
ok = spoolssd_schedule_check ( ev_ctx , msg_ctx ,
2011-07-18 18:39:50 +04:00
tevent_timeval_current ( ) ) ;
2011-04-21 23:06:18 +04:00
return ok ;
}
static bool spoolssd_schedule_check ( struct tevent_context * ev_ctx ,
2011-07-18 18:39:50 +04:00
struct messaging_context * msg_ctx ,
2011-04-21 23:06:18 +04:00
struct timeval current_time )
{
struct tevent_timer * te ;
struct timeval next_event ;
/* check situation again in 10 seconds */
next_event = tevent_timeval_current_ofs ( 10 , 0 ) ;
2011-05-18 19:24:30 +04:00
/* TODO: check when the socket becomes readable, so that children
* are checked only when there is some activity ? */
2011-08-08 22:15:14 +04:00
te = tevent_add_timer ( ev_ctx , spoolss_pool , next_event ,
spoolssd_check_children , msg_ctx ) ;
2011-04-21 23:06:18 +04:00
if ( ! te ) {
DEBUG ( 2 , ( " Failed to set up children monitoring! \n " ) ) ;
return false ;
}
return true ;
}
static void spoolssd_check_children ( struct tevent_context * ev_ctx ,
struct tevent_timer * te ,
struct timeval current_time ,
void * pvt )
{
2011-08-08 22:15:14 +04:00
struct messaging_context * msg_ctx ;
2011-04-21 23:06:18 +04:00
2011-08-08 22:15:14 +04:00
msg_ctx = talloc_get_type_abort ( pvt , struct messaging_context ) ;
2011-04-21 23:06:18 +04:00
2011-08-12 23:25:48 +04:00
pfh_manage_pool ( ev_ctx , msg_ctx , & pf_spoolss_cfg , spoolss_pool ) ;
2011-04-21 23:06:18 +04:00
2011-08-12 20:24:48 +04:00
spoolssd_schedule_check ( ev_ctx , msg_ctx , current_time ) ;
2011-04-21 23:06:18 +04:00
}
2011-05-18 19:24:30 +04:00
static void print_queue_forward ( struct messaging_context * msg ,
void * private_data ,
uint32_t msg_type ,
struct server_id server_id ,
DATA_BLOB * data )
{
messaging_send_buf ( msg , pid_to_procid ( background_lpq_updater_pid ) ,
MSG_PRINTER_UPDATE , data - > data , data - > length ) ;
}
2011-08-10 14:48:30 +04:00
static char * get_bq_logfile ( void )
2011-08-05 23:14:26 +04:00
{
2012-07-18 09:37:23 +04:00
char * lfile = lp_logfile ( talloc_tos ( ) ) ;
2011-08-05 23:14:26 +04:00
int rc ;
if ( lfile = = NULL | | lfile [ 0 ] = = ' \0 ' ) {
rc = asprintf ( & lfile , " %s/log.%s.bq " ,
get_dyn_LOGFILEBASE ( ) , DAEMON_NAME ) ;
} else {
2012-07-18 09:37:23 +04:00
rc = asprintf ( & lfile , " %s.bq " , lp_logfile ( talloc_tos ( ) ) ) ;
2011-08-05 23:14:26 +04:00
}
if ( rc = = - 1 ) {
lfile = NULL ;
}
return lfile ;
}
2011-05-18 19:24:30 +04:00
pid_t start_spoolssd ( struct tevent_context * ev_ctx ,
2011-01-20 20:59:40 +03:00
struct messaging_context * msg_ctx )
2010-05-20 16:48:18 +04:00
{
2014-02-27 12:58:27 +04:00
enum rpc_service_mode_e epm_mode = rpc_epmapper_mode ( ) ;
2010-06-16 02:39:27 +04:00
struct rpc_srv_callbacks spoolss_cb ;
2011-07-01 20:40:38 +04:00
struct dcerpc_binding_vector * v ;
TALLOC_CTX * mem_ctx ;
2010-05-20 16:48:18 +04:00
pid_t pid ;
NTSTATUS status ;
2011-04-21 23:06:18 +04:00
int listen_fd ;
2010-05-20 16:48:18 +04:00
int ret ;
2011-04-21 23:06:18 +04:00
bool ok ;
2010-05-20 16:48:18 +04:00
DEBUG ( 1 , ( " Forking SPOOLSS Daemon \n " ) ) ;
2011-08-08 18:08:46 +04:00
/*
* Block signals before forking child as it will have to
* set its own handlers . Child will re - enable SIGHUP as
* soon as the handlers are set up .
*/
BlockSignals ( true , SIGTERM ) ;
BlockSignals ( true , SIGHUP ) ;
2012-03-24 23:17:08 +04:00
pid = fork ( ) ;
2010-05-20 16:48:18 +04:00
if ( pid = = - 1 ) {
2011-05-18 19:24:30 +04:00
DEBUG ( 0 , ( " Failed to fork SPOOLSS [%s] \n " ,
2010-05-20 16:48:18 +04:00
strerror ( errno ) ) ) ;
}
2011-08-08 18:08:46 +04:00
/* parent or error */
2011-05-18 19:24:30 +04:00
if ( pid ! = 0 ) {
2011-08-08 18:08:46 +04:00
/* Re-enable SIGHUP before returnig */
BlockSignals ( false , SIGTERM ) ;
BlockSignals ( false , SIGHUP ) ;
2011-05-18 19:24:30 +04:00
return pid ;
2010-05-20 16:48:18 +04:00
}
2015-09-23 21:14:05 +03:00
status = smbd_reinit_after_fork ( msg_ctx , ev_ctx , true ,
" spoolssd-master " ) ;
2010-05-20 16:48:18 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " reinit_after_fork() failed \n " ) ) ;
smb_panic ( " reinit_after_fork() failed " ) ;
}
2011-08-17 00:36:43 +04:00
/* save the parent process id so the children can use it later */
2012-10-19 09:15:31 +04:00
parent_id = messaging_server_id ( msg_ctx ) ;
2011-08-17 00:36:43 +04:00
2011-08-05 18:08:23 +04:00
spoolss_reopen_logs ( 0 ) ;
2011-08-12 23:25:48 +04:00
pfh_daemon_config ( DAEMON_NAME ,
& pf_spoolss_cfg ,
& default_pf_spoolss_cfg ) ;
2010-06-16 02:38:44 +04:00
2011-08-08 18:08:46 +04:00
spoolss_setup_sig_term_handler ( ev_ctx ) ;
spoolss_setup_sig_hup_handler ( ev_ctx , msg_ctx ) ;
BlockSignals ( false , SIGTERM ) ;
BlockSignals ( false , SIGHUP ) ;
2011-05-18 19:24:30 +04:00
/* always start the backgroundqueue listner in spoolssd */
2011-08-05 23:14:26 +04:00
bq_logfile = get_bq_logfile ( ) ;
pid = start_background_queue ( ev_ctx , msg_ctx , bq_logfile ) ;
2011-05-18 19:24:30 +04:00
if ( pid > 0 ) {
background_lpq_updater_pid = pid ;
}
2011-04-21 23:06:18 +04:00
/* the listening fd must be created before the children are actually
* forked out . */
listen_fd = create_named_pipe_socket ( SPOOLSS_PIPE_NAME ) ;
if ( listen_fd = = - 1 ) {
exit ( 1 ) ;
}
2011-08-12 23:25:48 +04:00
ret = listen ( listen_fd , pf_spoolss_cfg . max_allowed_clients ) ;
2011-04-21 23:06:18 +04:00
if ( ret = = - 1 ) {
DEBUG ( 0 , ( " Failed to listen on spoolss pipe - %s \n " ,
strerror ( errno ) ) ) ;
exit ( 1 ) ;
}
/* start children before any more initialization is done */
2011-07-18 18:39:50 +04:00
ok = prefork_create_pool ( ev_ctx , /* mem_ctx */
ev_ctx , msg_ctx ,
1 , & listen_fd ,
2011-08-12 23:25:48 +04:00
pf_spoolss_cfg . min_children ,
pf_spoolss_cfg . max_children ,
2011-04-21 23:06:18 +04:00
& spoolss_children_main , NULL ,
2011-08-08 22:15:14 +04:00
& spoolss_pool ) ;
2011-07-15 20:08:35 +04:00
if ( ! ok ) {
exit ( 1 ) ;
}
2011-04-21 23:06:18 +04:00
2012-10-19 09:15:31 +04:00
if ( ! serverid_register ( messaging_server_id ( msg_ctx ) ,
2011-08-10 00:46:21 +04:00
FLAG_MSG_GENERAL |
FLAG_MSG_PRINT_GENERAL ) ) {
2010-05-20 16:48:18 +04:00
exit ( 1 ) ;
}
if ( ! locking_init ( ) ) {
exit ( 1 ) ;
}
2011-01-20 20:59:40 +03:00
messaging_register ( msg_ctx , ev_ctx ,
2010-06-16 23:36:06 +04:00
MSG_SMB_CONF_UPDATED , smb_conf_updated ) ;
2011-05-18 19:24:30 +04:00
messaging_register ( msg_ctx , NULL , MSG_PRINTER_UPDATE ,
print_queue_forward ) ;
2011-08-17 00:36:43 +04:00
messaging_register ( msg_ctx , ev_ctx ,
MSG_PREFORK_CHILD_EVENT , child_ping ) ;
2010-05-20 16:48:18 +04:00
2014-07-11 19:00:05 +04:00
/*
* As soon as messaging is up check if pcap has been loaded already .
* If pcap has not been loaded yet , then ignore , as we will reload on
* client enumeration anyway .
*/
2014-07-23 14:12:34 +04:00
if ( pcap_cache_loaded ( NULL ) ) {
2011-08-10 17:20:24 +04:00
load_printers ( ev_ctx , msg_ctx ) ;
}
2011-07-01 20:40:38 +04:00
mem_ctx = talloc_new ( NULL ) ;
if ( mem_ctx = = NULL ) {
exit ( 1 ) ;
}
2010-06-16 02:39:27 +04:00
/*
* Initialize spoolss with an init function to convert printers first .
* static_init_rpc will try to initialize the spoolss server too but you
* can ' t register it twice .
*/
spoolss_cb . init = spoolss_init_cb ;
2011-01-20 20:59:40 +03:00
spoolss_cb . shutdown = spoolss_shutdown_cb ;
spoolss_cb . private_data = msg_ctx ;
2010-06-16 02:39:27 +04:00
status = rpc_winreg_init ( NULL ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2015-06-03 14:33:00 +03:00
DEBUG ( 0 , ( " Failed to register winreg rpc interface! (%s) \n " ,
2010-06-16 02:39:27 +04:00
nt_errstr ( status ) ) ) ;
exit ( 1 ) ;
}
status = rpc_spoolss_init ( & spoolss_cb ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2015-06-03 14:33:00 +03:00
DEBUG ( 0 , ( " Failed to register spoolss rpc interface! (%s) \n " ,
2010-06-16 02:39:27 +04:00
nt_errstr ( status ) ) ) ;
exit ( 1 ) ;
}
2014-02-27 12:58:27 +04:00
if ( epm_mode ! = RPC_SERVICE_MODE_DISABLED & &
( lp_parm_bool ( - 1 , " rpc_server " , " register_embedded_np " , false ) ) ) {
status = dcerpc_binding_vector_new ( mem_ctx , & v ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Failed to create binding vector (%s) \n " ,
nt_errstr ( status ) ) ) ;
exit ( 1 ) ;
}
2010-05-20 16:48:18 +04:00
2014-02-27 12:58:27 +04:00
status = dcerpc_binding_vector_add_np_default ( & ndr_table_spoolss , v ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Failed to add np to binding vector (%s) \n " ,
nt_errstr ( status ) ) ) ;
exit ( 1 ) ;
}
2011-07-01 20:40:38 +04:00
2014-02-27 12:58:27 +04:00
status = rpc_ep_register ( ev_ctx , msg_ctx , & ndr_table_spoolss , v ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Failed to register spoolss endpoint! (%s) \n " ,
nt_errstr ( status ) ) ) ;
exit ( 1 ) ;
}
2011-03-28 16:18:23 +04:00
}
2011-07-01 20:40:38 +04:00
talloc_free ( mem_ctx ) ;
2011-08-08 22:15:14 +04:00
ok = spoolssd_setup_children_monitor ( ev_ctx , msg_ctx ) ;
2011-04-21 23:06:18 +04:00
if ( ! ok ) {
DEBUG ( 0 , ( " Failed to setup children monitoring! \n " ) ) ;
exit ( 1 ) ;
}
2013-03-14 14:17:54 +04:00
DEBUG ( 1 , ( " SPOOLSS Daemon Started (%u) \n " , ( unsigned int ) getpid ( ) ) ) ;
2010-06-16 02:39:27 +04:00
2011-08-12 23:25:48 +04:00
pfh_manage_pool ( ev_ctx , msg_ctx , & pf_spoolss_cfg , spoolss_pool ) ;
2011-08-12 20:24:48 +04:00
2010-05-20 16:48:18 +04:00
/* loop forever */
2011-01-20 20:59:40 +03:00
ret = tevent_loop_wait ( ev_ctx ) ;
2010-05-20 16:48:18 +04:00
/* should not be reached */
2011-08-11 22:23:19 +04:00
DEBUG ( 0 , ( " spoolssd tevent_loop_wait() exited with %d - %s \n " ,
2010-05-20 16:48:18 +04:00
ret , ( ret = = 0 ) ? " out of events " : strerror ( errno ) ) ) ;
exit ( 1 ) ;
}