2000-11-15 00:56:32 +03:00
/*
2002-03-22 09:24:38 +03:00
* Unix SMB / CIFS implementation .
2000-03-10 20:12:24 +03:00
* RPC Pipe client / server routines
* Copyright ( C ) Andrew Tridgell 1992 - 2000 ,
2004-04-13 18:39:48 +04:00
* Copyright ( C ) Jean François Micouleau 1998 - 2000.
2005-07-15 18:26:11 +04:00
* Copyright ( C ) Gerald Carter 2002 - 2005.
2000-11-15 00:56:32 +03:00
*
2000-03-10 20:12:24 +03: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
2007-07-09 23:25:36 +04:00
* the Free Software Foundation ; either version 3 of the License , or
2000-03-10 20:12:24 +03:00
* ( at your option ) any later version .
2000-11-15 00:56:32 +03:00
*
2000-03-10 20:12:24 +03:00
* 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 .
2000-11-15 00:56:32 +03:00
*
2000-03-10 20:12:24 +03:00
* You should have received a copy of the GNU General Public License
2007-07-10 09:23:25 +04:00
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
2000-03-10 20:12:24 +03:00
*/
2000-02-07 19:17:59 +03:00
# include "includes.h"
2010-06-15 13:48:12 +04:00
# include "printing/nt_printing_tdb.h"
2010-07-31 02:47:20 +04:00
# include "../librpc/gen_ndr/ndr_spoolss.h"
2011-02-08 16:17:14 +03:00
# include "rpc_server/spoolss/srv_spoolss_util.h"
2010-07-31 02:47:20 +04:00
# include "nt_printing.h"
2010-08-05 04:25:37 +04:00
# include "secrets.h"
2010-08-05 17:14:04 +04:00
# include "../librpc/gen_ndr/netlogon.h"
2010-10-12 08:27:50 +04:00
# include "../libcli/security/security.h"
2011-03-22 18:50:02 +03:00
# include "passdb/machine_sid.h"
2011-03-23 01:49:17 +03:00
# include "smbd/smbd.h"
2011-09-24 07:33:11 +04:00
# include "smbd/globals.h"
2011-03-24 16:12:42 +03:00
# include "auth.h"
2011-03-24 17:31:06 +03:00
# include "messages.h"
2011-04-30 01:47:25 +04:00
# include "rpc_server/spoolss/srv_spoolss_nt.h"
2011-07-05 02:55:35 +04:00
# include "rpc_client/cli_winreg_spoolss.h"
2010-04-15 04:48:00 +04:00
2001-01-04 22:27:08 +03:00
/* Map generic permissions to printer object specific permissions */
2007-10-06 01:41:17 +04:00
const struct generic_mapping printer_generic_mapping = {
2002-03-15 11:14:10 +03:00
PRINTER_READ ,
2002-04-11 07:15:02 +04:00
PRINTER_WRITE ,
2002-03-15 11:14:10 +03:00
PRINTER_EXECUTE ,
PRINTER_ALL_ACCESS
} ;
2002-04-15 07:49:53 +04:00
/* Map generic permissions to print server object specific permissions */
2007-10-06 01:41:17 +04:00
const struct generic_mapping printserver_generic_mapping = {
2002-04-15 07:49:53 +04:00
SERVER_READ ,
SERVER_WRITE ,
SERVER_EXECUTE ,
SERVER_ALL_ACCESS
} ;
2008-05-06 03:24:52 +04:00
/* Map generic permissions to job object specific permissions */
const struct generic_mapping job_generic_mapping = {
JOB_READ ,
JOB_WRITE ,
JOB_EXECUTE ,
JOB_ALL_ACCESS
} ;
2009-05-12 16:15:01 +04:00
static const struct print_architecture_table_node archi_table [ ] = {
2003-04-23 17:27:35 +04:00
2003-08-15 00:51:41 +04:00
{ " Windows 4.0 " , SPL_ARCH_WIN40 , 0 } ,
{ " Windows NT x86 " , SPL_ARCH_W32X86 , 2 } ,
{ " Windows NT R4000 " , SPL_ARCH_W32MIPS , 2 } ,
{ " Windows NT Alpha_AXP " , SPL_ARCH_W32ALPHA , 2 } ,
{ " Windows NT PowerPC " , SPL_ARCH_W32PPC , 2 } ,
2004-08-10 18:27:17 +04:00
{ " Windows IA64 " , SPL_ARCH_IA64 , 3 } ,
2004-10-05 02:13:57 +04:00
{ " Windows x64 " , SPL_ARCH_X64 , 3 } ,
2003-04-23 17:27:35 +04:00
{ NULL , " " , - 1 }
} ;
2013-01-17 20:18:04 +04:00
static bool print_driver_directories_init ( void )
{
int service , i ;
char * driver_path ;
bool ok ;
TALLOC_CTX * mem_ctx = talloc_stackframe ( ) ;
2016-09-02 11:00:01 +03:00
const char * dir_list [ ] = {
" W32X86/PCC " ,
" x64/PCC " ,
" color "
} ;
2013-01-17 20:18:04 +04:00
service = lp_servicenumber ( " print$ " ) ;
if ( service < 0 ) {
/* We don't have a print$ share */
DEBUG ( 5 , ( " No print$ share has been configured. \n " ) ) ;
2013-01-18 06:39:13 +04:00
talloc_free ( mem_ctx ) ;
2013-01-17 20:18:04 +04:00
return true ;
}
2014-02-02 17:04:46 +04:00
driver_path = lp_path ( mem_ctx , service ) ;
2013-01-17 20:18:04 +04:00
if ( driver_path = = NULL ) {
2013-01-18 06:39:13 +04:00
talloc_free ( mem_ctx ) ;
2013-01-17 20:18:04 +04:00
return false ;
}
2014-07-27 21:18:09 +04:00
ok = directory_create_or_exist ( driver_path , 0755 ) ;
2013-01-17 20:18:04 +04:00
if ( ! ok ) {
DEBUG ( 1 , ( " Failed to create printer driver directory %s \n " ,
driver_path ) ) ;
talloc_free ( mem_ctx ) ;
return false ;
}
for ( i = 0 ; archi_table [ i ] . long_archi ! = NULL ; i + + ) {
const char * arch_path ;
arch_path = talloc_asprintf ( mem_ctx ,
" %s/%s " ,
driver_path ,
archi_table [ i ] . short_archi ) ;
if ( arch_path = = NULL ) {
talloc_free ( mem_ctx ) ;
return false ;
}
2014-07-27 21:18:09 +04:00
ok = directory_create_or_exist ( arch_path , 0755 ) ;
2013-01-17 20:18:04 +04:00
if ( ! ok ) {
DEBUG ( 1 , ( " Failed to create printer driver "
" architecture directory %s \n " ,
arch_path ) ) ;
talloc_free ( mem_ctx ) ;
return false ;
}
}
2016-09-02 11:00:01 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( dir_list ) ; i + + ) {
const char * path ;
path = talloc_asprintf ( mem_ctx ,
" %s/%s " ,
driver_path ,
dir_list [ i ] ) ;
if ( path = = NULL ) {
talloc_free ( mem_ctx ) ;
return false ;
}
ok = directory_create_or_exist ( path , 0755 ) ;
if ( ! ok ) {
DEBUG ( 1 , ( " Failed to create printer driver "
" architecture directory %s \n " ,
path ) ) ;
talloc_free ( mem_ctx ) ;
return false ;
}
}
2018-08-16 11:51:44 +03:00
driver_path = state_path ( talloc_tos ( ) , " DriverStore " ) ;
2017-07-31 11:09:52 +03:00
if ( driver_path = = NULL ) {
talloc_free ( mem_ctx ) ;
return false ;
}
2016-09-12 22:00:18 +03:00
ok = directory_create_or_exist ( driver_path , 0755 ) ;
if ( ! ok ) {
DEBUG ( 1 , ( " failed to create path %s \n " , driver_path ) ) ;
talloc_free ( mem_ctx ) ;
return false ;
}
2017-07-31 11:09:52 +03:00
2018-08-16 11:51:44 +03:00
driver_path = state_path ( talloc_tos ( ) , " DriverStore/FileRepository " ) ;
2017-07-31 11:09:52 +03:00
if ( driver_path = = NULL ) {
talloc_free ( mem_ctx ) ;
return false ;
}
2016-09-12 22:00:18 +03:00
ok = directory_create_or_exist ( driver_path , 0755 ) ;
if ( ! ok ) {
DEBUG ( 1 , ( " failed to create path %s \n " , driver_path ) ) ;
talloc_free ( mem_ctx ) ;
return false ;
}
2017-07-31 11:09:52 +03:00
2018-08-16 11:51:44 +03:00
driver_path = state_path ( talloc_tos ( ) , " DriverStore/Temp " ) ;
2017-07-31 11:09:52 +03:00
if ( driver_path = = NULL ) {
talloc_free ( mem_ctx ) ;
return false ;
}
2016-09-12 22:00:18 +03:00
ok = directory_create_or_exist ( driver_path , 0755 ) ;
if ( ! ok ) {
DEBUG ( 1 , ( " failed to create path %s \n " , driver_path ) ) ;
talloc_free ( mem_ctx ) ;
return false ;
}
2013-01-17 20:18:04 +04:00
talloc_free ( mem_ctx ) ;
return true ;
}
2014-02-12 22:13:19 +04:00
/****************************************************************************
Forward a MSG_PRINTER_DRVUPGRADE message from another smbd to the
background lpq updater .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void forward_drv_upgrade_printer_msg ( struct messaging_context * msg ,
void * private_data ,
uint32_t msg_type ,
struct server_id server_id ,
DATA_BLOB * data )
{
extern pid_t background_lpq_updater_pid ;
if ( background_lpq_updater_pid = = - 1 ) {
DEBUG ( 3 , ( " no background lpq queue updater \n " ) ) ;
return ;
}
messaging_send_buf ( msg ,
pid_to_procid ( background_lpq_updater_pid ) ,
MSG_PRINTER_DRVUPGRADE ,
data - > data ,
data - > length ) ;
}
2000-02-07 19:17:59 +03:00
/****************************************************************************
2002-11-01 02:41:00 +03:00
Open the NT printing tdbs . Done once before fork ( ) .
2000-02-07 19:17:59 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-01-09 08:24:07 +03:00
2007-10-19 04:40:25 +04:00
bool nt_printing_init ( struct messaging_context * msg_ctx )
2000-02-07 19:17:59 +03:00
{
2004-09-23 23:24:02 +04:00
WERROR win_rc ;
2005-05-27 23:02:30 +04:00
2013-01-17 20:18:04 +04:00
if ( ! print_driver_directories_init ( ) ) {
return false ;
}
2010-06-15 13:48:12 +04:00
if ( ! nt_printing_tdb_upgrade ( ) ) {
return false ;
2000-05-24 10:10:21 +04:00
}
2009-02-09 14:40:12 +03:00
2002-07-15 14:35:28 +04:00
/*
* register callback to handle updating printers as new
2014-02-12 22:13:19 +04:00
* drivers are installed . Forwards to background lpq updater .
2002-07-15 14:35:28 +04:00
*/
2007-05-17 00:56:39 +04:00
messaging_register ( msg_ctx , NULL , MSG_PRINTER_DRVUPGRADE ,
2014-02-12 22:13:19 +04:00
forward_drv_upgrade_printer_msg ) ;
2002-08-17 20:31:24 +04:00
2004-10-13 23:40:22 +04:00
if ( lp_security ( ) = = SEC_ADS ) {
2010-08-08 16:37:47 +04:00
win_rc = check_published_printers ( msg_ctx ) ;
2004-10-13 23:40:22 +04:00
if ( ! W_ERROR_IS_OK ( win_rc ) )
2008-11-01 19:19:26 +03:00
DEBUG ( 0 , ( " nt_printing_init: error checking published printers: %s \n " , win_errstr ( win_rc ) ) ) ;
2004-10-13 23:40:22 +04:00
}
2004-09-23 23:24:02 +04:00
2010-06-15 13:48:12 +04:00
return true ;
2000-05-24 10:10:21 +04:00
}
2000-02-07 19:17:59 +03:00
2004-05-03 20:38:37 +04:00
/*******************************************************************
Function to allow filename parsing " the old way " .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-06-10 21:37:57 +04:00
static NTSTATUS driver_unix_convert ( connection_struct * conn ,
const char * old_name ,
struct smb_filename * * smb_fname )
2004-05-03 20:38:37 +04:00
{
s3: Change unix_convert (and its callers) to use struct smb_filename
This is the first of a series of patches that change path based
operations to operate on a struct smb_filename instead of a char *.
This same concept already exists in source4.
My goals for this series of patches are to eventually:
1) Solve the stream vs. posix filename that contains a colon ambiguity
that currently exists.
2) Make unix_convert the only function that parses the stream name.
3) Clean up the unix_convert API.
4) Change all path based vfs operation to take a struct smb_filename.
5) Make is_ntfs_stream_name() a constant operation that can simply
check the state of struct smb_filename rather than re-parse the
filename.
6) Eliminate the need for split_ntfs_stream_name() to exist.
My strategy is to start from the inside at unix_convert() and work my
way out through the vfs layer, call by call. This first patch does
just that, by changing unix_convert and all of its callers to operate
on struct smb_filename. Since this is such a large change, I plan on
pushing the patches in phases, where each phase keeps full
compatibility and passes make test.
The API of unix_convert has been simplified from:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
bool allow_wcard_last_component,
char **pp_conv_path,
char **pp_saved_last_component,
SMB_STRUCT_STAT *pst)
to:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
struct smb_filename *smb_fname,
uint32_t ucf_flags)
Currently the smb_filename struct looks like:
struct smb_filename {
char *base_name;
char *stream_name;
char *original_lcomp;
SMB_STRUCT_STAT st;
};
One key point here is the decision to break up the base_name and
stream_name. I have introduced a helper function called
get_full_smb_filename() that takes an smb_filename struct and
allocates the full_name. I changed the callers of unix_convert() to
subsequently call get_full_smb_filename() for the time being, but I
plan to eventually eliminate get_full_smb_filename().
2009-04-08 00:39:57 +04:00
NTSTATUS status ;
2007-11-16 01:19:52 +03:00
TALLOC_CTX * ctx = talloc_tos ( ) ;
char * name = talloc_strdup ( ctx , old_name ) ;
if ( ! name ) {
2009-06-10 21:37:57 +04:00
return NT_STATUS_NO_MEMORY ;
2007-11-16 01:19:52 +03:00
}
2004-05-03 20:38:37 +04:00
unix_format ( name ) ;
2007-11-16 01:19:52 +03:00
name = unix_clean_name ( ctx , name ) ;
if ( ! name ) {
2009-06-10 21:37:57 +04:00
return NT_STATUS_NO_MEMORY ;
2007-09-08 00:57:01 +04:00
}
2007-11-16 01:19:52 +03:00
trim_string ( name , " / " , " / " ) ;
s3: Change unix_convert (and its callers) to use struct smb_filename
This is the first of a series of patches that change path based
operations to operate on a struct smb_filename instead of a char *.
This same concept already exists in source4.
My goals for this series of patches are to eventually:
1) Solve the stream vs. posix filename that contains a colon ambiguity
that currently exists.
2) Make unix_convert the only function that parses the stream name.
3) Clean up the unix_convert API.
4) Change all path based vfs operation to take a struct smb_filename.
5) Make is_ntfs_stream_name() a constant operation that can simply
check the state of struct smb_filename rather than re-parse the
filename.
6) Eliminate the need for split_ntfs_stream_name() to exist.
My strategy is to start from the inside at unix_convert() and work my
way out through the vfs layer, call by call. This first patch does
just that, by changing unix_convert and all of its callers to operate
on struct smb_filename. Since this is such a large change, I plan on
pushing the patches in phases, where each phase keeps full
compatibility and passes make test.
The API of unix_convert has been simplified from:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
bool allow_wcard_last_component,
char **pp_conv_path,
char **pp_saved_last_component,
SMB_STRUCT_STAT *pst)
to:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
struct smb_filename *smb_fname,
uint32_t ucf_flags)
Currently the smb_filename struct looks like:
struct smb_filename {
char *base_name;
char *stream_name;
char *original_lcomp;
SMB_STRUCT_STAT st;
};
One key point here is the decision to break up the base_name and
stream_name. I have introduced a helper function called
get_full_smb_filename() that takes an smb_filename struct and
allocates the full_name. I changed the callers of unix_convert() to
subsequently call get_full_smb_filename() for the time being, but I
plan to eventually eliminate get_full_smb_filename().
2009-04-08 00:39:57 +04:00
2009-06-10 21:37:57 +04:00
status = unix_convert ( ctx , conn , name , smb_fname , 0 ) ;
s3: Change unix_convert (and its callers) to use struct smb_filename
This is the first of a series of patches that change path based
operations to operate on a struct smb_filename instead of a char *.
This same concept already exists in source4.
My goals for this series of patches are to eventually:
1) Solve the stream vs. posix filename that contains a colon ambiguity
that currently exists.
2) Make unix_convert the only function that parses the stream name.
3) Clean up the unix_convert API.
4) Change all path based vfs operation to take a struct smb_filename.
5) Make is_ntfs_stream_name() a constant operation that can simply
check the state of struct smb_filename rather than re-parse the
filename.
6) Eliminate the need for split_ntfs_stream_name() to exist.
My strategy is to start from the inside at unix_convert() and work my
way out through the vfs layer, call by call. This first patch does
just that, by changing unix_convert and all of its callers to operate
on struct smb_filename. Since this is such a large change, I plan on
pushing the patches in phases, where each phase keeps full
compatibility and passes make test.
The API of unix_convert has been simplified from:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
bool allow_wcard_last_component,
char **pp_conv_path,
char **pp_saved_last_component,
SMB_STRUCT_STAT *pst)
to:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
struct smb_filename *smb_fname,
uint32_t ucf_flags)
Currently the smb_filename struct looks like:
struct smb_filename {
char *base_name;
char *stream_name;
char *original_lcomp;
SMB_STRUCT_STAT st;
};
One key point here is the decision to break up the base_name and
stream_name. I have introduced a helper function called
get_full_smb_filename() that takes an smb_filename struct and
allocates the full_name. I changed the callers of unix_convert() to
subsequently call get_full_smb_filename() for the time being, but I
plan to eventually eliminate get_full_smb_filename().
2009-04-08 00:39:57 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-06-10 21:37:57 +04:00
return NT_STATUS_NO_MEMORY ;
s3: Change unix_convert (and its callers) to use struct smb_filename
This is the first of a series of patches that change path based
operations to operate on a struct smb_filename instead of a char *.
This same concept already exists in source4.
My goals for this series of patches are to eventually:
1) Solve the stream vs. posix filename that contains a colon ambiguity
that currently exists.
2) Make unix_convert the only function that parses the stream name.
3) Clean up the unix_convert API.
4) Change all path based vfs operation to take a struct smb_filename.
5) Make is_ntfs_stream_name() a constant operation that can simply
check the state of struct smb_filename rather than re-parse the
filename.
6) Eliminate the need for split_ntfs_stream_name() to exist.
My strategy is to start from the inside at unix_convert() and work my
way out through the vfs layer, call by call. This first patch does
just that, by changing unix_convert and all of its callers to operate
on struct smb_filename. Since this is such a large change, I plan on
pushing the patches in phases, where each phase keeps full
compatibility and passes make test.
The API of unix_convert has been simplified from:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
bool allow_wcard_last_component,
char **pp_conv_path,
char **pp_saved_last_component,
SMB_STRUCT_STAT *pst)
to:
NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *orig_path,
struct smb_filename *smb_fname,
uint32_t ucf_flags)
Currently the smb_filename struct looks like:
struct smb_filename {
char *base_name;
char *stream_name;
char *original_lcomp;
SMB_STRUCT_STAT st;
};
One key point here is the decision to break up the base_name and
stream_name. I have introduced a helper function called
get_full_smb_filename() that takes an smb_filename struct and
allocates the full_name. I changed the callers of unix_convert() to
subsequently call get_full_smb_filename() for the time being, but I
plan to eventually eliminate get_full_smb_filename().
2009-04-08 00:39:57 +04:00
}
2009-06-10 21:37:57 +04:00
return NT_STATUS_OK ;
2004-05-03 20:38:37 +04:00
}
2000-02-07 19:17:59 +03:00
/****************************************************************************
2006-06-20 01:36:19 +04:00
Function to do the mapping between the long architecture name and
the short one .
2000-02-07 19:17:59 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-06-20 01:36:19 +04:00
2003-04-23 17:27:35 +04:00
const char * get_short_archi ( const char * long_archi )
2000-02-07 19:17:59 +03:00
{
2003-04-23 17:27:35 +04:00
int i = - 1 ;
2000-02-07 19:17:59 +03:00
2011-03-01 00:04:29 +03:00
DEBUG ( 107 , ( " Getting architecture dependent directory \n " ) ) ;
2003-04-23 17:27:35 +04:00
do {
i + + ;
} while ( ( archi_table [ i ] . long_archi ! = NULL ) & &
2011-05-13 22:21:30 +04:00
strcasecmp_m ( long_archi , archi_table [ i ] . long_archi ) ) ;
2002-10-31 21:42:38 +03:00
2003-04-23 17:27:35 +04:00
if ( archi_table [ i ] . long_archi = = NULL ) {
DEBUGADD ( 10 , ( " Unknown architecture [%s] ! \n " , long_archi ) ) ;
return NULL ;
}
2002-10-31 21:42:38 +03:00
2003-04-23 17:27:35 +04:00
/* this might be client code - but shouldn't this be an fstrcpy etc? */
2000-02-07 19:17:59 +03:00
2003-04-23 17:27:35 +04:00
DEBUGADD ( 108 , ( " index: [%d] \n " , i ) ) ;
DEBUGADD ( 108 , ( " long architecture: [%s] \n " , archi_table [ i ] . long_archi ) ) ;
DEBUGADD ( 108 , ( " short architecture: [%s] \n " , archi_table [ i ] . short_archi ) ) ;
2000-02-07 19:17:59 +03:00
2003-04-23 17:27:35 +04:00
return archi_table [ i ] . short_archi ;
2000-07-25 17:15:16 +04:00
}
2018-04-30 20:15:49 +03:00
/****************************************************************************
Read data from fsp on the vfs .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2018-05-01 21:38:49 +03:00
static ssize_t printing_pread_data ( files_struct * fsp ,
2018-04-30 21:57:52 +03:00
char * buf ,
2018-05-02 23:45:44 +03:00
off_t * poff ,
2018-04-30 21:57:52 +03:00
size_t byte_count )
2018-04-30 20:15:49 +03:00
{
size_t total = 0 ;
2018-05-02 23:45:44 +03:00
off_t in_pos = * poff ;
2018-05-01 21:47:24 +03:00
/* Don't allow integer wrap on read. */
if ( in_pos + byte_count < in_pos ) {
return - 1 ;
2018-05-02 23:45:44 +03:00
}
2018-04-30 20:15:49 +03:00
while ( total < byte_count ) {
2018-05-01 21:51:43 +03:00
ssize_t ret = read_file ( fsp ,
buf + total ,
in_pos ,
2018-04-30 20:15:49 +03:00
byte_count - total ) ;
if ( ret = = 0 ) {
2018-05-01 21:47:24 +03:00
* poff = in_pos ;
2018-04-30 20:15:49 +03:00
return total ;
}
if ( ret = = - 1 ) {
if ( errno = = EINTR ) {
continue ;
} else {
return - 1 ;
}
}
2018-05-02 23:45:44 +03:00
in_pos + = ret ;
2018-04-30 20:15:49 +03:00
total + = ret ;
}
2018-05-01 21:47:24 +03:00
* poff = in_pos ;
2018-04-30 20:15:49 +03:00
return ( ssize_t ) total ;
}
2018-05-01 01:06:39 +03:00
/****************************************************************************
Detect the major and minor version of a PE file .
Returns :
1 if file is a PE file and we got version numbers ,
0 if this file is a PE file and we couldn ' t get the version numbers ,
- 1 on error .
NB . buf is passed into and freed inside this function . This is a
bad API design , but fixing this is a task for another day .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int handle_pe_file ( files_struct * fsp ,
2018-05-01 21:16:02 +03:00
off_t in_pos ,
2018-05-01 01:06:39 +03:00
char * fname ,
char * buf ,
uint32_t * major ,
uint32_t * minor )
{
unsigned int i ;
unsigned int num_sections ;
unsigned int section_table_bytes ;
ssize_t byte_count ;
2018-05-01 21:16:02 +03:00
off_t rel_pos ;
2018-05-01 01:06:39 +03:00
int ret = - 1 ;
/* Just skip over optional header to get to section table */
2018-05-01 21:16:02 +03:00
rel_pos = SVAL ( buf , PE_HEADER_OPTIONAL_HEADER_SIZE ) -
2018-05-01 01:06:39 +03:00
( NE_HEADER_SIZE - PE_HEADER_SIZE ) ;
2018-05-01 21:16:02 +03:00
if ( in_pos + rel_pos < in_pos ) {
/* Integer wrap. */
2018-05-01 01:06:39 +03:00
goto out ;
}
2018-05-01 21:16:02 +03:00
in_pos = rel_pos + in_pos ;
2018-05-01 01:06:39 +03:00
/* get the section table */
num_sections = SVAL ( buf , PE_HEADER_NUMBER_OF_SECTIONS ) ;
2018-05-08 09:41:04 +03:00
if ( num_sections > = ( UINT_MAX / PE_HEADER_SECT_HEADER_SIZE ) ) {
/* Integer wrap. */
goto out ;
}
2018-05-01 01:06:39 +03:00
section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE ;
if ( section_table_bytes = = 0 ) {
goto out ;
}
SAFE_FREE ( buf ) ;
buf = ( char * ) SMB_MALLOC ( section_table_bytes ) ;
if ( buf = = NULL ) {
DBG_ERR ( " PE file [%s] section table malloc "
" failed bytes = %d \n " ,
fname ,
section_table_bytes ) ;
goto out ;
}
2018-05-01 21:38:49 +03:00
byte_count = printing_pread_data ( fsp , buf , & in_pos , section_table_bytes ) ;
2018-05-01 01:06:39 +03:00
if ( byte_count < section_table_bytes ) {
DBG_NOTICE ( " PE file [%s] Section header too short, "
" bytes read = %lu \n " ,
fname ,
( unsigned long ) byte_count ) ;
goto out ;
}
/*
* Iterate the section table looking for
* the resource section " .rsrc "
*/
for ( i = 0 ; i < num_sections ; i + + ) {
int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE ;
if ( strcmp ( " .rsrc " ,
& buf [ sec_offset + PE_HEADER_SECT_NAME_OFFSET ] ) = = 0 ) {
unsigned int section_pos = IVAL ( buf ,
sec_offset +
PE_HEADER_SECT_PTR_DATA_OFFSET ) ;
unsigned int section_bytes = IVAL ( buf ,
sec_offset +
PE_HEADER_SECT_SIZE_DATA_OFFSET ) ;
if ( section_bytes = = 0 ) {
goto out ;
}
SAFE_FREE ( buf ) ;
buf = ( char * ) SMB_MALLOC ( section_bytes ) ;
if ( buf = = NULL ) {
DBG_ERR ( " PE file [%s] version malloc "
" failed bytes = %d \n " ,
fname ,
section_bytes ) ;
goto out ;
}
/*
2018-05-01 21:16:02 +03:00
* Read from the start of the . rsrc
2018-05-01 01:06:39 +03:00
* section info
*/
2018-05-01 21:16:02 +03:00
in_pos = section_pos ;
2018-05-01 01:06:39 +03:00
2018-05-01 21:38:49 +03:00
byte_count = printing_pread_data ( fsp ,
2018-05-01 01:06:39 +03:00
buf ,
2018-05-01 21:38:49 +03:00
& in_pos ,
2018-05-01 01:06:39 +03:00
section_bytes ) ;
if ( byte_count < section_bytes ) {
DBG_NOTICE ( " PE file "
" [%s] .rsrc section too short, "
" bytes read = %lu \n " ,
fname ,
( unsigned long ) byte_count ) ;
goto out ;
}
if ( section_bytes < VS_VERSION_INFO_UNICODE_SIZE ) {
goto out ;
}
for ( i = 0 ;
i < section_bytes - VS_VERSION_INFO_UNICODE_SIZE ;
i + + ) {
/*
* Scan for 1 st 3 unicoded bytes
* followed by word aligned magic
* value .
*/
int mpos ;
bool magic_match = false ;
if ( buf [ i ] = = ' V ' & &
buf [ i + 1 ] = = ' \0 ' & &
buf [ i + 2 ] = = ' S ' ) {
magic_match = true ;
}
if ( magic_match = = false ) {
continue ;
}
/* Align to next long address */
mpos = ( i + sizeof ( VS_SIGNATURE ) * 2 +
3 ) & 0xfffffffc ;
if ( IVAL ( buf , mpos ) = = VS_MAGIC_VALUE ) {
* major = IVAL ( buf ,
mpos + VS_MAJOR_OFFSET ) ;
* minor = IVAL ( buf ,
mpos + VS_MINOR_OFFSET ) ;
DBG_INFO ( " PE file [%s] Version = "
" %08x:%08x (%d.%d.%d.%d) \n " ,
fname ,
* major ,
* minor ,
( * major > > 16 ) & 0xffff ,
* major & 0xffff ,
( * minor > > 16 ) & 0xffff ,
* minor & 0xffff ) ;
ret = 1 ;
goto out ;
}
}
}
}
/* Version info not found, fall back to origin date/time */
DBG_DEBUG ( " PE file [%s] has no version info \n " , fname ) ;
ret = 0 ;
out :
SAFE_FREE ( buf ) ;
return ret ;
}
2018-05-01 01:50:14 +03:00
/****************************************************************************
Detect the major and minor version of an NE file .
Returns :
1 if file is an NE file and we got version numbers ,
0 if this file is an NE file and we couldn ' t get the version numbers ,
- 1 on error .
NB . buf is passed into and freed inside this function . This is a
bad API design , but fixing this is a task for another day .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int handle_ne_file ( files_struct * fsp ,
2018-05-01 21:19:49 +03:00
off_t in_pos ,
2018-05-01 01:50:14 +03:00
char * fname ,
char * buf ,
uint32_t * major ,
uint32_t * minor )
{
unsigned int i ;
ssize_t byte_count ;
int ret = - 1 ;
if ( CVAL ( buf , NE_HEADER_TARGET_OS_OFFSET ) ! = NE_HEADER_TARGOS_WIN ) {
DBG_NOTICE ( " NE file [%s] wrong target OS = 0x%x \n " ,
fname ,
CVAL ( buf , NE_HEADER_TARGET_OS_OFFSET ) ) ;
/*
* At this point , we assume the file is in error .
* It still could be something else besides a NE file ,
* but it unlikely at this point .
*/
goto out ;
}
/* Allocate a bit more space to speed up things */
SAFE_FREE ( buf ) ;
buf = ( char * ) SMB_MALLOC ( VS_NE_BUF_SIZE ) ;
if ( buf = = NULL ) {
DBG_ERR ( " NE file [%s] malloc failed bytes = %d \n " ,
fname ,
PE_HEADER_SIZE ) ;
goto out ;
}
/*
* This is a HACK ! I got tired of trying to sort through the
* messy ' NE ' file format . If anyone wants to clean this up
* please have at it , but this works . ' NE ' files will
* eventually fade away . JRR
*/
2018-05-01 21:38:49 +03:00
byte_count = printing_pread_data ( fsp , buf , & in_pos , VS_NE_BUF_SIZE ) ;
2018-05-01 01:50:14 +03:00
while ( byte_count > 0 ) {
/*
* Cover case that should not occur in a well
* formed ' NE ' . dll file
*/
if ( byte_count - VS_VERSION_INFO_SIZE < = 0 ) {
break ;
}
for ( i = 0 ; i < byte_count ; i + + ) {
/*
* Fast skip past data that can ' t
* possibly match
*/
if ( buf [ i ] ! = ' V ' ) {
2018-05-01 21:38:49 +03:00
byte_count = printing_pread_data ( fsp ,
2018-05-01 01:50:14 +03:00
buf ,
2018-05-01 21:38:49 +03:00
& in_pos ,
2018-05-01 01:50:14 +03:00
VS_NE_BUF_SIZE ) ;
continue ;
}
/*
* Potential match data crosses buf boundry ,
* move it to beginning of buf , and fill the
* buf with as much as it will hold .
*/
if ( i > byte_count - VS_VERSION_INFO_SIZE ) {
ssize_t amount_read ;
ssize_t amount_unused = byte_count - i ;
memmove ( buf , & buf [ i ] , amount_unused ) ;
2018-05-01 21:38:49 +03:00
amount_read = printing_pread_data ( fsp ,
2018-05-01 01:50:14 +03:00
& buf [ amount_unused ] ,
2018-05-01 21:38:49 +03:00
& in_pos ,
2018-05-01 01:50:14 +03:00
VS_NE_BUF_SIZE - amount_unused ) ;
if ( amount_read < 0 ) {
DBG_ERR ( " NE file [%s] Read "
" error, errno=%d \n " ,
fname ,
errno ) ;
goto out ;
}
if ( amount_read + amount_unused <
amount_read ) {
/* Check for integer wrap. */
break ;
}
byte_count = amount_read +
amount_unused ;
if ( byte_count < VS_VERSION_INFO_SIZE ) {
break ;
}
i = 0 ;
}
/*
* Check that the full signature string and
* the magic number that follows exist ( not
* a perfect solution , but the chances that this
* occurs in code is , well , remote . Yes I know
* I ' m comparing the ' V ' twice , as it is
* simpler to read the code .
*/
if ( strcmp ( & buf [ i ] , VS_SIGNATURE ) = = 0 ) {
/*
* Compute skip alignment to next
* long address .
*/
2018-05-01 21:19:49 +03:00
off_t cpos = in_pos ;
2018-05-01 01:50:14 +03:00
int skip = - ( cpos - ( byte_count - i ) +
sizeof ( VS_SIGNATURE ) ) & 3 ;
if ( IVAL ( buf ,
i + sizeof ( VS_SIGNATURE ) + skip )
! = 0xfeef04bd ) {
2018-05-01 21:38:49 +03:00
byte_count = printing_pread_data ( fsp ,
2018-05-01 01:50:14 +03:00
buf ,
2018-05-01 21:38:49 +03:00
& in_pos ,
2018-05-01 01:50:14 +03:00
VS_NE_BUF_SIZE ) ;
continue ;
}
* major = IVAL ( buf ,
i + sizeof ( VS_SIGNATURE ) +
skip + VS_MAJOR_OFFSET ) ;
* minor = IVAL ( buf ,
i + sizeof ( VS_SIGNATURE ) +
skip + VS_MINOR_OFFSET ) ;
DBG_INFO ( " NE file [%s] Version "
" = %08x:%08x (%d.%d.%d.%d) \n " ,
fname ,
* major ,
* minor ,
( * major > > 16 ) & 0xffff ,
* major & 0xffff ,
( * minor > > 16 ) & 0xffff ,
* minor & 0xffff ) ;
ret = 1 ;
goto out ;
}
}
}
/* Version info not found, fall back to origin date/time */
DBG_ERR ( " NE file [%s] Version info not found \n " , fname ) ;
ret = 0 ;
out :
SAFE_FREE ( buf ) ;
return ret ;
}
2000-07-25 17:15:16 +04:00
/****************************************************************************
2002-01-08 04:22:23 +03:00
Version information in Microsoft files is held in a VS_VERSION_INFO structure .
There are two case to be covered here : PE ( Portable Executable ) and NE ( New
Executable ) files . Both files support the same INFO structure , but PE files
store the signature in unicode , and NE files store it as ! unicode .
returns - 1 on error , 1 on version info found , and 0 on no version info found .
2000-07-25 17:15:16 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-01-08 04:22:23 +03:00
2018-04-30 21:57:52 +03:00
static int get_file_version ( files_struct * fsp ,
char * fname ,
uint32_t * major ,
uint32_t * minor )
2000-07-25 17:15:16 +04:00
{
2003-10-30 00:28:00 +03:00
char * buf = NULL ;
2001-08-10 23:38:53 +04:00
ssize_t byte_count ;
2018-05-01 21:08:40 +03:00
off_t in_pos = fsp - > fh - > pos ;
2018-04-30 21:57:52 +03:00
buf = ( char * ) SMB_MALLOC ( DOS_HEADER_SIZE ) ;
if ( buf = = NULL ) {
DBG_ERR ( " PE file [%s] DOS Header malloc failed bytes = %d \n " ,
fname ,
DOS_HEADER_SIZE ) ;
2000-10-25 21:56:38 +04:00
goto error_exit ;
}
2000-11-15 00:56:32 +03:00
2018-05-01 21:38:49 +03:00
byte_count = printing_pread_data ( fsp , buf , & in_pos , DOS_HEADER_SIZE ) ;
2018-04-30 21:57:52 +03:00
if ( byte_count < DOS_HEADER_SIZE ) {
DBG_NOTICE ( " File [%s] DOS header too short, bytes read = %lu \n " ,
fname ,
( unsigned long ) byte_count ) ;
2001-08-10 23:38:53 +04:00
goto no_version_info ;
2000-10-25 21:56:38 +04:00
}
/* Is this really a DOS header? */
if ( SVAL ( buf , DOS_HEADER_MAGIC_OFFSET ) ! = DOS_HEADER_MAGIC ) {
2018-04-30 21:57:52 +03:00
DBG_INFO ( " File [%s] bad DOS magic = 0x%x \n " ,
fname ,
SVAL ( buf , DOS_HEADER_MAGIC_OFFSET ) ) ;
2001-08-10 23:38:53 +04:00
goto no_version_info ;
2000-10-25 21:56:38 +04:00
}
2018-04-30 21:57:52 +03:00
/*
* Skip OEM header ( if any ) and the
* DOS stub to start of Windows header .
*/
2018-05-01 21:08:40 +03:00
in_pos = SVAL ( buf , DOS_HEADER_LFANEW_OFFSET ) ;
2000-10-25 21:56:38 +04:00
2007-03-19 20:45:13 +03:00
/* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */
2018-05-01 21:38:49 +03:00
byte_count = printing_pread_data ( fsp , buf , & in_pos , NE_HEADER_SIZE ) ;
2018-04-30 21:57:52 +03:00
if ( byte_count < NE_HEADER_SIZE ) {
DBG_NOTICE ( " File [%s] Windows header too short, "
" bytes read = %lu \n " ,
fname ,
( unsigned long ) byte_count ) ;
/*
* Assume this isn ' t an error . . .
* the file just looks sort of like a PE / NE file
*/
2001-08-10 23:38:53 +04:00
goto no_version_info ;
2000-10-25 21:56:38 +04:00
}
2018-04-30 21:57:52 +03:00
/*
* The header may be a PE ( Portable Executable )
* or an NE ( New Executable ) .
*/
2000-10-25 21:56:38 +04:00
if ( IVAL ( buf , PE_HEADER_SIGNATURE_OFFSET ) = = PE_HEADER_SIGNATURE ) {
2018-05-01 01:06:39 +03:00
return handle_pe_file ( fsp ,
2018-05-01 21:11:01 +03:00
in_pos ,
2018-05-01 01:06:39 +03:00
fname ,
buf ,
major ,
minor ) ;
2018-04-30 21:57:52 +03:00
} else if ( SVAL ( buf , NE_HEADER_SIGNATURE_OFFSET ) = =
NE_HEADER_SIGNATURE ) {
2018-05-01 01:50:14 +03:00
return handle_ne_file ( fsp ,
2018-05-01 21:11:01 +03:00
in_pos ,
2018-05-01 01:50:14 +03:00
fname ,
buf ,
major ,
minor ) ;
2018-04-30 21:57:52 +03:00
} else {
/*
* Assume this isn ' t an error . . . the file just
* looks sort of like a PE / NE file .
*/
DBG_NOTICE ( " File [%s] unknown file format, signature = 0x%x \n " ,
fname ,
IVAL ( buf , PE_HEADER_SIGNATURE_OFFSET ) ) ;
2018-05-01 01:50:14 +03:00
/* Fallthrough into no_version_info: */
2018-04-30 21:57:52 +03:00
}
2000-11-15 00:56:32 +03:00
no_version_info :
2001-09-17 13:25:57 +04:00
SAFE_FREE ( buf ) ;
2002-01-08 04:22:23 +03:00
return 0 ;
2000-11-15 00:56:32 +03:00
error_exit :
2001-09-17 13:25:57 +04:00
SAFE_FREE ( buf ) ;
2000-11-15 00:56:32 +03:00
return - 1 ;
}
/****************************************************************************
Drivers for Microsoft systems contain multiple files . Often , multiple drivers
share one or more files . During the MS installation process files are checked
to insure that only a newer version of a shared file is installed over an
older version . There are several possibilities for this comparison . If there
is no previous version , the new one is newer ( obviously ) . If either file is
missing the version info structure , compare the creation date ( on Unix use
the modification date ) . Otherwise chose the numerically larger version number .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-02-25 23:53:53 +03:00
static int file_version_is_newer ( connection_struct * conn , fstring new_file , fstring old_file )
2000-11-15 00:56:32 +03:00
{
2007-11-16 01:19:52 +03:00
bool use_version = true ;
2000-11-15 00:56:32 +03:00
2015-04-27 02:02:55 +03:00
uint32_t new_major ;
uint32_t new_minor ;
2000-11-15 00:56:32 +03:00
time_t new_create_time ;
2015-04-27 02:02:55 +03:00
uint32_t old_major ;
uint32_t old_minor ;
2000-11-15 00:56:32 +03:00
time_t old_create_time ;
2009-06-10 21:37:57 +04:00
struct smb_filename * smb_fname = NULL ;
2000-11-15 00:56:32 +03:00
files_struct * fsp = NULL ;
SMB_STRUCT_STAT st ;
2000-11-28 02:59:42 +03:00
2006-07-11 22:01:26 +04:00
NTSTATUS status ;
2009-06-10 21:37:57 +04:00
int ret ;
2006-07-11 22:01:26 +04:00
2005-06-03 03:18:52 +04:00
SET_STAT_INVALID ( st ) ;
2000-11-15 05:39:11 +03:00
new_create_time = ( time_t ) 0 ;
old_create_time = ( time_t ) 0 ;
2000-11-15 00:56:32 +03:00
/* Get file version info (if available) for previous file (if it exists) */
2009-06-10 21:37:57 +04:00
status = driver_unix_convert ( conn , old_file , & smb_fname ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto error_exit ;
}
2008-11-21 05:55:24 +03:00
status = SMB_VFS_CREATE_FILE (
conn , /* conn */
NULL , /* req */
0 , /* root_dir_fid */
2009-06-12 23:54:11 +04:00
smb_fname , /* fname */
2008-11-21 05:55:24 +03:00
FILE_GENERIC_READ , /* access_mask */
FILE_SHARE_READ | FILE_SHARE_WRITE , /* share_access */
FILE_OPEN , /* create_disposition*/
0 , /* create_options */
FILE_ATTRIBUTE_NORMAL , /* file_attributes */
INTERNAL_OPEN_ONLY , /* oplock_request */
2013-08-21 17:56:14 +04:00
NULL , /* lease */
2008-11-21 05:55:24 +03:00
0 , /* allocation_size */
2010-03-06 02:10:30 +03:00
0 , /* private_flags */
2008-11-21 05:55:24 +03:00
NULL , /* sd */
NULL , /* ea_list */
& fsp , /* result */
2014-11-26 16:12:51 +03:00
NULL , /* pinfo */
NULL , NULL ) ; /* create context */
2005-07-08 08:51:27 +04:00
2006-07-11 22:01:26 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2000-11-15 00:56:32 +03:00
/* Old file not found, so by definition new file is in fact newer */
2009-06-12 23:54:11 +04:00
DEBUG ( 10 , ( " file_version_is_newer: Can't open old file [%s], "
" errno = %d \n " , smb_fname_str_dbg ( smb_fname ) ,
errno ) ) ;
2009-06-10 21:37:57 +04:00
ret = 1 ;
goto done ;
2000-11-15 00:56:32 +03:00
} else {
2009-06-10 21:37:57 +04:00
ret = get_file_version ( fsp , old_file , & old_major , & old_minor ) ;
2005-07-08 08:51:27 +04:00
if ( ret = = - 1 ) {
goto error_exit ;
}
2000-11-15 00:56:32 +03:00
if ( ! ret ) {
DEBUG ( 6 , ( " file_version_is_newer: Version info not found [%s], use mod time \n " ,
old_file ) ) ;
2007-11-16 01:19:52 +03:00
use_version = false ;
2008-01-07 15:21:26 +03:00
if ( SMB_VFS_FSTAT ( fsp , & st ) = = - 1 ) {
2007-11-16 01:19:52 +03:00
goto error_exit ;
}
2009-05-14 17:34:42 +04:00
old_create_time = convert_timespec_to_time_t ( st . st_ex_mtime ) ;
2009-02-25 20:59:53 +03:00
DEBUGADD ( 6 , ( " file_version_is_newer: mod time = %ld sec \n " ,
( long ) old_create_time ) ) ;
2000-11-15 00:56:32 +03:00
}
}
2008-10-09 18:27:49 +04:00
close_file ( NULL , fsp , NORMAL_CLOSE ) ;
2008-09-29 21:09:53 +04:00
fsp = NULL ;
2000-11-15 00:56:32 +03:00
/* Get file version info (if available) for new file */
2009-06-10 21:37:57 +04:00
status = driver_unix_convert ( conn , new_file , & smb_fname ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto error_exit ;
}
2008-11-21 05:55:24 +03:00
status = SMB_VFS_CREATE_FILE (
conn , /* conn */
NULL , /* req */
0 , /* root_dir_fid */
2009-06-12 23:54:11 +04:00
smb_fname , /* fname */
2008-11-21 05:55:24 +03:00
FILE_GENERIC_READ , /* access_mask */
FILE_SHARE_READ | FILE_SHARE_WRITE , /* share_access */
FILE_OPEN , /* create_disposition*/
0 , /* create_options */
FILE_ATTRIBUTE_NORMAL , /* file_attributes */
INTERNAL_OPEN_ONLY , /* oplock_request */
2013-08-21 17:56:14 +04:00
NULL , /* lease */
2008-11-21 05:55:24 +03:00
0 , /* allocation_size */
2010-03-06 02:10:30 +03:00
0 , /* private_flags */
2008-11-21 05:55:24 +03:00
NULL , /* sd */
NULL , /* ea_list */
& fsp , /* result */
2014-11-26 16:12:51 +03:00
NULL , /* pinfo */
NULL , NULL ) ; /* create context */
2005-07-08 08:51:27 +04:00
2006-07-11 22:01:26 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2000-11-15 00:56:32 +03:00
/* New file not found, this shouldn't occur if the caller did its job */
2009-06-12 23:54:11 +04:00
DEBUG ( 3 , ( " file_version_is_newer: Can't open new file [%s], "
" errno = %d \n " , smb_fname_str_dbg ( smb_fname ) , errno ) ) ;
2000-11-15 00:56:32 +03:00
goto error_exit ;
} else {
2009-06-10 21:37:57 +04:00
ret = get_file_version ( fsp , new_file , & new_major , & new_minor ) ;
2005-07-08 08:51:27 +04:00
if ( ret = = - 1 ) {
goto error_exit ;
}
2000-11-15 00:56:32 +03:00
if ( ! ret ) {
DEBUG ( 6 , ( " file_version_is_newer: Version info not found [%s], use mod time \n " ,
new_file ) ) ;
2007-11-16 01:19:52 +03:00
use_version = false ;
2008-01-07 15:21:26 +03:00
if ( SMB_VFS_FSTAT ( fsp , & st ) = = - 1 ) {
2007-11-16 01:19:52 +03:00
goto error_exit ;
}
2009-05-14 17:34:42 +04:00
new_create_time = convert_timespec_to_time_t ( st . st_ex_mtime ) ;
2009-02-25 20:59:53 +03:00
DEBUGADD ( 6 , ( " file_version_is_newer: mod time = %ld sec \n " ,
( long ) new_create_time ) ) ;
2000-11-15 00:56:32 +03:00
}
}
2008-10-09 18:27:49 +04:00
close_file ( NULL , fsp , NORMAL_CLOSE ) ;
2008-09-29 21:57:22 +04:00
fsp = NULL ;
2000-11-15 00:56:32 +03:00
2002-08-17 20:31:24 +04:00
if ( use_version & & ( new_major ! = old_major | | new_minor ! = old_minor ) ) {
2000-11-15 00:56:32 +03:00
/* Compare versions and choose the larger version number */
if ( new_major > old_major | |
( new_major = = old_major & & new_minor > old_minor ) ) {
2007-11-16 01:19:52 +03:00
2000-11-15 00:56:32 +03:00
DEBUG ( 6 , ( " file_version_is_newer: Replacing [%s] with [%s] \n " , old_file , new_file ) ) ;
2009-06-10 21:37:57 +04:00
ret = 1 ;
goto done ;
2000-11-15 00:56:32 +03:00
}
else {
DEBUG ( 6 , ( " file_version_is_newer: Leaving [%s] unchanged \n " , old_file ) ) ;
2009-06-10 21:37:57 +04:00
ret = 0 ;
goto done ;
2000-11-15 00:56:32 +03:00
}
2001-08-10 23:38:53 +04:00
} else {
/* Compare modification time/dates and choose the newest time/date */
if ( new_create_time > old_create_time ) {
DEBUG ( 6 , ( " file_version_is_newer: Replacing [%s] with [%s] \n " , old_file , new_file ) ) ;
2009-06-10 21:37:57 +04:00
ret = 1 ;
goto done ;
2001-08-10 23:38:53 +04:00
}
else {
DEBUG ( 6 , ( " file_version_is_newer: Leaving [%s] unchanged \n " , old_file ) ) ;
2009-06-10 21:37:57 +04:00
ret = 0 ;
goto done ;
2001-08-10 23:38:53 +04:00
}
}
2009-06-10 21:37:57 +04:00
error_exit :
if ( fsp )
close_file ( NULL , fsp , NORMAL_CLOSE ) ;
ret = - 1 ;
done :
TALLOC_FREE ( smb_fname ) ;
return ret ;
2001-08-10 23:38:53 +04:00
}
/****************************************************************************
Determine the correct cVersion associated with an architecture and driver
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2018-05-24 18:40:27 +03:00
static uint32_t get_correct_cversion ( const struct auth_session_info * session_info ,
2008-11-24 01:01:24 +03:00
const char * architecture ,
2009-11-16 17:52:31 +03:00
const char * driverpath_in ,
2017-05-04 18:48:42 +03:00
const char * driver_directory ,
2008-11-24 01:01:24 +03:00
WERROR * perr )
2001-08-10 23:38:53 +04:00
{
2018-05-24 18:40:27 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2011-03-01 21:17:48 +03:00
int cversion = - 1 ;
2001-09-16 03:32:19 +04:00
NTSTATUS nt_status ;
2009-06-10 21:37:57 +04:00
struct smb_filename * smb_fname = NULL ;
2001-08-10 23:38:53 +04:00
files_struct * fsp = NULL ;
2018-05-24 18:55:02 +03:00
struct conn_struct_tos * c = NULL ;
2008-11-24 01:01:24 +03:00
connection_struct * conn = NULL ;
2010-11-10 02:07:49 +03:00
char * printdollar = NULL ;
2017-05-04 18:48:42 +03:00
char * printdollar_path = NULL ;
char * working_dir = NULL ;
2008-11-24 01:01:24 +03:00
int printdollar_snum ;
2001-08-10 23:38:53 +04:00
2015-12-03 17:24:24 +03:00
* perr = WERR_INVALID_PARAMETER ;
2001-12-29 23:29:43 +03:00
2001-08-10 23:38:53 +04:00
/* If architecture is Windows 95/98/ME, the version is always 0. */
2005-09-27 23:18:20 +04:00
if ( strcmp ( architecture , SPL_ARCH_WIN40 ) = = 0 ) {
2001-08-10 23:38:53 +04:00
DEBUG ( 10 , ( " get_correct_cversion: Driver is Win9x, cversion = 0 \n " ) ) ;
2001-12-29 23:29:43 +03:00
* perr = WERR_OK ;
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2001-08-10 23:38:53 +04:00
return 0 ;
}
2005-09-27 23:18:20 +04:00
/* If architecture is Windows x64, the version is always 3. */
if ( strcmp ( architecture , SPL_ARCH_X64 ) = = 0 ) {
DEBUG ( 10 , ( " get_correct_cversion: Driver is x64, cversion = 3 \n " ) ) ;
* perr = WERR_OK ;
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2005-09-27 23:18:20 +04:00
return 3 ;
}
2018-05-24 18:40:27 +03:00
printdollar_snum = find_service ( frame , " print$ " , & printdollar ) ;
2010-11-10 02:07:49 +03:00
if ( ! printdollar ) {
2015-12-03 17:24:14 +03:00
* perr = WERR_NOT_ENOUGH_MEMORY ;
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2010-11-10 02:07:49 +03:00
return - 1 ;
}
2008-11-24 01:01:24 +03:00
if ( printdollar_snum = = - 1 ) {
2015-12-03 17:24:23 +03:00
* perr = WERR_BAD_NET_NAME ;
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2001-08-10 23:38:53 +04:00
return - 1 ;
}
2018-05-24 18:40:27 +03:00
printdollar_path = lp_path ( frame , printdollar_snum ) ;
2017-05-04 18:48:42 +03:00
if ( printdollar_path = = NULL ) {
* perr = WERR_NOT_ENOUGH_MEMORY ;
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2017-05-04 18:48:42 +03:00
return - 1 ;
}
2018-05-24 18:40:27 +03:00
working_dir = talloc_asprintf ( frame ,
2017-05-04 18:48:42 +03:00
" %s/%s " ,
printdollar_path ,
architecture ) ;
/*
* If the driver has been uploaded into a temorpary driver
* directory , switch to the driver directory .
*/
if ( driver_directory ! = NULL ) {
2018-05-24 18:40:27 +03:00
working_dir = talloc_asprintf ( frame , " %s/%s/%s " ,
2017-05-04 18:48:42 +03:00
printdollar_path ,
architecture ,
driver_directory ) ;
}
2018-08-21 21:09:16 +03:00
nt_status = create_conn_struct_tos_cwd ( global_messaging_context ( ) ,
2018-05-24 18:55:02 +03:00
printdollar_snum ,
working_dir ,
session_info ,
& c ) ;
2008-11-24 01:01:24 +03:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
DEBUG ( 0 , ( " get_correct_cversion: create_conn_struct "
" returned %s \n " , nt_errstr ( nt_status ) ) ) ;
* perr = ntstatus_to_werror ( nt_status ) ;
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2001-08-10 23:38:53 +04:00
return - 1 ;
}
2018-05-24 18:55:02 +03:00
conn = c - > conn ;
2001-08-10 23:38:53 +04:00
2011-03-02 16:34:28 +03:00
nt_status = set_conn_force_user_group ( conn , printdollar_snum ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
DEBUG ( 0 , ( " failed set force user / group \n " ) ) ;
* perr = ntstatus_to_werror ( nt_status ) ;
goto error_free_conn ;
}
2011-04-30 02:09:09 +04:00
if ( ! become_user_by_session ( conn , session_info ) ) {
2011-03-02 16:34:28 +03:00
DEBUG ( 0 , ( " failed to become user \n " ) ) ;
* perr = WERR_ACCESS_DENIED ;
goto error_free_conn ;
}
2017-05-04 18:48:42 +03:00
/*
* We switch to the directory where the driver files are located ,
* so only work on the file names
*/
nt_status = driver_unix_convert ( conn , driverpath_in , & smb_fname ) ;
2009-06-10 21:37:57 +04:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
* perr = ntstatus_to_werror ( nt_status ) ;
2007-11-16 01:19:52 +03:00
goto error_exit ;
}
2001-08-10 23:38:53 +04:00
2009-06-10 21:37:57 +04:00
nt_status = vfs_file_exist ( conn , smb_fname ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
2010-08-31 18:58:54 +04:00
DEBUG ( 3 , ( " get_correct_cversion: vfs_file_exist failed \n " ) ) ;
2015-12-03 17:24:11 +03:00
* perr = WERR_FILE_NOT_FOUND ;
2005-06-15 23:28:14 +04:00
goto error_exit ;
}
2011-03-01 21:17:48 +03:00
nt_status = SMB_VFS_CREATE_FILE (
2008-11-21 05:55:24 +03:00
conn , /* conn */
NULL , /* req */
0 , /* root_dir_fid */
2009-06-12 23:54:11 +04:00
smb_fname , /* fname */
2008-11-21 05:55:24 +03:00
FILE_GENERIC_READ , /* access_mask */
FILE_SHARE_READ | FILE_SHARE_WRITE , /* share_access */
FILE_OPEN , /* create_disposition*/
0 , /* create_options */
FILE_ATTRIBUTE_NORMAL , /* file_attributes */
INTERNAL_OPEN_ONLY , /* oplock_request */
2013-08-21 17:56:14 +04:00
NULL , /* lease */
2010-03-06 02:10:30 +03:00
0 , /* private_flags */
2008-11-21 05:55:24 +03:00
0 , /* allocation_size */
NULL , /* sd */
NULL , /* ea_list */
& fsp , /* result */
2014-11-26 16:12:51 +03:00
NULL , /* pinfo */
NULL , NULL ) ; /* create context */
2005-06-15 23:28:14 +04:00
2011-03-01 21:17:48 +03:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
2009-06-12 23:54:11 +04:00
DEBUG ( 3 , ( " get_correct_cversion: Can't open file [%s], errno = "
" %d \n " , smb_fname_str_dbg ( smb_fname ) , errno ) ) ;
2001-09-04 11:13:01 +04:00
* perr = WERR_ACCESS_DENIED ;
2001-08-10 23:38:53 +04:00
goto error_exit ;
2005-07-08 08:51:27 +04:00
} else {
2015-04-27 02:02:55 +03:00
uint32_t major ;
uint32_t minor ;
2009-06-12 23:54:11 +04:00
int ret ;
ret = get_file_version ( fsp , smb_fname - > base_name , & major , & minor ) ;
2011-03-01 21:17:48 +03:00
if ( ret = = - 1 ) {
2015-12-03 17:24:24 +03:00
* perr = WERR_INVALID_PARAMETER ;
2011-03-01 21:17:48 +03:00
goto error_exit ;
} else if ( ! ret ) {
2009-06-12 23:54:11 +04:00
DEBUG ( 6 , ( " get_correct_cversion: Version info not "
" found [%s] \n " ,
smb_fname_str_dbg ( smb_fname ) ) ) ;
2015-12-03 17:24:24 +03:00
* perr = WERR_INVALID_PARAMETER ;
2001-08-10 23:38:53 +04:00
goto error_exit ;
}
/*
* This is a Microsoft ' ism . See references in MSDN to VER_FILEVERSION
2009-02-09 14:40:12 +03:00
* for more details . Version in this case is not just the version of the
2001-08-10 23:38:53 +04:00
* file , but the version in the sense of kernal mode ( 2 ) vs . user mode
2009-02-09 14:40:12 +03:00
* ( 3 ) drivers . Other bits of the version fields are the version info .
2001-08-10 23:38:53 +04:00
* JRR 010716
*/
cversion = major & 0x0000ffff ;
switch ( cversion ) {
case 2 : /* WinNT drivers */
case 3 : /* Win2K drivers */
break ;
2009-02-09 14:40:12 +03:00
2001-08-10 23:38:53 +04:00
default :
2009-06-12 23:54:11 +04:00
DEBUG ( 6 , ( " get_correct_cversion: cversion "
" invalid [%s] cversion = %d \n " ,
smb_fname_str_dbg ( smb_fname ) ,
cversion ) ) ;
2001-08-10 23:38:53 +04:00
goto error_exit ;
}
2009-06-12 23:54:11 +04:00
DEBUG ( 10 , ( " get_correct_cversion: Version info found [%s] major "
" = 0x%x minor = 0x%x \n " ,
smb_fname_str_dbg ( smb_fname ) , major , minor ) ) ;
2001-08-10 23:38:53 +04:00
}
2005-06-15 23:28:14 +04:00
DEBUG ( 10 , ( " get_correct_cversion: Driver file [%s] cversion = %d \n " ,
2009-06-12 23:54:11 +04:00
smb_fname_str_dbg ( smb_fname ) , cversion ) ) ;
2011-03-01 21:17:48 +03:00
* perr = WERR_OK ;
2001-08-10 23:38:53 +04:00
2008-11-24 01:01:24 +03:00
error_exit :
2011-03-02 16:34:28 +03:00
unbecome_user ( ) ;
error_free_conn :
2008-11-24 01:01:24 +03:00
if ( fsp ! = NULL ) {
2008-10-09 18:27:49 +04:00
close_file ( NULL , fsp , NORMAL_CLOSE ) ;
2008-11-24 01:01:24 +03:00
}
2012-01-24 00:18:01 +04:00
if ( ! W_ERROR_IS_OK ( * perr ) ) {
2011-03-01 21:17:48 +03:00
cversion = - 1 ;
2008-11-24 01:01:24 +03:00
}
2011-03-01 21:17:48 +03:00
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2008-11-24 01:01:24 +03:00
return cversion ;
2001-08-10 23:38:53 +04:00
}
/****************************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-11-16 17:52:31 +03:00
# define strip_driver_path(_mem_ctx, _element) do { \
2010-04-23 04:34:43 +04:00
if ( _element & & ( ( _p = strrchr ( ( _element ) , ' \\ ' ) ) ! = NULL ) ) { \
2009-11-26 01:47:36 +03:00
( _element ) = talloc_asprintf ( ( _mem_ctx ) , " %s " , _p + 1 ) ; \
W_ERROR_HAVE_NO_MEMORY ( ( _element ) ) ; \
2009-11-16 17:52:31 +03:00
} \
} while ( 0 ) ;
2009-11-23 14:57:46 +03:00
static WERROR clean_up_driver_struct_level ( TALLOC_CTX * mem_ctx ,
2018-05-24 18:40:27 +03:00
const struct auth_session_info * session_info ,
2009-11-23 14:57:46 +03:00
const char * architecture ,
const char * * driver_path ,
const char * * data_file ,
const char * * config_file ,
const char * * help_file ,
struct spoolss_StringArray * dependent_files ,
2016-11-15 16:29:29 +03:00
enum spoolss_DriverOSVersion * version ,
uint32_t flags ,
const char * * driver_directory )
2001-08-10 23:38:53 +04:00
{
2009-11-23 14:57:46 +03:00
const char * short_architecture ;
2001-08-10 23:38:53 +04:00
int i ;
2001-09-04 11:13:01 +04:00
WERROR err ;
2009-11-16 17:52:31 +03:00
char * _p ;
2001-08-10 23:38:53 +04:00
2010-11-29 19:56:40 +03:00
if ( ! * driver_path | | ! * data_file ) {
2015-12-03 17:24:24 +03:00
return WERR_INVALID_PARAMETER ;
2010-11-29 19:56:40 +03:00
}
if ( ! strequal ( architecture , SPOOLSS_ARCHITECTURE_4_0 ) & & ! * config_file ) {
2015-12-03 17:24:24 +03:00
return WERR_INVALID_PARAMETER ;
2010-04-23 04:34:43 +04:00
}
2016-11-15 16:29:29 +03:00
if ( flags & APD_COPY_FROM_DIRECTORY ) {
char * path ;
char * q ;
/*
* driver_path is set to :
*
* \ \ PRINTSRV \ print $ \ x64 \ { 279245 b0 - a8bd - 4431 - bf6f - baee92ac15c0 } \ pscript5 . dll
*/
path = talloc_strdup ( mem_ctx , * driver_path ) ;
if ( path = = NULL ) {
return WERR_NOT_ENOUGH_MEMORY ;
}
/* Remove pscript5.dll */
q = strrchr_m ( path , ' \\ ' ) ;
if ( q = = NULL ) {
return WERR_INVALID_PARAMETER ;
}
* q = ' \0 ' ;
/* Get \{279245b0-a8bd-4431-bf6f-baee92ac15c0} */
q = strrchr_m ( path , ' \\ ' ) ;
if ( q = = NULL ) {
return WERR_INVALID_PARAMETER ;
}
/*
* Set driver_directory to :
*
* { 279245 b0 - a8bd - 4431 - bf6f - baee92ac15c0 }
*
* This is the directory where all the files have been uploaded
*/
* driver_directory = q + 1 ;
}
2001-08-10 23:38:53 +04:00
/* clean up the driver name.
* we can get . \ driver . dll
* or worse c : \ windows \ system \ driver . dll !
*/
/* using an intermediate string to not have overlaping memcpy()'s */
2009-11-23 14:57:46 +03:00
strip_driver_path ( mem_ctx , * driver_path ) ;
strip_driver_path ( mem_ctx , * data_file ) ;
2010-11-29 19:56:40 +03:00
if ( * config_file ) {
strip_driver_path ( mem_ctx , * config_file ) ;
}
2010-04-23 04:34:43 +04:00
if ( help_file ) {
strip_driver_path ( mem_ctx , * help_file ) ;
}
2001-08-10 23:38:53 +04:00
2009-11-23 14:57:46 +03:00
if ( dependent_files & & dependent_files - > string ) {
for ( i = 0 ; dependent_files - > string [ i ] ; i + + ) {
strip_driver_path ( mem_ctx , dependent_files - > string [ i ] ) ;
2001-08-10 23:38:53 +04:00
}
}
2009-11-23 14:57:46 +03:00
short_architecture = get_short_archi ( architecture ) ;
if ( ! short_architecture ) {
2006-06-20 01:36:19 +04:00
return WERR_UNKNOWN_PRINTER_DRIVER ;
}
2009-02-09 14:40:12 +03:00
2001-08-10 23:38:53 +04:00
/* jfm:7/16/2000 the client always sends the cversion=0.
* The server should check which version the driver is by reading
* the PE header of driver - > driverpath .
*
* For Windows 95 / 98 the version is 0 ( so the value sent is correct )
* For Windows NT ( the architecture doesn ' t matter )
* NT 3.1 : cversion = 0
* NT 3.5 / 3.51 : cversion = 1
* NT 4 : cversion = 2
* NT2K : cversion = 3
*/
2009-11-16 17:52:31 +03:00
2017-05-04 18:48:42 +03:00
* version = get_correct_cversion ( session_info ,
short_architecture ,
* driver_path ,
* driver_directory ,
& err ) ;
2009-11-23 14:57:46 +03:00
if ( * version = = - 1 ) {
2006-06-20 01:36:19 +04:00
return err ;
2001-08-10 23:38:53 +04:00
}
2001-09-04 11:13:01 +04:00
return WERR_OK ;
2001-08-10 23:38:53 +04:00
}
/****************************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-11-23 14:57:46 +03:00
2010-06-16 13:44:36 +04:00
WERROR clean_up_driver_struct ( TALLOC_CTX * mem_ctx ,
2018-05-24 18:40:27 +03:00
const struct auth_session_info * session_info ,
const struct spoolss_AddDriverInfoCtr * r ,
2016-11-15 16:29:29 +03:00
uint32_t flags ,
const char * * driver_directory )
2001-08-10 23:38:53 +04:00
{
2009-11-16 17:52:31 +03:00
switch ( r - > level ) {
case 3 :
2011-04-30 02:09:09 +04:00
return clean_up_driver_struct_level ( mem_ctx , session_info ,
2009-11-23 14:57:46 +03:00
r - > info . info3 - > architecture ,
& r - > info . info3 - > driver_path ,
& r - > info . info3 - > data_file ,
& r - > info . info3 - > config_file ,
& r - > info . info3 - > help_file ,
r - > info . info3 - > dependent_files ,
2016-11-15 16:29:29 +03:00
& r - > info . info3 - > version ,
flags ,
driver_directory ) ;
2009-11-16 17:52:31 +03:00
case 6 :
2011-04-30 02:09:09 +04:00
return clean_up_driver_struct_level ( mem_ctx , session_info ,
2009-11-23 14:57:46 +03:00
r - > info . info6 - > architecture ,
& r - > info . info6 - > driver_path ,
& r - > info . info6 - > data_file ,
& r - > info . info6 - > config_file ,
& r - > info . info6 - > help_file ,
r - > info . info6 - > dependent_files ,
2016-11-15 16:29:29 +03:00
& r - > info . info6 - > version ,
flags ,
driver_directory ) ;
2016-08-18 11:26:10 +03:00
case 8 :
return clean_up_driver_struct_level ( mem_ctx , session_info ,
r - > info . info8 - > architecture ,
& r - > info . info8 - > driver_path ,
& r - > info . info8 - > data_file ,
& r - > info . info8 - > config_file ,
& r - > info . info8 - > help_file ,
r - > info . info8 - > dependent_files ,
2016-11-15 16:29:29 +03:00
& r - > info . info8 - > version ,
flags ,
driver_directory ) ;
2009-11-16 17:52:31 +03:00
default :
return WERR_NOT_SUPPORTED ;
2000-11-15 00:56:32 +03:00
}
2001-08-10 23:38:53 +04:00
}
2000-11-15 00:56:32 +03:00
2001-08-10 23:38:53 +04:00
/****************************************************************************
This function sucks and should be replaced . JRA .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-11-16 17:52:31 +03:00
static void convert_level_6_to_level3 ( struct spoolss_AddDriverInfo3 * dst ,
const struct spoolss_AddDriverInfo6 * src )
2001-08-10 23:38:53 +04:00
{
2009-11-16 17:52:31 +03:00
dst - > version = src - > version ;
dst - > driver_name = src - > driver_name ;
dst - > architecture = src - > architecture ;
dst - > driver_path = src - > driver_path ;
dst - > data_file = src - > data_file ;
dst - > config_file = src - > config_file ;
dst - > help_file = src - > help_file ;
dst - > monitor_name = src - > monitor_name ;
dst - > default_datatype = src - > default_datatype ;
dst - > _ndr_size_dependent_files = src - > _ndr_size_dependent_files ;
dst - > dependent_files = src - > dependent_files ;
2001-08-10 23:38:53 +04:00
}
2016-08-18 11:26:10 +03:00
static void convert_level_8_to_level3 ( struct spoolss_AddDriverInfo3 * dst ,
const struct spoolss_AddDriverInfo8 * src )
{
dst - > version = src - > version ;
dst - > driver_name = src - > driver_name ;
dst - > architecture = src - > architecture ;
dst - > driver_path = src - > driver_path ;
dst - > data_file = src - > data_file ;
dst - > config_file = src - > config_file ;
dst - > help_file = src - > help_file ;
dst - > monitor_name = src - > monitor_name ;
dst - > default_datatype = src - > default_datatype ;
dst - > _ndr_size_dependent_files = src - > _ndr_size_dependent_files ;
dst - > dependent_files = src - > dependent_files ;
}
2000-11-15 00:56:32 +03:00
/****************************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-04-30 03:07:31 +04:00
static WERROR move_driver_file_to_download_area ( TALLOC_CTX * mem_ctx ,
connection_struct * conn ,
const char * driver_file ,
2009-04-30 18:49:50 +04:00
const char * short_architecture ,
uint32_t driver_version ,
2016-11-15 16:29:29 +03:00
uint32_t version ,
const char * driver_directory )
2009-04-30 03:07:31 +04:00
{
2009-06-10 21:37:57 +04:00
struct smb_filename * smb_fname_old = NULL ;
struct smb_filename * smb_fname_new = NULL ;
2009-04-30 03:07:31 +04:00
char * old_name = NULL ;
char * new_name = NULL ;
NTSTATUS status ;
2009-06-10 21:37:57 +04:00
WERROR ret ;
2009-04-30 03:07:31 +04:00
2016-11-15 16:29:29 +03:00
if ( driver_directory ! = NULL ) {
old_name = talloc_asprintf ( mem_ctx ,
" %s/%s/%s " ,
short_architecture ,
driver_directory ,
driver_file ) ;
} else {
old_name = talloc_asprintf ( mem_ctx ,
" %s/%s " ,
short_architecture ,
driver_file ) ;
}
if ( old_name = = NULL ) {
return WERR_NOT_ENOUGH_MEMORY ;
}
2009-04-30 03:07:31 +04:00
2009-04-30 18:49:50 +04:00
new_name = talloc_asprintf ( mem_ctx , " %s/%d/%s " ,
short_architecture , driver_version , driver_file ) ;
2009-06-15 09:45:47 +04:00
if ( new_name = = NULL ) {
TALLOC_FREE ( old_name ) ;
2015-12-03 17:24:14 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2009-06-15 09:45:47 +04:00
}
2009-04-30 18:49:50 +04:00
if ( version ! = - 1 & & ( version = file_version_is_newer ( conn , old_name , new_name ) ) > 0 ) {
2009-06-10 21:37:57 +04:00
status = driver_unix_convert ( conn , old_name , & smb_fname_old ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2015-12-03 17:24:14 +03:00
ret = WERR_NOT_ENOUGH_MEMORY ;
2009-06-10 21:37:57 +04:00
goto out ;
}
/* Setup a synthetic smb_filename struct */
2011-06-07 05:44:43 +04:00
smb_fname_new = talloc_zero ( mem_ctx , struct smb_filename ) ;
2009-06-10 21:37:57 +04:00
if ( ! smb_fname_new ) {
2015-12-03 17:24:14 +03:00
ret = WERR_NOT_ENOUGH_MEMORY ;
2009-06-10 21:37:57 +04:00
goto out ;
}
smb_fname_new - > base_name = new_name ;
2009-04-30 03:07:31 +04:00
2009-06-10 21:37:57 +04:00
DEBUG ( 10 , ( " move_driver_file_to_download_area: copying '%s' to "
" '%s' \n " , smb_fname_old - > base_name ,
smb_fname_new - > base_name ) ) ;
2009-04-30 03:07:31 +04:00
2009-06-10 21:37:57 +04:00
status = copy_file ( mem_ctx , conn , smb_fname_old , smb_fname_new ,
2009-04-30 03:07:31 +04:00
OPENX_FILE_EXISTS_TRUNCATE |
OPENX_FILE_CREATE_IF_NOT_EXIST ,
0 , false ) ;
2009-04-30 18:49:50 +04:00
2009-04-30 03:07:31 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-06-10 21:37:57 +04:00
DEBUG ( 0 , ( " move_driver_file_to_download_area: Unable "
" to rename [%s] to [%s]: %s \n " ,
smb_fname_old - > base_name , new_name ,
nt_errstr ( status ) ) ) ;
2018-04-19 17:14:38 +03:00
ret = WERR_APP_INIT_FAILURE ;
2009-06-10 21:37:57 +04:00
goto out ;
2009-04-30 03:07:31 +04:00
}
}
2009-06-10 21:37:57 +04:00
ret = WERR_OK ;
out :
TALLOC_FREE ( smb_fname_old ) ;
TALLOC_FREE ( smb_fname_new ) ;
return ret ;
2009-04-30 03:07:31 +04:00
}
2018-05-24 18:40:27 +03:00
WERROR move_driver_to_download_area ( const struct auth_session_info * session_info ,
const struct spoolss_AddDriverInfoCtr * r ,
2016-11-15 16:29:29 +03:00
const char * driver_directory )
2000-07-25 17:15:16 +04:00
{
2018-05-24 18:40:27 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2009-11-16 17:52:31 +03:00
struct spoolss_AddDriverInfo3 * driver ;
struct spoolss_AddDriverInfo3 converted_driver ;
2009-04-30 18:49:50 +04:00
const char * short_architecture ;
2009-06-10 21:37:57 +04:00
struct smb_filename * smb_dname = NULL ;
2007-11-16 01:19:52 +03:00
char * new_dir = NULL ;
2018-05-24 18:55:02 +03:00
struct conn_struct_tos * c = NULL ;
2008-11-24 00:46:08 +03:00
connection_struct * conn = NULL ;
2001-09-16 03:32:19 +04:00
NTSTATUS nt_status ;
2000-07-25 17:15:16 +04:00
int i ;
2007-11-16 01:19:52 +03:00
int ver = 0 ;
2010-11-10 02:07:49 +03:00
char * printdollar = NULL ;
2008-11-24 00:46:08 +03:00
int printdollar_snum ;
2011-03-01 21:17:47 +03:00
WERROR err = WERR_OK ;
2000-08-31 01:09:21 +04:00
2009-11-16 17:52:31 +03:00
switch ( r - > level ) {
2009-04-30 18:49:50 +04:00
case 3 :
2009-11-16 17:52:31 +03:00
driver = r - > info . info3 ;
2009-04-30 18:49:50 +04:00
break ;
case 6 :
2009-11-16 17:52:31 +03:00
convert_level_6_to_level3 ( & converted_driver , r - > info . info6 ) ;
2000-09-07 03:20:35 +04:00
driver = & converted_driver ;
2009-04-30 18:49:50 +04:00
break ;
2016-08-18 11:26:10 +03:00
case 8 :
convert_level_8_to_level3 ( & converted_driver , r - > info . info8 ) ;
driver = & converted_driver ;
break ;
2009-04-30 18:49:50 +04:00
default :
2009-11-16 17:52:31 +03:00
DEBUG ( 0 , ( " move_driver_to_download_area: Unknown info level (%u) \n " , ( unsigned int ) r - > level ) ) ;
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2015-12-03 17:24:42 +03:00
return WERR_INVALID_LEVEL ;
2000-09-07 03:20:35 +04:00
}
2009-11-16 17:52:31 +03:00
short_architecture = get_short_archi ( driver - > architecture ) ;
2009-04-30 18:49:50 +04:00
if ( ! short_architecture ) {
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2006-06-20 01:36:19 +04:00
return WERR_UNKNOWN_PRINTER_DRIVER ;
}
2000-07-25 17:15:16 +04:00
2018-05-24 18:40:27 +03:00
printdollar_snum = find_service ( frame , " print$ " , & printdollar ) ;
2010-11-10 02:07:49 +03:00
if ( ! printdollar ) {
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2015-12-03 17:24:14 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2010-11-10 02:07:49 +03:00
}
2008-11-24 00:46:08 +03:00
if ( printdollar_snum = = - 1 ) {
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2015-12-03 17:24:23 +03:00
return WERR_BAD_NET_NAME ;
2000-07-26 02:35:57 +04:00
}
2018-08-21 21:09:16 +03:00
nt_status = create_conn_struct_tos_cwd ( global_messaging_context ( ) ,
2018-05-24 18:55:02 +03:00
printdollar_snum ,
lp_path ( frame , printdollar_snum ) ,
session_info ,
& c ) ;
2008-11-24 00:46:08 +03:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
DEBUG ( 0 , ( " move_driver_to_download_area: create_conn_struct "
" returned %s \n " , nt_errstr ( nt_status ) ) ) ;
2011-03-01 21:17:47 +03:00
err = ntstatus_to_werror ( nt_status ) ;
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2011-03-01 21:17:47 +03:00
return err ;
2000-07-25 21:09:29 +04:00
}
2018-05-24 18:55:02 +03:00
conn = c - > conn ;
2000-07-25 21:09:29 +04:00
2011-03-02 16:34:28 +03:00
nt_status = set_conn_force_user_group ( conn , printdollar_snum ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
DEBUG ( 0 , ( " failed set force user / group \n " ) ) ;
err = ntstatus_to_werror ( nt_status ) ;
goto err_free_conn ;
}
2011-04-30 02:09:09 +04:00
if ( ! become_user_by_session ( conn , session_info ) ) {
2011-03-02 16:34:28 +03:00
DEBUG ( 0 , ( " failed to become user \n " ) ) ;
err = WERR_ACCESS_DENIED ;
goto err_free_conn ;
}
2018-05-24 18:40:27 +03:00
new_dir = talloc_asprintf ( frame ,
2007-11-16 01:19:52 +03:00
" %s/%d " ,
2009-04-30 18:49:50 +04:00
short_architecture ,
2009-11-16 17:52:31 +03:00
driver - > version ) ;
2007-11-16 01:19:52 +03:00
if ( ! new_dir ) {
2015-12-03 17:24:14 +03:00
err = WERR_NOT_ENOUGH_MEMORY ;
2007-11-16 01:19:52 +03:00
goto err_exit ;
}
2009-06-10 21:37:57 +04:00
nt_status = driver_unix_convert ( conn , new_dir , & smb_dname ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
2015-12-03 17:24:14 +03:00
err = WERR_NOT_ENOUGH_MEMORY ;
2007-11-16 01:19:52 +03:00
goto err_exit ;
}
2009-06-10 21:37:57 +04:00
DEBUG ( 5 , ( " Creating first directory: %s \n " , smb_dname - > base_name ) ) ;
2009-04-30 18:49:50 +04:00
2011-03-01 21:17:47 +03:00
nt_status = create_directory ( conn , NULL , smb_dname ) ;
if ( ! NT_STATUS_IS_OK ( nt_status )
& & ! NT_STATUS_EQUAL ( nt_status , NT_STATUS_OBJECT_NAME_COLLISION ) ) {
DEBUG ( 0 , ( " failed to create driver destination directory: %s \n " ,
nt_errstr ( nt_status ) ) ) ;
err = ntstatus_to_werror ( nt_status ) ;
goto err_exit ;
}
2000-07-25 17:15:16 +04:00
2000-11-15 00:56:32 +03:00
/* For each driver file, archi\filexxx.yyy, if there is a duplicate file
* listed for this driver which has already been moved , skip it ( note :
* drivers may list the same file name several times . Then check if the
2009-11-16 17:52:31 +03:00
* file already exists in archi \ version \ , if so , check that the version
2000-11-15 00:56:32 +03:00
* info ( or time stamps if version info is unavailable ) is newer ( or the
2009-11-16 17:52:31 +03:00
* date is later ) . If it is , move it to archi \ version \ filexxx . yyy .
2000-11-15 00:56:32 +03:00
* Otherwise , delete the file .
2000-08-01 00:41:51 +04:00
*
2009-11-16 17:52:31 +03:00
* If a file is not moved to archi \ version \ because of an error , all the
2000-11-15 00:56:32 +03:00
* rest of the ' unmoved ' driver files are removed from archi \ . If one or
2009-11-16 17:52:31 +03:00
* more of the driver ' s files was already moved to archi \ version \ , it
2000-11-15 00:56:32 +03:00
* potentially leaves the driver in a partially updated state . Version
* trauma will most likely occur if an client attempts to use any printer
* bound to the driver . Perhaps a rewrite to make sure the moves can be
* done is appropriate . . . later JRR
2000-07-25 17:15:16 +04:00
*/
2000-11-15 00:56:32 +03:00
DEBUG ( 5 , ( " Moving files now ! \n " ) ) ;
2000-10-25 21:56:38 +04:00
2009-11-16 17:52:31 +03:00
if ( driver - > driver_path & & strlen ( driver - > driver_path ) ) {
2007-11-16 01:19:52 +03:00
2018-05-24 18:40:27 +03:00
err = move_driver_file_to_download_area ( frame ,
2011-03-01 21:17:47 +03:00
conn ,
driver - > driver_path ,
short_architecture ,
driver - > version ,
2016-11-15 16:29:29 +03:00
ver ,
driver_directory ) ;
2011-03-01 21:17:47 +03:00
if ( ! W_ERROR_IS_OK ( err ) ) {
2009-04-30 03:25:23 +04:00
goto err_exit ;
2007-11-16 01:19:52 +03:00
}
2000-10-25 21:56:38 +04:00
}
2000-07-25 17:15:16 +04:00
2009-11-16 17:52:31 +03:00
if ( driver - > data_file & & strlen ( driver - > data_file ) ) {
if ( ! strequal ( driver - > data_file , driver - > driver_path ) ) {
2009-04-30 03:25:23 +04:00
2018-05-24 18:40:27 +03:00
err = move_driver_file_to_download_area ( frame ,
2011-03-01 21:17:47 +03:00
conn ,
driver - > data_file ,
short_architecture ,
driver - > version ,
2016-11-15 16:29:29 +03:00
ver ,
driver_directory ) ;
2011-03-01 21:17:47 +03:00
if ( ! W_ERROR_IS_OK ( err ) ) {
2009-04-30 03:25:23 +04:00
goto err_exit ;
2004-05-03 20:38:37 +04:00
}
2000-08-09 22:40:48 +04:00
}
2000-08-01 00:41:51 +04:00
}
2000-07-25 17:15:16 +04:00
2009-11-16 17:52:31 +03:00
if ( driver - > config_file & & strlen ( driver - > config_file ) ) {
if ( ! strequal ( driver - > config_file , driver - > driver_path ) & &
! strequal ( driver - > config_file , driver - > data_file ) ) {
2009-04-30 03:25:23 +04:00
2018-05-24 18:40:27 +03:00
err = move_driver_file_to_download_area ( frame ,
2011-03-01 21:17:47 +03:00
conn ,
driver - > config_file ,
short_architecture ,
driver - > version ,
2016-11-15 16:29:29 +03:00
ver ,
driver_directory ) ;
2011-03-01 21:17:47 +03:00
if ( ! W_ERROR_IS_OK ( err ) ) {
2009-04-30 03:25:23 +04:00
goto err_exit ;
2004-05-03 20:38:37 +04:00
}
2000-08-09 22:40:48 +04:00
}
2000-08-01 00:41:51 +04:00
}
2000-07-25 17:15:16 +04:00
2009-11-16 17:52:31 +03:00
if ( driver - > help_file & & strlen ( driver - > help_file ) ) {
if ( ! strequal ( driver - > help_file , driver - > driver_path ) & &
! strequal ( driver - > help_file , driver - > data_file ) & &
! strequal ( driver - > help_file , driver - > config_file ) ) {
2009-04-30 03:25:23 +04:00
2018-05-24 18:40:27 +03:00
err = move_driver_file_to_download_area ( frame ,
2011-03-01 21:17:47 +03:00
conn ,
driver - > help_file ,
short_architecture ,
driver - > version ,
2016-11-15 16:29:29 +03:00
ver ,
driver_directory ) ;
2011-03-01 21:17:47 +03:00
if ( ! W_ERROR_IS_OK ( err ) ) {
2009-04-30 03:25:23 +04:00
goto err_exit ;
2004-05-03 20:38:37 +04:00
}
2000-08-09 22:40:48 +04:00
}
2000-08-01 00:41:51 +04:00
}
2000-07-25 17:15:16 +04:00
2009-11-16 17:52:31 +03:00
if ( driver - > dependent_files & & driver - > dependent_files - > string ) {
for ( i = 0 ; driver - > dependent_files - > string [ i ] ; i + + ) {
if ( ! strequal ( driver - > dependent_files - > string [ i ] , driver - > driver_path ) & &
! strequal ( driver - > dependent_files - > string [ i ] , driver - > data_file ) & &
! strequal ( driver - > dependent_files - > string [ i ] , driver - > config_file ) & &
! strequal ( driver - > dependent_files - > string [ i ] , driver - > help_file ) ) {
2000-08-22 10:28:33 +04:00
int j ;
for ( j = 0 ; j < i ; j + + ) {
2009-11-16 17:52:31 +03:00
if ( strequal ( driver - > dependent_files - > string [ i ] , driver - > dependent_files - > string [ j ] ) ) {
2000-08-22 10:28:33 +04:00
goto NextDriver ;
}
}
2018-05-24 18:40:27 +03:00
err = move_driver_file_to_download_area ( frame ,
2011-03-01 21:17:47 +03:00
conn ,
driver - > dependent_files - > string [ i ] ,
short_architecture ,
driver - > version ,
2016-11-15 16:29:29 +03:00
ver ,
driver_directory ) ;
2011-03-01 21:17:47 +03:00
if ( ! W_ERROR_IS_OK ( err ) ) {
2009-04-30 03:25:23 +04:00
goto err_exit ;
2004-05-03 20:38:37 +04:00
}
2000-08-01 00:41:51 +04:00
}
2000-09-27 03:28:04 +04:00
NextDriver : ;
2000-07-25 17:15:16 +04:00
}
}
2011-03-01 21:17:47 +03:00
err = WERR_OK ;
2011-03-02 16:34:28 +03:00
err_exit :
unbecome_user ( ) ;
err_free_conn :
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2011-03-01 21:17:47 +03:00
return err ;
2000-02-07 19:17:59 +03:00
}
2001-05-18 08:11:17 +04:00
/****************************************************************************
Determine whether or not a particular driver is currently assigned
to a printer
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-07-15 14:35:28 +04:00
2010-04-15 04:48:00 +04:00
bool printer_driver_in_use ( TALLOC_CTX * mem_ctx ,
2011-07-28 13:34:08 +04:00
struct dcerpc_binding_handle * b ,
const struct spoolss_DriverInfo8 * r )
2001-05-18 08:11:17 +04:00
{
2002-07-15 14:35:28 +04:00
int snum ;
int n_services = lp_numservices ( ) ;
2017-01-10 20:25:22 +03:00
bool in_use = false ;
2010-04-26 22:46:33 +04:00
struct spoolss_PrinterInfo2 * pinfo2 = NULL ;
WERROR result ;
2001-05-18 08:11:17 +04:00
2009-11-27 03:49:08 +03:00
if ( ! r ) {
return false ;
}
2001-05-18 08:11:17 +04:00
2005-03-08 01:06:25 +03:00
DEBUG ( 10 , ( " printer_driver_in_use: Beginning search through ntprinters.tdb... \n " ) ) ;
2009-02-09 14:40:12 +03:00
2001-05-18 08:11:17 +04:00
/* loop through the printers.tdb and check for the drivername */
2009-02-09 14:40:12 +03:00
2005-03-08 01:06:25 +03:00
for ( snum = 0 ; snum < n_services & & ! in_use ; snum + + ) {
2014-02-02 17:48:41 +04:00
if ( ! lp_snum_ok ( snum ) | | ! lp_printable ( snum ) ) {
2001-05-18 08:11:17 +04:00
continue ;
2010-04-26 22:46:33 +04:00
}
2009-02-09 14:40:12 +03:00
2011-07-05 02:55:35 +04:00
result = winreg_get_printer ( mem_ctx , b ,
2012-07-18 09:37:23 +04:00
lp_servicename ( talloc_tos ( ) , snum ) ,
2010-08-08 16:23:12 +04:00
& pinfo2 ) ;
2010-04-26 22:46:33 +04:00
if ( ! W_ERROR_IS_OK ( result ) ) {
continue ; /* skip */
}
2009-02-09 14:40:12 +03:00
2010-04-26 22:46:33 +04:00
if ( strequal ( r - > driver_name , pinfo2 - > drivername ) ) {
2017-01-10 20:25:22 +03:00
in_use = true ;
2010-04-26 22:46:33 +04:00
}
2009-02-09 14:40:12 +03:00
2010-04-26 22:46:33 +04:00
TALLOC_FREE ( pinfo2 ) ;
2002-07-15 14:35:28 +04:00
}
2009-02-09 14:40:12 +03:00
2005-03-08 01:06:25 +03:00
DEBUG ( 10 , ( " printer_driver_in_use: Completed search through ntprinters.tdb... \n " ) ) ;
2009-02-09 14:40:12 +03:00
2005-03-08 01:06:25 +03:00
if ( in_use ) {
2012-12-10 16:42:37 +04:00
struct spoolss_DriverInfo8 * driver = NULL ;
2005-03-08 01:06:25 +03:00
WERROR werr ;
2009-02-09 14:40:12 +03:00
2009-11-27 03:49:08 +03:00
DEBUG ( 5 , ( " printer_driver_in_use: driver \" %s \" is currently in use \n " , r - > driver_name ) ) ;
2009-02-09 14:40:12 +03:00
/* we can still remove the driver if there is one of
2005-03-08 01:06:25 +03:00
" Windows NT x86 " version 2 or 3 left */
2009-02-09 14:40:12 +03:00
2017-01-10 20:25:22 +03:00
if ( strequal ( SPOOLSS_ARCHITECTURE_NT_X86 , r - > architecture ) ) {
if ( r - > version = = 2 ) {
werr = winreg_get_driver ( mem_ctx , b ,
r - > architecture ,
r - > driver_name ,
3 , & driver ) ;
} else if ( r - > version = = 3 ) {
werr = winreg_get_driver ( mem_ctx , b ,
r - > architecture ,
r - > driver_name ,
2 , & driver ) ;
} else {
DBG_ERR ( " Unknown driver version (%d) \n " ,
r - > version ) ;
werr = WERR_UNKNOWN_PRINTER_DRIVER ;
}
} else if ( strequal ( SPOOLSS_ARCHITECTURE_x64 , r - > architecture ) ) {
2011-07-05 02:55:35 +04:00
werr = winreg_get_driver ( mem_ctx , b ,
2017-01-10 20:25:22 +03:00
SPOOLSS_ARCHITECTURE_NT_X86 ,
2010-04-15 04:48:00 +04:00
r - > driver_name ,
DRIVER_ANY_VERSION ,
& driver ) ;
} else {
2017-01-10 20:25:22 +03:00
DBG_ERR ( " Unknown driver architecture: %s \n " ,
r - > architecture ) ;
2010-04-15 04:48:00 +04:00
werr = WERR_UNKNOWN_PRINTER_DRIVER ;
2005-03-08 01:06:25 +03:00
}
/* now check the error code */
2009-02-09 14:40:12 +03:00
2005-03-08 01:06:25 +03:00
if ( W_ERROR_IS_OK ( werr ) ) {
/* it's ok to remove the driver, we have other architctures left */
2017-01-10 20:25:22 +03:00
in_use = false ;
2010-04-15 04:48:00 +04:00
talloc_free ( driver ) ;
2005-03-08 01:06:25 +03:00
}
}
2009-02-09 14:40:12 +03:00
2002-07-15 14:35:28 +04:00
/* report that the driver is not in use by default */
2009-02-09 14:40:12 +03:00
2005-03-08 01:06:25 +03:00
return in_use ;
2002-07-15 14:35:28 +04:00
}
2001-05-18 08:11:17 +04:00
2002-07-15 14:35:28 +04:00
/**********************************************************************
Check to see if a ogiven file is in use by * info
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-02-09 14:40:12 +03:00
2009-11-27 03:49:08 +03:00
static bool drv_file_in_use ( const char * file , const struct spoolss_DriverInfo8 * info )
2002-07-15 14:35:28 +04:00
{
2002-09-25 19:19:00 +04:00
int i = 0 ;
2008-04-25 02:02:23 +04:00
2002-07-15 14:35:28 +04:00
if ( ! info )
return False ;
2008-04-25 02:02:23 +04:00
/* mz: skip files that are in the list but already deleted */
if ( ! file | | ! file [ 0 ] ) {
return false ;
}
2009-11-17 14:54:02 +03:00
if ( strequal ( file , info - > driver_path ) )
2002-07-15 14:35:28 +04:00
return True ;
2001-06-27 00:23:45 +04:00
2009-11-17 14:54:02 +03:00
if ( strequal ( file , info - > data_file ) )
2002-07-15 14:35:28 +04:00
return True ;
2009-11-17 14:54:02 +03:00
if ( strequal ( file , info - > config_file ) )
2002-07-15 14:35:28 +04:00
return True ;
2009-11-17 14:54:02 +03:00
if ( strequal ( file , info - > help_file ) )
2002-07-15 14:35:28 +04:00
return True ;
2009-02-09 14:40:12 +03:00
2002-09-25 19:19:00 +04:00
/* see of there are any dependent files to examine */
2009-02-09 14:40:12 +03:00
2009-11-17 14:54:02 +03:00
if ( ! info - > dependent_files )
2002-09-25 19:19:00 +04:00
return False ;
2009-02-09 14:40:12 +03:00
2009-11-17 14:54:02 +03:00
while ( info - > dependent_files [ i ] & & * info - > dependent_files [ i ] ) {
if ( strequal ( file , info - > dependent_files [ i ] ) )
2002-09-25 19:19:00 +04:00
return True ;
i + + ;
2002-07-15 14:35:28 +04:00
}
2009-02-09 14:40:12 +03:00
2002-07-15 14:35:28 +04:00
return False ;
}
/**********************************************************************
2009-02-09 14:40:12 +03:00
Utility function to remove the dependent file pointed to by the
input parameter from the list
2002-07-15 14:35:28 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-11-17 14:54:02 +03:00
static void trim_dependent_file ( TALLOC_CTX * mem_ctx , const char * * files , int idx )
2002-07-15 14:35:28 +04:00
{
2009-02-09 14:40:12 +03:00
2002-09-25 19:19:00 +04:00
/* bump everything down a slot */
2009-11-17 14:54:02 +03:00
while ( files & & files [ idx + 1 ] ) {
files [ idx ] = talloc_strdup ( mem_ctx , files [ idx + 1 ] ) ;
2002-09-25 19:19:00 +04:00
idx + + ;
2002-07-15 14:35:28 +04:00
}
2009-02-09 14:40:12 +03:00
2009-11-17 14:54:02 +03:00
files [ idx ] = NULL ;
2002-09-25 19:19:00 +04:00
2009-02-09 14:40:12 +03:00
return ;
2002-07-15 14:35:28 +04:00
}
/**********************************************************************
2009-02-09 14:40:12 +03:00
Check if any of the files used by src are also used by drv
2002-07-15 14:35:28 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-11-17 14:54:02 +03:00
static bool trim_overlap_drv_files ( TALLOC_CTX * mem_ctx ,
2009-11-27 03:49:08 +03:00
struct spoolss_DriverInfo8 * src ,
const struct spoolss_DriverInfo8 * drv )
2002-07-15 14:35:28 +04:00
{
2007-10-19 04:40:25 +04:00
bool in_use = False ;
2002-09-25 19:19:00 +04:00
int i = 0 ;
2009-02-09 14:40:12 +03:00
2002-07-15 14:35:28 +04:00
if ( ! src | | ! drv )
return False ;
2009-02-09 14:40:12 +03:00
2002-07-15 14:35:28 +04:00
/* check each file. Remove it from the src structure if it overlaps */
2009-02-09 14:40:12 +03:00
2009-11-17 14:54:02 +03:00
if ( drv_file_in_use ( src - > driver_path , drv ) ) {
2002-07-15 14:35:28 +04:00
in_use = True ;
2009-11-17 14:54:02 +03:00
DEBUG ( 10 , ( " Removing driverfile [%s] from list \n " , src - > driver_path ) ) ;
src - > driver_path = talloc_strdup ( mem_ctx , " " ) ;
if ( ! src - > driver_path ) { return false ; }
2002-07-15 14:35:28 +04:00
}
2009-02-09 14:40:12 +03:00
2009-11-17 14:54:02 +03:00
if ( drv_file_in_use ( src - > data_file , drv ) ) {
2002-07-15 14:35:28 +04:00
in_use = True ;
2009-11-17 14:54:02 +03:00
DEBUG ( 10 , ( " Removing datafile [%s] from list \n " , src - > data_file ) ) ;
src - > data_file = talloc_strdup ( mem_ctx , " " ) ;
if ( ! src - > data_file ) { return false ; }
2002-07-15 14:35:28 +04:00
}
2009-02-09 14:40:12 +03:00
2009-11-17 14:54:02 +03:00
if ( drv_file_in_use ( src - > config_file , drv ) ) {
2002-07-15 14:35:28 +04:00
in_use = True ;
2009-11-17 14:54:02 +03:00
DEBUG ( 10 , ( " Removing configfile [%s] from list \n " , src - > config_file ) ) ;
src - > config_file = talloc_strdup ( mem_ctx , " " ) ;
if ( ! src - > config_file ) { return false ; }
2002-07-15 14:35:28 +04:00
}
2009-02-09 14:40:12 +03:00
2009-11-17 14:54:02 +03:00
if ( drv_file_in_use ( src - > help_file , drv ) ) {
2002-09-25 19:19:00 +04:00
in_use = True ;
2009-11-17 14:54:02 +03:00
DEBUG ( 10 , ( " Removing helpfile [%s] from list \n " , src - > help_file ) ) ;
src - > help_file = talloc_strdup ( mem_ctx , " " ) ;
if ( ! src - > help_file ) { return false ; }
2002-07-15 14:35:28 +04:00
}
2009-02-09 14:40:12 +03:00
2002-09-25 19:19:00 +04:00
/* are there any dependentfiles to examine? */
2009-02-09 14:40:12 +03:00
2009-11-17 14:54:02 +03:00
if ( ! src - > dependent_files )
2002-09-25 19:19:00 +04:00
return in_use ;
2009-02-09 14:40:12 +03:00
2009-11-17 14:54:02 +03:00
while ( src - > dependent_files [ i ] & & * src - > dependent_files [ i ] ) {
if ( drv_file_in_use ( src - > dependent_files [ i ] , drv ) ) {
2002-09-25 19:19:00 +04:00
in_use = True ;
2009-11-17 14:54:02 +03:00
DEBUG ( 10 , ( " Removing [%s] from dependent file list \n " , src - > dependent_files [ i ] ) ) ;
trim_dependent_file ( mem_ctx , src - > dependent_files , i ) ;
2003-02-25 23:53:53 +03:00
} else
2002-09-25 19:19:00 +04:00
i + + ;
2009-02-09 14:40:12 +03:00
}
2002-07-15 14:35:28 +04:00
return in_use ;
}
/****************************************************************************
2009-02-09 14:40:12 +03:00
Determine whether or not a particular driver files are currently being
used by any other driver .
2002-07-15 14:35:28 +04:00
Return value is True if any files were in use by other drivers
and False otherwise .
2009-02-09 14:40:12 +03:00
2002-07-15 14:35:28 +04:00
Upon return , * info has been modified to only contain the driver files
which are not in use
2008-04-25 02:02:23 +04:00
Fix from mz :
This needs to check all drivers to ensure that all files in use
have been removed from * info , not just the ones in the first
match .
2002-07-15 14:35:28 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-11-17 14:54:02 +03:00
bool printer_driver_files_in_use ( TALLOC_CTX * mem_ctx ,
2011-07-28 13:36:50 +04:00
struct dcerpc_binding_handle * b ,
2009-11-27 03:49:08 +03:00
struct spoolss_DriverInfo8 * info )
2002-07-15 14:35:28 +04:00
{
int i ;
2015-04-27 02:02:55 +03:00
uint32_t version ;
2009-11-27 03:49:08 +03:00
struct spoolss_DriverInfo8 * driver ;
2008-04-25 02:02:23 +04:00
bool in_use = false ;
2010-04-15 04:48:00 +04:00
uint32_t num_drivers ;
const char * * drivers ;
WERROR result ;
2008-04-25 02:02:23 +04:00
2002-09-25 19:19:00 +04:00
if ( ! info )
return False ;
2009-02-09 14:40:12 +03:00
2009-11-17 14:54:02 +03:00
version = info - > version ;
2009-02-09 14:40:12 +03:00
2002-07-15 14:35:28 +04:00
/* loop over all driver versions */
2009-02-09 14:40:12 +03:00
2010-04-15 04:48:00 +04:00
DEBUG ( 5 , ( " printer_driver_files_in_use: Beginning search of drivers... \n " ) ) ;
2009-02-09 14:40:12 +03:00
2002-09-25 19:19:00 +04:00
/* get the list of drivers */
2009-02-09 14:40:12 +03:00
2011-07-05 02:55:35 +04:00
result = winreg_get_driver_list ( mem_ctx , b ,
2010-04-15 04:48:00 +04:00
info - > architecture , version ,
& num_drivers , & drivers ) ;
if ( ! W_ERROR_IS_OK ( result ) ) {
return true ;
}
2009-02-09 14:40:12 +03:00
2010-04-15 04:48:00 +04:00
DEBUGADD ( 4 , ( " we have:[%d] drivers in environment [%s] and version [%d] \n " ,
num_drivers , info - > architecture , version ) ) ;
2002-07-15 14:35:28 +04:00
2002-09-25 19:19:00 +04:00
/* check each driver for overlap in files */
2009-02-09 14:40:12 +03:00
2010-04-15 04:48:00 +04:00
for ( i = 0 ; i < num_drivers ; i + + ) {
DEBUGADD ( 5 , ( " \t driver: [%s] \n " , drivers [ i ] ) ) ;
2009-02-09 14:40:12 +03:00
2009-11-17 14:54:02 +03:00
driver = NULL ;
2009-02-09 14:40:12 +03:00
2011-07-05 02:55:35 +04:00
result = winreg_get_driver ( mem_ctx , b ,
2010-04-15 04:48:00 +04:00
info - > architecture , drivers [ i ] ,
version , & driver ) ;
if ( ! W_ERROR_IS_OK ( result ) ) {
talloc_free ( drivers ) ;
2002-09-25 19:19:00 +04:00
return True ;
}
2009-02-09 14:40:12 +03:00
2002-09-25 19:19:00 +04:00
/* check if d2 uses any files from d1 */
/* only if this is a different driver than the one being deleted */
2009-02-09 14:40:12 +03:00
2009-11-27 03:49:08 +03:00
if ( ! strequal ( info - > driver_name , driver - > driver_name ) ) {
if ( trim_overlap_drv_files ( mem_ctx , info , driver ) ) {
2008-04-25 02:02:23 +04:00
/* mz: Do not instantly return -
* we need to ensure this file isn ' t
* also in use by other drivers . */
in_use = true ;
2002-07-15 14:35:28 +04:00
}
2002-09-25 19:19:00 +04:00
}
2007-11-22 00:56:36 +03:00
2010-04-15 04:48:00 +04:00
talloc_free ( driver ) ;
2007-11-22 00:56:36 +03:00
}
2010-04-15 04:48:00 +04:00
talloc_free ( drivers ) ;
2007-11-22 00:56:36 +03:00
2010-04-15 04:48:00 +04:00
DEBUG ( 5 , ( " printer_driver_files_in_use: Completed search of drivers... \n " ) ) ;
2007-11-22 00:56:36 +03:00
2008-04-25 02:02:23 +04:00
return in_use ;
2001-05-18 08:11:17 +04:00
}
2009-07-25 05:38:40 +04:00
static NTSTATUS driver_unlink_internals ( connection_struct * conn ,
2012-01-11 22:50:36 +04:00
const char * short_arch ,
int vers ,
const char * fname )
2009-07-25 05:38:40 +04:00
{
2012-01-11 22:50:36 +04:00
TALLOC_CTX * tmp_ctx = talloc_new ( conn ) ;
2009-07-25 05:38:40 +04:00
struct smb_filename * smb_fname = NULL ;
2012-01-11 22:50:36 +04:00
char * print_dlr_path ;
NTSTATUS status = NT_STATUS_NO_MEMORY ;
print_dlr_path = talloc_asprintf ( tmp_ctx , " %s/%d/%s " ,
short_arch , vers , fname ) ;
if ( print_dlr_path = = NULL ) {
goto err_out ;
}
2009-07-25 05:38:40 +04:00
2016-03-19 07:19:38 +03:00
smb_fname = synthetic_smb_fname ( tmp_ctx , print_dlr_path , NULL , NULL , 0 ) ;
2013-04-15 13:50:51 +04:00
if ( smb_fname = = NULL ) {
2012-01-11 22:50:36 +04:00
goto err_out ;
2009-07-25 05:38:40 +04:00
}
status = unlink_internals ( conn , NULL , 0 , smb_fname , false ) ;
2012-01-11 22:50:36 +04:00
err_out :
talloc_free ( tmp_ctx ) ;
2009-07-25 05:38:40 +04:00
return status ;
}
2002-07-15 14:35:28 +04:00
/****************************************************************************
2007-11-22 00:56:36 +03:00
Actually delete the driver files . Make sure that
printer_driver_files_in_use ( ) return False before calling
2002-07-15 14:35:28 +04:00
this .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-07-18 07:06:47 +04:00
bool delete_driver_files ( const struct auth_session_info * session_info ,
2010-04-15 04:48:00 +04:00
const struct spoolss_DriverInfo8 * r )
2002-07-15 14:35:28 +04:00
{
2018-05-24 18:40:27 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2012-01-11 22:50:36 +04:00
const char * short_arch ;
2018-05-24 18:55:02 +03:00
struct conn_struct_tos * c = NULL ;
connection_struct * conn = NULL ;
2002-07-15 14:35:28 +04:00
NTSTATUS nt_status ;
2010-11-10 02:07:49 +03:00
char * printdollar = NULL ;
2008-11-24 01:13:11 +03:00
int printdollar_snum ;
bool ret = false ;
2003-03-05 04:30:15 +03:00
2009-11-27 03:49:08 +03:00
if ( ! r ) {
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2009-11-27 03:49:08 +03:00
return false ;
}
2007-11-22 00:56:36 +03:00
2009-11-17 14:54:02 +03:00
DEBUG ( 6 , ( " delete_driver_files: deleting driver [%s] - version [%d] \n " ,
2009-11-27 03:49:08 +03:00
r - > driver_name , r - > version ) ) ;
2007-11-22 00:56:36 +03:00
2018-05-24 18:40:27 +03:00
printdollar_snum = find_service ( frame , " print$ " , & printdollar ) ;
2010-11-10 02:07:49 +03:00
if ( ! printdollar ) {
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2010-11-10 02:07:49 +03:00
return false ;
}
2008-11-24 01:13:11 +03:00
if ( printdollar_snum = = - 1 ) {
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2008-11-24 01:13:11 +03:00
return false ;
}
2007-11-22 00:56:36 +03:00
2018-08-21 21:09:16 +03:00
nt_status = create_conn_struct_tos_cwd ( global_messaging_context ( ) ,
2018-05-24 18:55:02 +03:00
printdollar_snum ,
lp_path ( frame , printdollar_snum ) ,
session_info ,
& c ) ;
2008-11-24 01:13:11 +03:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
DEBUG ( 0 , ( " delete_driver_files: create_conn_struct "
" returned %s \n " , nt_errstr ( nt_status ) ) ) ;
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2008-11-24 01:13:11 +03:00
return false ;
2002-07-15 14:35:28 +04:00
}
2018-05-24 18:55:02 +03:00
conn = c - > conn ;
2002-07-15 14:35:28 +04:00
2011-03-02 16:34:28 +03:00
nt_status = set_conn_force_user_group ( conn , printdollar_snum ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
DEBUG ( 0 , ( " failed set force user / group \n " ) ) ;
ret = false ;
goto err_free_conn ;
}
2011-04-01 13:55:27 +04:00
if ( ! become_user_by_session ( conn , session_info ) ) {
2011-03-02 16:34:28 +03:00
DEBUG ( 0 , ( " failed to become user \n " ) ) ;
ret = false ;
goto err_free_conn ;
}
2006-02-18 00:07:26 +03:00
if ( ! CAN_WRITE ( conn ) ) {
DEBUG ( 3 , ( " delete_driver_files: Cannot delete print driver when [print$] is read-only \n " ) ) ;
2011-03-01 21:17:48 +03:00
ret = false ;
goto err_out ;
2002-07-15 14:35:28 +04:00
}
2012-01-11 22:50:36 +04:00
short_arch = get_short_archi ( r - > architecture ) ;
if ( short_arch = = NULL ) {
DEBUG ( 0 , ( " bad architecture %s \n " , r - > architecture ) ) ;
ret = false ;
goto err_out ;
}
/* now delete the files */
2007-11-22 00:56:36 +03:00
2009-11-27 03:49:08 +03:00
if ( r - > driver_path & & r - > driver_path [ 0 ] ) {
2012-01-11 22:50:36 +04:00
DEBUG ( 10 , ( " deleting driverfile [%s] \n " , r - > driver_path ) ) ;
driver_unlink_internals ( conn , short_arch , r - > version , r - > driver_path ) ;
2002-07-15 14:35:28 +04:00
}
2007-11-22 00:56:36 +03:00
2009-11-27 03:49:08 +03:00
if ( r - > config_file & & r - > config_file [ 0 ] ) {
2012-01-11 22:50:36 +04:00
DEBUG ( 10 , ( " deleting configfile [%s] \n " , r - > config_file ) ) ;
driver_unlink_internals ( conn , short_arch , r - > version , r - > config_file ) ;
2002-07-15 14:35:28 +04:00
}
2007-11-22 00:56:36 +03:00
2009-11-27 03:49:08 +03:00
if ( r - > data_file & & r - > data_file [ 0 ] ) {
2012-01-11 22:50:36 +04:00
DEBUG ( 10 , ( " deleting datafile [%s] \n " , r - > data_file ) ) ;
driver_unlink_internals ( conn , short_arch , r - > version , r - > data_file ) ;
2002-07-15 14:35:28 +04:00
}
2007-11-22 00:56:36 +03:00
2009-11-27 03:49:08 +03:00
if ( r - > help_file & & r - > help_file [ 0 ] ) {
2012-01-11 22:50:36 +04:00
DEBUG ( 10 , ( " deleting helpfile [%s] \n " , r - > help_file ) ) ;
driver_unlink_internals ( conn , short_arch , r - > version , r - > help_file ) ;
2002-07-15 14:35:28 +04:00
}
2007-11-22 00:56:36 +03:00
2009-11-27 03:49:08 +03:00
if ( r - > dependent_files ) {
2012-01-11 22:50:36 +04:00
int i = 0 ;
2009-11-27 03:49:08 +03:00
while ( r - > dependent_files [ i ] & & r - > dependent_files [ i ] [ 0 ] ) {
2012-01-11 22:50:36 +04:00
DEBUG ( 10 , ( " deleting dependent file [%s] \n " , r - > dependent_files [ i ] ) ) ;
driver_unlink_internals ( conn , short_arch , r - > version , r - > dependent_files [ i ] ) ;
2002-09-25 19:19:00 +04:00
i + + ;
2002-07-15 14:35:28 +04:00
}
}
2011-03-01 21:17:48 +03:00
ret = true ;
err_out :
2011-03-02 16:34:28 +03:00
unbecome_user ( ) ;
err_free_conn :
2018-05-24 18:40:27 +03:00
TALLOC_FREE ( frame ) ;
2008-11-24 01:13:11 +03:00
return ret ;
2002-07-15 14:35:28 +04:00
}
2000-02-07 19:17:59 +03:00
/* error code:
0 : everything OK
1 : level not implemented
2 : file doesn ' t exist
3 : can ' t allocate memory
4 : can ' t free memory
2012-06-11 19:48:32 +04:00
5 : non existent struct
2000-02-07 19:17:59 +03:00
*/
/*
A printer and a printer driver are 2 different things .
NT manages them separatelly , Samba does the same .
Why ? Simply because it ' s easier and it makes sense !
2009-02-09 14:40:12 +03:00
2000-02-07 19:17:59 +03:00
Now explanation : You have 3 printers behind your samba server ,
2000-11-15 00:56:32 +03:00
2 of them are the same make and model ( laser A and B ) . But laser B
2000-02-07 19:17:59 +03:00
has an 3000 sheet feeder and laser A doesn ' t such an option .
Your third printer is an old dot - matrix model for the accounting : - ) .
2009-02-09 14:40:12 +03:00
2000-02-07 19:17:59 +03:00
If the / usr / local / samba / lib directory ( default dir ) , you will have
5 files to describe all of this .
2009-02-09 14:40:12 +03:00
2000-02-07 19:17:59 +03:00
3 files for the printers ( 1 by printer ) :
NTprinter_laser A
NTprinter_laser B
NTprinter_accounting
2 files for the drivers ( 1 for the laser and 1 for the dot matrix )
NTdriver_printer model X
NTdriver_printer model Y
2000-11-15 00:56:32 +03:00
jfm : I should use this comment for the text file to explain
2000-02-07 19:17:59 +03:00
same thing for the forms BTW .
Je devrais mettre mes commentaires en francais , ca serait mieux : - )
*/
2001-01-04 22:27:08 +03:00
/* Convert generic access rights to printer object specific access rights.
It turns out that NT4 security descriptors use generic access rights and
NT5 the object specific ones . */
2010-05-18 12:29:34 +04:00
void map_printer_permissions ( struct security_descriptor * sd )
2001-01-04 22:27:08 +03:00
{
int i ;
for ( i = 0 ; sd - > dacl & & i < sd - > dacl - > num_aces ; i + + ) {
2006-09-21 02:23:12 +04:00
se_map_generic ( & sd - > dacl - > aces [ i ] . access_mask ,
2001-01-04 22:27:08 +03:00
& printer_generic_mapping ) ;
}
}
2010-05-18 12:29:34 +04:00
void map_job_permissions ( struct security_descriptor * sd )
2008-05-06 03:24:52 +04:00
{
int i ;
for ( i = 0 ; sd - > dacl & & i < sd - > dacl - > num_aces ; i + + ) {
se_map_generic ( & sd - > dacl - > aces [ i ] . access_mask ,
& job_generic_mapping ) ;
}
}
2000-08-09 08:19:18 +04:00
/****************************************************************************
2001-01-19 19:57:39 +03:00
Check a user has permissions to perform the given operation . We use the
permission constants defined in include / rpc_spoolss . h to check the various
actions we perform when checking printer access .
2000-09-01 22:49:26 +04:00
PRINTER_ACCESS_ADMINISTER :
print_queue_pause , print_queue_resume , update_printer_sec ,
update_printer , spoolss_addprinterex_level_2 ,
_spoolss_setprinterdata
2000-11-15 00:56:32 +03:00
2000-09-01 22:49:26 +04:00
PRINTER_ACCESS_USE :
print_job_start
2001-01-19 19:57:39 +03:00
JOB_ACCESS_ADMINISTER :
2000-09-01 22:49:26 +04:00
print_job_delete , print_job_pause , print_job_resume ,
print_queue_purge
2000-06-16 12:20:44 +04:00
2005-01-15 00:24:15 +03:00
Try access control in the following order ( for performance reasons ) :
2009-04-27 19:54:23 +04:00
1 ) root and SE_PRINT_OPERATOR can do anything ( easy check )
2005-01-15 00:24:15 +03:00
2 ) check security descriptor ( bit comparisons in memory )
3 ) " printer admins " ( may result in numerous calls to winbind )
2000-08-09 08:19:18 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2013-09-26 15:24:15 +04:00
WERROR print_access_check ( const struct auth_session_info * session_info ,
struct messaging_context * msg_ctx , int snum ,
int access_type )
2000-06-16 12:20:44 +04:00
{
2010-04-16 13:35:05 +04:00
struct spoolss_security_descriptor * secdesc = NULL ;
2015-04-27 02:02:55 +03:00
uint32_t access_granted ;
2010-04-16 13:35:05 +04:00
size_t sd_size ;
2001-09-04 11:13:01 +04:00
NTSTATUS status ;
2010-04-16 13:35:05 +04:00
WERROR result ;
2002-07-15 14:35:28 +04:00
const char * pname ;
2001-02-28 03:51:02 +03:00
TALLOC_CTX * mem_ctx = NULL ;
2009-02-09 14:40:12 +03:00
2000-09-01 22:49:26 +04:00
/* If user is NULL then use the current_user structure */
2005-01-15 00:24:15 +03:00
/* Always allow root or SE_PRINT_OPERATROR to do anything */
2000-09-01 22:49:26 +04:00
2013-09-26 15:24:15 +04:00
if ( ( session_info - > unix_token - > uid = = sec_initial_uid ( ) )
| | security_token_has_privilege ( session_info - > security_token ,
SEC_PRIV_PRINT_OPERATOR ) ) {
return WERR_OK ;
2000-08-09 08:19:18 +04:00
}
2000-06-16 12:20:44 +04:00
2000-08-09 08:19:18 +04:00
/* Get printer name */
2000-09-01 22:49:26 +04:00
2012-07-18 09:37:23 +04:00
pname = lp_printername ( talloc_tos ( ) , snum ) ;
2000-09-01 22:49:26 +04:00
2000-08-24 03:05:49 +04:00
if ( ! pname | | ! * pname ) {
2013-09-26 15:24:15 +04:00
return WERR_ACCESS_DENIED ;
2000-08-24 03:05:49 +04:00
}
2000-06-16 12:20:44 +04:00
2000-08-09 08:19:18 +04:00
/* Get printer security descriptor */
2000-09-01 22:49:26 +04:00
2002-12-20 23:21:31 +03:00
if ( ! ( mem_ctx = talloc_init ( " print_access_check " ) ) ) {
2015-12-03 17:24:14 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2001-02-28 03:51:02 +03:00
}
2011-07-05 02:16:03 +04:00
result = winreg_get_printer_secdesc_internal ( mem_ctx ,
2011-02-21 12:25:52 +03:00
get_session_info_system ( ) ,
2010-08-08 16:28:17 +04:00
msg_ctx ,
2010-04-16 13:35:05 +04:00
pname ,
& secdesc ) ;
if ( ! W_ERROR_IS_OK ( result ) ) {
2006-06-20 01:36:19 +04:00
talloc_destroy ( mem_ctx ) ;
2015-12-03 17:24:14 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2006-06-20 01:36:19 +04:00
}
2001-01-19 19:57:39 +03:00
if ( access_type = = JOB_ACCESS_ADMINISTER ) {
2010-04-16 13:35:05 +04:00
struct spoolss_security_descriptor * parent_secdesc = secdesc ;
2001-01-19 19:57:39 +03:00
/* Create a child security descriptor to check permissions
against . This is because print jobs are child objects
objects of a printer . */
2010-04-16 13:35:05 +04:00
status = se_create_child_secdesc ( mem_ctx ,
& secdesc ,
& sd_size ,
parent_secdesc ,
parent_secdesc - > owner_sid ,
parent_secdesc - > group_sid ,
false ) ;
2008-10-29 23:27:14 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2006-06-20 01:36:19 +04:00
talloc_destroy ( mem_ctx ) ;
2013-09-26 15:24:15 +04:00
return ntstatus_to_werror ( status ) ;
2006-06-20 01:36:19 +04:00
}
2010-04-16 13:35:05 +04:00
map_job_permissions ( secdesc ) ;
2008-05-06 03:24:52 +04:00
} else {
2010-04-16 13:35:05 +04:00
map_printer_permissions ( secdesc ) ;
2001-01-19 19:57:39 +03:00
}
2001-01-04 22:27:08 +03:00
2008-05-06 03:24:52 +04:00
/* Check access */
2011-02-21 12:25:52 +03:00
status = se_access_check ( secdesc , session_info - > security_token , access_type ,
2008-10-31 20:51:45 +03:00
& access_granted ) ;
2000-06-16 12:20:44 +04:00
2008-10-31 20:51:45 +03:00
DEBUG ( 4 , ( " access check was %s \n " , NT_STATUS_IS_OK ( status ) ? " SUCCESS " : " FAILURE " ) ) ;
2000-06-16 12:20:44 +04:00
2001-02-28 03:51:02 +03:00
talloc_destroy ( mem_ctx ) ;
2009-02-09 14:40:12 +03:00
2013-09-26 15:24:15 +04:00
return ntstatus_to_werror ( status ) ;
2000-06-16 12:20:44 +04:00
}
2000-08-01 04:41:19 +04:00
/****************************************************************************
Check the time parameters allow a print operation .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-07-18 07:06:47 +04:00
bool print_time_access_check ( const struct auth_session_info * session_info ,
2010-08-08 16:29:39 +04:00
struct messaging_context * msg_ctx ,
2010-04-26 21:51:33 +04:00
const char * servicename )
2000-08-01 04:41:19 +04:00
{
2010-04-26 21:51:33 +04:00
struct spoolss_PrinterInfo2 * pinfo2 = NULL ;
WERROR result ;
2007-10-19 04:40:25 +04:00
bool ok = False ;
2000-08-01 04:41:19 +04:00
time_t now = time ( NULL ) ;
struct tm * t ;
2015-04-27 02:02:55 +03:00
uint32_t mins ;
2000-08-01 04:41:19 +04:00
2011-07-05 02:16:03 +04:00
result = winreg_get_printer_internal ( NULL , session_info , msg_ctx ,
2010-09-29 06:51:56 +04:00
servicename , & pinfo2 ) ;
2010-04-26 21:51:33 +04:00
if ( ! W_ERROR_IS_OK ( result ) ) {
2000-08-01 04:41:19 +04:00
return False ;
2010-04-26 21:51:33 +04:00
}
2000-08-01 04:41:19 +04:00
2010-04-26 21:51:33 +04:00
if ( pinfo2 - > starttime = = 0 & & pinfo2 - > untiltime = = 0 ) {
2000-08-01 04:41:19 +04:00
ok = True ;
2010-04-26 21:51:33 +04:00
}
2000-08-01 04:41:19 +04:00
t = gmtime ( & now ) ;
2015-05-14 03:26:01 +03:00
mins = ( uint32_t ) t - > tm_hour * 60 + ( uint32_t ) t - > tm_min ;
2000-08-01 04:41:19 +04:00
2010-04-26 21:51:33 +04:00
if ( mins > = pinfo2 - > starttime & & mins < = pinfo2 - > untiltime ) {
2000-08-01 04:41:19 +04:00
ok = True ;
2010-04-26 21:51:33 +04:00
}
2000-08-01 04:41:19 +04:00
2010-04-26 21:51:33 +04:00
TALLOC_FREE ( pinfo2 ) ;
2000-08-01 04:41:19 +04:00
2010-04-26 21:51:33 +04:00
if ( ! ok ) {
2000-09-13 06:24:35 +04:00
errno = EACCES ;
2010-04-26 21:51:33 +04:00
}
2000-09-13 06:24:35 +04:00
2000-08-01 04:41:19 +04:00
return ok ;
}
2004-10-02 00:34:12 +04:00
2010-04-27 02:50:44 +04:00
void nt_printer_remove ( TALLOC_CTX * mem_ctx ,
2011-07-18 07:06:47 +04:00
const struct auth_session_info * session_info ,
2010-08-08 16:31:14 +04:00
struct messaging_context * msg_ctx ,
2010-04-27 02:50:44 +04:00
const char * printer )
{
WERROR result ;
2005-07-15 18:26:11 +04:00
2011-07-05 02:16:03 +04:00
result = winreg_delete_printer_key_internal ( mem_ctx , session_info , msg_ctx ,
2010-08-08 12:29:50 +04:00
printer , " " ) ;
2010-04-27 02:50:44 +04:00
if ( ! W_ERROR_IS_OK ( result ) ) {
2012-02-07 14:41:54 +04:00
DEBUG ( 0 , ( " nt_printer_remove: failed to remove printer %s: "
" %s \n " , printer , win_errstr ( result ) ) ) ;
}
}
void nt_printer_add ( TALLOC_CTX * mem_ctx ,
const struct auth_session_info * session_info ,
struct messaging_context * msg_ctx ,
const char * printer )
{
WERROR result ;
result = winreg_create_printer_internal ( mem_ctx , session_info , msg_ctx ,
printer ) ;
if ( ! W_ERROR_IS_OK ( result ) ) {
DEBUG ( 0 , ( " nt_printer_add: failed to add printer %s: %s \n " ,
printer , win_errstr ( result ) ) ) ;
2010-04-27 02:50:44 +04:00
}
}