2011-08-02 00:50:51 +04:00
/*
Unix SMB / Netbios implementation .
Version 3.0
printing backend routines
Copyright ( C ) Andrew Tridgell 1992 - 2000
Copyright ( C ) Jeremy Allison 2002
Copyright ( C ) Simo Sorce 2011
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"
2021-04-22 14:39:31 +03:00
# include <spawn.h>
2011-08-02 00:50:51 +04:00
# include "smbd/globals.h"
# include "include/messages.h"
2013-02-25 13:41:18 +04:00
# include "lib/util/util_process.h"
2021-04-22 14:39:31 +03:00
# include "lib/util/sys_rw.h"
2011-08-02 00:50:51 +04:00
# include "printing.h"
# include "printing/pcap.h"
2021-03-13 16:34:35 +03:00
# include "printing/printer_list.h"
2011-08-03 14:59:17 +04:00
# include "printing/queue_process.h"
2011-08-02 00:50:51 +04:00
# include "locking/proto.h"
2020-10-28 14:09:39 +03:00
# include "locking/share_mode_lock.h"
2012-06-05 16:53:01 +04:00
# include "smbd/smbd.h"
2011-08-10 23:23:20 +04:00
# include "rpc_server/rpc_config.h"
2011-08-10 17:27:24 +04:00
# include "printing/load.h"
2019-10-01 18:21:00 +03:00
# include "printing/spoolssd.h"
2014-02-12 22:13:19 +04:00
# include "rpc_server/spoolss/srv_spoolss_nt.h"
2014-08-01 18:25:59 +04:00
# include "auth.h"
# include "nt_printing.h"
2018-04-24 15:19:48 +03:00
# include "util_event.h"
2021-01-03 23:53:49 +03:00
# include "lib/global_contexts.h"
2011-05-18 19:24:30 +04:00
2014-08-01 18:25:59 +04:00
/**
* @ brief Purge stale printers and reload from pre - populated pcap cache .
*
* This function should normally only be called as a callback on a successful
* pcap_cache_reload ( ) .
*
* This function can cause DELETION of printers and drivers from our registry ,
* so calling it on a failed pcap reload may REMOVE permanently all printers
* and drivers .
*
* @ param [ in ] ev The event context .
*
* @ param [ in ] msg_ctx The messaging context .
*/
static void delete_and_reload_printers_full ( struct tevent_context * ev ,
struct messaging_context * msg_ctx )
{
struct auth_session_info * session_info = NULL ;
struct spoolss_PrinterInfo2 * pinfo2 = NULL ;
2019-11-04 14:14:34 +03:00
const struct loadparm_substitution * lp_sub =
loadparm_s3_global_substitution ( ) ;
2014-08-01 18:25:59 +04:00
int n_services ;
int pnum ;
int snum ;
const char * pname ;
const char * sname ;
NTSTATUS status ;
n_services = lp_numservices ( ) ;
pnum = lp_servicenumber ( PRINTERS_NAME ) ;
status = make_session_info_system ( talloc_tos ( ) , & session_info ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 3 , ( " reload_printers: "
" Could not create system session_info \n " ) ) ;
/* can't remove stale printers before we
2021-03-21 11:45:13 +03:00
* are fully initialized */
2014-08-01 18:25:59 +04:00
return ;
}
/*
* Add default config for printers added to smb . conf file and remove
* stale printers
*/
for ( snum = 0 ; snum < n_services ; snum + + ) {
/* avoid removing PRINTERS_NAME */
if ( snum = = pnum ) {
continue ;
}
/* skip no-printer services */
if ( ! snum_is_shared_printer ( snum ) ) {
continue ;
}
sname = lp_const_servicename ( snum ) ;
2019-11-04 14:14:34 +03:00
pname = lp_printername ( session_info , lp_sub , snum ) ;
2014-08-01 18:25:59 +04:00
/* check printer, but avoid removing non-autoloaded printers */
2021-03-13 16:34:35 +03:00
if ( lp_autoloaded ( snum ) & &
! printer_list_printername_exists ( pname ) ) {
2014-08-01 18:25:59 +04:00
DEBUG ( 3 , ( " removing stale printer %s \n " , pname ) ) ;
if ( is_printer_published ( session_info , session_info ,
msg_ctx ,
NULL ,
lp_servicename ( session_info ,
2019-11-07 13:01:05 +03:00
lp_sub ,
2014-08-01 18:25:59 +04:00
snum ) ,
& pinfo2 ) ) {
nt_printer_publish ( session_info ,
session_info ,
msg_ctx ,
pinfo2 ,
DSPRINT_UNPUBLISH ) ;
TALLOC_FREE ( pinfo2 ) ;
}
nt_printer_remove ( session_info , session_info , msg_ctx ,
pname ) ;
} else {
DEBUG ( 8 , ( " Adding default registry entry for printer "
" [%s], if it doesn't exist. \n " , sname ) ) ;
nt_printer_add ( session_info , session_info , msg_ctx ,
sname ) ;
}
}
/* finally, purge old snums */
2018-05-23 17:35:20 +03:00
delete_and_reload_printers ( ) ;
2014-08-01 18:25:59 +04:00
TALLOC_FREE ( session_info ) ;
}
2011-08-02 00:50:51 +04:00
/****************************************************************************
Notify smbds of new printcap data
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void reload_pcap_change_notify ( struct tevent_context * ev ,
struct messaging_context * msg_ctx )
{
2012-09-27 21:01:15 +04:00
/*
* Reload the printers first in the background process so that
* newly added printers get default values created in the registry .
*
* This will block the process for some time ( ~ 1 sec per printer ) , but
2021-03-21 11:45:13 +03:00
* it doesn ' t block smbd ' s serving clients .
2012-09-27 21:01:15 +04:00
*/
2014-08-01 18:25:59 +04:00
delete_and_reload_printers_full ( ev , msg_ctx ) ;
2012-09-27 21:01:15 +04:00
2017-11-05 14:54:10 +03:00
messaging_send_all ( msg_ctx , MSG_PRINTER_PCAP , NULL , 0 ) ;
2011-08-02 00:50:51 +04:00
}
2016-04-18 19:48:43 +03:00
struct bq_state {
2012-01-16 18:54:41 +04:00
struct tevent_context * ev ;
struct messaging_context * msg ;
2016-04-18 19:48:43 +03:00
struct idle_event * housekeep ;
2021-04-23 11:32:43 +03:00
struct tevent_signal * sighup_handler ;
struct tevent_signal * sigchld_handler ;
2012-01-16 18:54:41 +04:00
} ;
2011-08-02 00:50:51 +04:00
static bool print_queue_housekeeping ( const struct timeval * now , void * pvt )
{
2016-04-18 19:48:43 +03:00
struct bq_state * state ;
state = talloc_get_type_abort ( pvt , struct bq_state ) ;
2011-08-02 00:50:51 +04:00
DEBUG ( 5 , ( " print queue housekeeping \n " ) ) ;
2021-03-22 18:11:21 +03:00
pcap_cache_reload ( state - > ev , state - > msg , reload_pcap_change_notify ) ;
2011-08-02 00:50:51 +04:00
return true ;
}
2016-04-18 19:48:43 +03:00
static bool printing_subsystem_queue_tasks ( struct bq_state * state )
2011-08-02 00:50:51 +04:00
{
2016-04-18 19:48:42 +03:00
uint32_t housekeeping_period = lp_printcap_cache_time ( ) ;
2012-01-16 18:54:41 +04:00
2016-04-18 19:48:43 +03:00
/* cancel any existing housekeeping event */
TALLOC_FREE ( state - > housekeep ) ;
2012-01-16 18:54:41 +04:00
2019-01-29 03:55:04 +03:00
if ( ( housekeeping_period = = 0 ) | | ! lp_load_printers ( ) ) {
2016-04-18 19:48:42 +03:00
DEBUG ( 4 , ( " background print queue housekeeping disabled \n " ) ) ;
return true ;
}
2016-04-18 19:48:43 +03:00
state - > housekeep = event_add_idle ( state - > ev , NULL ,
timeval_set ( housekeeping_period , 0 ) ,
" print_queue_housekeeping " ,
print_queue_housekeeping , state ) ;
if ( state - > housekeep = = NULL ) {
2012-01-16 18:54:41 +04:00
DEBUG ( 0 , ( " Could not add print_queue_housekeeping event \n " ) ) ;
2011-08-02 00:50:51 +04:00
return false ;
}
return true ;
}
2011-08-05 23:14:26 +04:00
static void bq_reopen_logs ( char * logfile )
{
if ( logfile ) {
lp_set_logfile ( logfile ) ;
}
reopen_logs ( ) ;
}
2011-08-02 00:50:51 +04:00
static void bq_sig_hup_handler ( struct tevent_context * ev ,
struct tevent_signal * se ,
int signum ,
int count ,
void * siginfo ,
void * pvt )
{
2016-04-18 19:48:43 +03:00
struct bq_state * state ;
2011-08-02 00:50:51 +04:00
2016-04-18 19:48:43 +03:00
state = talloc_get_type_abort ( pvt , struct bq_state ) ;
2011-08-02 00:50:51 +04:00
change_to_root_user ( ) ;
DEBUG ( 1 , ( " Reloading pcap cache after SIGHUP \n " ) ) ;
2016-04-18 19:48:43 +03:00
pcap_cache_reload ( state - > ev , state - > msg ,
2021-03-22 18:11:21 +03:00
reload_pcap_change_notify ) ;
2016-04-18 19:48:43 +03:00
printing_subsystem_queue_tasks ( state ) ;
2011-08-05 23:14:26 +04:00
bq_reopen_logs ( NULL ) ;
2011-08-02 00:50:51 +04:00
}
2011-08-10 16:59:44 +04:00
static void bq_sig_chld_handler ( struct tevent_context * ev_ctx ,
struct tevent_signal * se ,
int signum , int count ,
void * siginfo , void * pvt )
{
int status ;
pid_t pid ;
2021-04-23 12:17:33 +03:00
do {
do {
pid = waitpid ( - 1 , & status , WNOHANG ) ;
} while ( ( pid = = - 1 ) & & ( errno = = EINTR ) ) ;
if ( WIFEXITED ( status ) ) {
DBG_INFO ( " Bq child process %d terminated with %d \n " ,
( int ) pid ,
WEXITSTATUS ( status ) ) ;
} else {
DBG_NOTICE ( " Bq child process %d terminated abnormally \n " ,
( int ) pid ) ;
}
} while ( pid > 0 ) ;
2011-08-10 16:59:44 +04:00
}
2011-08-02 00:50:51 +04:00
static void bq_smb_conf_updated ( struct messaging_context * msg_ctx ,
void * private_data ,
uint32_t msg_type ,
struct server_id server_id ,
DATA_BLOB * data )
{
2016-04-18 19:48:43 +03:00
struct bq_state * state ;
state = talloc_get_type_abort ( private_data , struct bq_state ) ;
2011-08-02 00:50:51 +04:00
DEBUG ( 10 , ( " smb_conf_updated: Got message saying smb.conf was "
" updated. Reloading. \n " ) ) ;
change_to_root_user ( ) ;
2021-03-22 18:11:21 +03:00
pcap_cache_reload ( state - > ev , msg_ctx , reload_pcap_change_notify ) ;
2016-04-18 19:48:43 +03:00
printing_subsystem_queue_tasks ( state ) ;
2011-08-02 00:50:51 +04:00
}
2021-04-23 11:32:43 +03:00
static int bq_state_destructor ( struct bq_state * s )
{
struct messaging_context * msg_ctx = s - > msg ;
TALLOC_FREE ( s - > sighup_handler ) ;
TALLOC_FREE ( s - > sigchld_handler ) ;
messaging_deregister ( msg_ctx , MSG_PRINTER_DRVUPGRADE , NULL ) ;
messaging_deregister ( msg_ctx , MSG_PRINTER_UPDATE , NULL ) ;
messaging_deregister ( msg_ctx , MSG_SMB_CONF_UPDATED , s ) ;
return 0 ;
}
struct bq_state * register_printing_bq_handlers (
TALLOC_CTX * mem_ctx ,
struct messaging_context * msg_ctx )
{
struct bq_state * state = NULL ;
NTSTATUS status ;
2021-04-22 14:39:31 +03:00
bool ok ;
2021-04-23 11:32:43 +03:00
state = talloc_zero ( mem_ctx , struct bq_state ) ;
if ( state = = NULL ) {
return NULL ;
}
state - > ev = messaging_tevent_context ( msg_ctx ) ;
state - > msg = msg_ctx ;
status = messaging_register (
msg_ctx , state , MSG_SMB_CONF_UPDATED , bq_smb_conf_updated ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
status = messaging_register (
msg_ctx , NULL , MSG_PRINTER_UPDATE , print_queue_receive ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail_dereg_smb_conf_updated ;
}
status = messaging_register (
msg_ctx , NULL , MSG_PRINTER_DRVUPGRADE , do_drv_upgrade_printer ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail_dereg_printer_update ;
}
state - > sighup_handler = tevent_add_signal (
state - > ev , state , SIGHUP , 0 , bq_sig_hup_handler , state ) ;
if ( state - > sighup_handler = = NULL ) {
goto fail_dereg_printer_drvupgrade ;
}
state - > sigchld_handler = tevent_add_signal (
state - > ev , state , SIGCHLD , 0 , bq_sig_chld_handler , NULL ) ;
if ( state - > sigchld_handler = = NULL ) {
goto fail_free_handlers ;
}
2021-04-22 14:39:31 +03:00
ok = printing_subsystem_queue_tasks ( state ) ;
if ( ! ok ) {
goto fail_free_handlers ;
}
2021-04-23 11:32:43 +03:00
talloc_set_destructor ( state , bq_state_destructor ) ;
return state ;
fail_free_handlers :
TALLOC_FREE ( state - > sighup_handler ) ;
TALLOC_FREE ( state - > sigchld_handler ) ;
fail_dereg_printer_drvupgrade :
messaging_deregister ( msg_ctx , MSG_PRINTER_DRVUPGRADE , NULL ) ;
fail_dereg_printer_update :
messaging_deregister ( msg_ctx , MSG_PRINTER_UPDATE , NULL ) ;
fail_dereg_smb_conf_updated :
messaging_deregister ( msg_ctx , MSG_SMB_CONF_UPDATED , state ) ;
fail :
TALLOC_FREE ( state ) ;
return NULL ;
}
2021-04-22 14:39:31 +03:00
extern char * * environ ;
2011-08-02 00:50:51 +04:00
/****************************************************************************
main thread of the background lpq updater
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-08-04 01:04:50 +04:00
pid_t start_background_queue ( struct tevent_context * ev ,
2011-08-05 23:14:26 +04:00
struct messaging_context * msg_ctx ,
char * logfile )
2011-08-02 00:50:51 +04:00
{
2011-08-04 01:04:50 +04:00
pid_t pid ;
2021-04-23 17:09:43 +03:00
int ret ;
2021-04-22 14:39:31 +03:00
ssize_t nread ;
char * * argv = NULL ;
int ready_fds [ 2 ] ;
2011-08-04 01:04:50 +04:00
2011-08-02 00:50:51 +04:00
DEBUG ( 3 , ( " start_background_queue: Starting background LPQ thread \n " ) ) ;
2021-04-22 14:39:31 +03:00
ret = pipe ( ready_fds ) ;
if ( ret = = - 1 ) {
return - 1 ;
2011-08-08 18:08:46 +04:00
}
2021-04-22 14:39:31 +03:00
argv = str_list_make_empty ( talloc_tos ( ) ) ;
str_list_add_printf (
& argv , " %s/samba-bgqd " , get_dyn_SAMBA_LIBEXECDIR ( ) ) ;
str_list_add_printf (
& argv , " --ready-signal-fd=%d " , ready_fds [ 1 ] ) ;
str_list_add_printf (
& argv , " --parent-watch-fd=%d " , parent_watch_fd ( ) ) ;
str_list_add_printf (
& argv , " --debuglevel=%d " , debuglevel_get_class ( DBGC_RPC_SRV ) ) ;
if ( ! is_default_dyn_CONFIGFILE ( ) ) {
str_list_add_printf (
& argv , " --configfile=%s " , get_dyn_CONFIGFILE ( ) ) ;
2021-04-23 17:09:43 +03:00
}
2021-04-22 14:39:31 +03:00
if ( ! is_default_dyn_LOGFILEBASE ( ) ) {
str_list_add_printf (
& argv , " --log-basename=%s " , get_dyn_LOGFILEBASE ( ) ) ;
2021-04-23 17:09:43 +03:00
}
2021-04-22 14:39:31 +03:00
str_list_add_printf ( & argv , " -F " ) ;
if ( argv = = NULL ) {
goto nomem ;
2021-04-23 17:09:43 +03:00
}
2011-08-02 00:50:51 +04:00
2021-04-22 14:39:31 +03:00
ret = posix_spawn ( & pid , argv [ 0 ] , NULL , NULL , argv , environ ) ;
if ( ret = = - 1 ) {
goto fail ;
2011-08-02 00:50:51 +04:00
}
2021-04-22 14:39:31 +03:00
TALLOC_FREE ( argv ) ;
2021-04-23 17:09:43 +03:00
2021-04-22 14:39:31 +03:00
close ( ready_fds [ 1 ] ) ;
2021-04-23 17:09:43 +03:00
2021-04-22 14:39:31 +03:00
nread = sys_read ( ready_fds [ 0 ] , & pid , sizeof ( pid ) ) ;
close ( ready_fds [ 0 ] ) ;
if ( nread ! = sizeof ( pid ) ) {
goto fail ;
}
2011-08-02 00:50:51 +04:00
2011-08-04 01:04:50 +04:00
return pid ;
2021-04-22 14:39:31 +03:00
nomem :
errno = ENOMEM ;
fail :
{
int err = errno ;
TALLOC_FREE ( argv ) ;
errno = err ;
}
return - 1 ;
2011-08-04 01:04:50 +04:00
}
2011-08-02 00:50:51 +04:00
2021-04-22 14:39:31 +03:00
2011-08-02 00:50:51 +04:00
/* Run before the parent forks */
bool printing_subsystem_init ( struct tevent_context * ev_ctx ,
struct messaging_context * msg_ctx ,
2019-02-26 18:58:10 +03:00
struct dcesrv_context * dce_ctx ,
2011-05-18 19:24:30 +04:00
bool start_daemons ,
2011-08-02 00:50:51 +04:00
bool background_queue )
{
2011-08-04 01:04:50 +04:00
pid_t pid = - 1 ;
2011-08-02 00:50:51 +04:00
2011-08-02 18:06:31 +04:00
if ( ! print_backend_init ( msg_ctx ) ) {
return false ;
}
2011-05-18 19:24:30 +04:00
/* start spoolss daemon */
/* start as a separate daemon only if enabled */
2011-08-10 23:23:20 +04:00
if ( start_daemons & & rpc_spoolss_daemon ( ) = = RPC_DAEMON_FORK ) {
2011-05-18 19:24:30 +04:00
2019-02-26 18:58:10 +03:00
pid = start_spoolssd ( ev_ctx , msg_ctx , dce_ctx ) ;
2011-05-18 19:24:30 +04:00
} else if ( start_daemons & & background_queue ) {
2011-08-04 01:04:50 +04:00
2011-08-05 23:14:26 +04:00
pid = start_background_queue ( ev_ctx , msg_ctx , NULL ) ;
2011-08-04 01:04:50 +04:00
2011-08-02 00:50:51 +04:00
} else {
2011-08-04 01:04:50 +04:00
bool ret ;
2016-04-18 19:48:43 +03:00
struct bq_state * state ;
state = talloc_zero ( NULL , struct bq_state ) ;
if ( state = = NULL ) {
exit ( 1 ) ;
}
state - > ev = ev_ctx ;
state - > msg = msg_ctx ;
2011-08-04 01:04:50 +04:00
2016-04-18 19:48:43 +03:00
ret = printing_subsystem_queue_tasks ( state ) ;
2011-08-04 01:04:50 +04:00
/* Publish nt printers, this requires a working winreg pipe */
2014-08-01 18:25:59 +04:00
pcap_cache_reload ( ev_ctx , msg_ctx ,
2021-03-22 18:11:21 +03:00
delete_and_reload_printers_full ) ;
2011-08-04 01:04:50 +04:00
return ret ;
2011-08-02 00:50:51 +04:00
}
2011-08-04 01:04:50 +04:00
if ( pid = = - 1 ) {
return false ;
}
background_lpq_updater_pid = pid ;
return true ;
2011-08-02 00:50:51 +04:00
}
void printing_subsystem_update ( struct tevent_context * ev_ctx ,
2011-08-04 16:56:01 +04:00
struct messaging_context * msg_ctx ,
bool force )
2011-08-02 00:50:51 +04:00
{
2011-08-04 16:56:01 +04:00
if ( background_lpq_updater_pid ! = - 1 ) {
2019-01-29 03:50:15 +03:00
load_printers ( ) ;
2011-08-04 16:56:01 +04:00
if ( force ) {
/* Send a sighup to the background process.
* this will force it to reload printers */
kill ( background_lpq_updater_pid , SIGHUP ) ;
}
return ;
}
2011-08-02 00:50:51 +04:00
2014-08-01 18:25:59 +04:00
pcap_cache_reload ( ev_ctx , msg_ctx ,
2021-03-22 18:11:21 +03:00
delete_and_reload_printers_full ) ;
2011-08-02 00:50:51 +04:00
}