2002-11-26 03:01:56 +03:00
/*
Unix SMB / Netbios implementation .
Version 3.0
printing backend routines
Copyright ( C ) Andrew Tridgell 1992 - 2000
Copyright ( C ) Jeremy Allison 2002
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
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
2002-11-26 03:01:56 +03:00
( 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
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2002-11-26 03:01:56 +03:00
*/
2003-11-12 04:51:10 +03:00
# include "includes.h"
2011-10-07 21:00:29 +04:00
# include "system/passwd.h" /* uid_wrapper */
2011-02-26 01:20:06 +03:00
# include "system/filesys.h"
2002-11-26 03:01:56 +03:00
# include "printing.h"
2011-05-05 13:25:29 +04:00
# include "util_tdb.h"
2002-11-26 03:01:56 +03:00
static struct tdb_print_db * print_db_head ;
/****************************************************************************
Function to find or create the printer specific job tdb given a printername .
Limits the number of tdb ' s open to MAX_PRINT_DBS_OPEN .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct tdb_print_db * get_print_db_byname ( const char * printername )
{
struct tdb_print_db * p = NULL , * last_entry = NULL ;
int num_open = 0 ;
2007-11-22 00:56:36 +03:00
char * printdb_path = NULL ;
2007-10-19 04:40:25 +04:00
bool done_become_root = False ;
2002-11-26 03:01:56 +03:00
2004-08-25 17:03:04 +04:00
SMB_ASSERT ( printername ! = NULL ) ;
2004-08-25 16:31:00 +04:00
2002-11-26 03:01:56 +03:00
for ( p = print_db_head , last_entry = print_db_head ; p ; p = p - > next ) {
/* Ensure the list terminates... JRA. */
SMB_ASSERT ( p - > next ! = print_db_head ) ;
if ( p - > tdb & & strequal ( p - > printer_name , printername ) ) {
DLIST_PROMOTE ( print_db_head , p ) ;
p - > ref_count + + ;
return p ;
}
num_open + + ;
last_entry = p ;
}
/* Not found. */
if ( num_open > = MAX_PRINT_DBS_OPEN ) {
/* Try and recycle the last entry. */
2006-06-20 05:25:31 +04:00
if ( print_db_head & & last_entry ) {
DLIST_PROMOTE ( print_db_head , last_entry ) ;
}
2002-11-26 03:01:56 +03:00
for ( p = print_db_head ; p ; p = p - > next ) {
if ( p - > ref_count )
continue ;
if ( p - > tdb ) {
if ( tdb_close ( print_db_head - > tdb ) ) {
DEBUG ( 0 , ( " get_print_db: Failed to close tdb for printer %s \n " ,
print_db_head - > printer_name ) ) ;
return NULL ;
}
}
p - > tdb = NULL ;
p - > ref_count = 0 ;
memset ( p - > printer_name , ' \0 ' , sizeof ( p - > printer_name ) ) ;
break ;
}
2006-06-20 05:25:31 +04:00
if ( p & & print_db_head ) {
2002-11-26 03:01:56 +03:00
DLIST_PROMOTE ( print_db_head , p ) ;
p = print_db_head ;
}
}
2007-11-22 00:56:36 +03:00
2002-11-26 03:01:56 +03:00
if ( ! p ) {
/* Create one. */
2004-12-07 21:25:53 +03:00
p = SMB_MALLOC_P ( struct tdb_print_db ) ;
2002-11-26 03:01:56 +03:00
if ( ! p ) {
DEBUG ( 0 , ( " get_print_db: malloc fail ! \n " ) ) ;
return NULL ;
}
ZERO_STRUCTP ( p ) ;
DLIST_ADD ( print_db_head , p ) ;
}
2007-11-22 00:56:36 +03:00
if ( asprintf ( & printdb_path , " %s%s.tdb " ,
2009-01-16 02:48:29 +03:00
cache_path ( " printing/ " ) ,
2007-11-22 00:56:36 +03:00
printername ) < 0 ) {
DLIST_REMOVE ( print_db_head , p ) ;
SAFE_FREE ( p ) ;
return NULL ;
}
2002-11-26 03:01:56 +03:00
2010-02-13 10:18:53 +03:00
if ( geteuid ( ) ! = sec_initial_uid ( ) ) {
2002-11-26 03:01:56 +03:00
become_root ( ) ;
done_become_root = True ;
}
2004-06-04 21:26:09 +04:00
p - > tdb = tdb_open_log ( printdb_path , 5000 , TDB_DEFAULT , O_RDWR | O_CREAT ,
0600 ) ;
2002-11-26 03:01:56 +03:00
if ( done_become_root )
unbecome_root ( ) ;
if ( ! p - > tdb ) {
DEBUG ( 0 , ( " get_print_db: Failed to open printer backend database %s. \n " ,
printdb_path ) ) ;
DLIST_REMOVE ( print_db_head , p ) ;
2007-11-22 00:56:36 +03:00
SAFE_FREE ( printdb_path ) ;
2002-11-26 03:01:56 +03:00
SAFE_FREE ( p ) ;
return NULL ;
}
2007-11-22 00:56:36 +03:00
SAFE_FREE ( printdb_path ) ;
2002-11-26 03:01:56 +03:00
fstrcpy ( p - > printer_name , printername ) ;
p - > ref_count + + ;
return p ;
}
/***************************************************************************
Remove a reference count .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void release_print_db ( struct tdb_print_db * pdb )
{
pdb - > ref_count - - ;
SMB_ASSERT ( pdb - > ref_count > = 0 ) ;
}
/***************************************************************************
Close all open print db entries .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void close_all_print_db ( void )
{
struct tdb_print_db * p = NULL , * next_p = NULL ;
for ( p = print_db_head ; p ; p = next_p ) {
next_p = p - > next ;
if ( p - > tdb )
tdb_close ( p - > tdb ) ;
DLIST_REMOVE ( print_db_head , p ) ;
ZERO_STRUCTP ( p ) ;
SAFE_FREE ( p ) ;
}
}
/****************************************************************************
Fetch and clean the pid_t record list for all pids interested in notify
messages . data needs freeing on exit .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-06-20 13:10:32 +04:00
TDB_DATA get_printer_notify_pid_list ( struct tdb_context * tdb , const char * printer_name , bool cleanlist )
2002-11-26 03:01:56 +03:00
{
TDB_DATA data ;
size_t i ;
ZERO_STRUCT ( data ) ;
2003-07-11 00:37:01 +04:00
data = tdb_fetch_bystring ( tdb , NOTIFY_PID_LIST_KEY ) ;
2002-11-26 03:01:56 +03:00
if ( ! data . dptr ) {
ZERO_STRUCT ( data ) ;
return data ;
}
if ( data . dsize % 8 ) {
DEBUG ( 0 , ( " get_printer_notify_pid_list: Size of record for printer %s not a multiple of 8 ! \n " , printer_name ) ) ;
2003-07-11 00:37:01 +04:00
tdb_delete_bystring ( tdb , NOTIFY_PID_LIST_KEY ) ;
2002-11-26 03:01:56 +03:00
SAFE_FREE ( data . dptr ) ;
ZERO_STRUCT ( data ) ;
return data ;
}
if ( ! cleanlist )
return data ;
/*
* Weed out all dead entries .
*/
for ( i = 0 ; i < data . dsize ; i + = 8 ) {
pid_t pid = ( pid_t ) IVAL ( data . dptr , i ) ;
2012-03-24 23:17:08 +04:00
if ( pid = = getpid ( ) )
2002-11-26 03:01:56 +03:00
continue ;
/* Entry is dead if process doesn't exist or refcount is zero. */
2005-09-30 21:13:37 +04:00
while ( ( i < data . dsize ) & & ( ( IVAL ( data . dptr , i + 4 ) = = 0 ) | | ! process_exists_by_pid ( pid ) ) ) {
2002-11-26 03:01:56 +03:00
/* Refcount == zero is a logic error and should never happen. */
if ( IVAL ( data . dptr , i + 4 ) = = 0 ) {
DEBUG ( 0 , ( " get_printer_notify_pid_list: Refcount == 0 for pid = %u printer %s ! \n " ,
( unsigned int ) pid , printer_name ) ) ;
}
if ( data . dsize - i > 8 )
memmove ( & data . dptr [ i ] , & data . dptr [ i + 8 ] , data . dsize - i - 8 ) ;
data . dsize - = 8 ;
}
}
return data ;
}