2008-04-21 21:10:29 +04:00
/*
2008-04-21 21:57:09 +04:00
Unix SMB / CIFS implementation .
SMB backend for the Common UNIX Printing System ( " CUPS " )
2008-05-30 21:08:27 +04:00
Copyright ( C ) Michael R Sweet 1999
2008-04-21 21:57:09 +04:00
Copyright ( C ) Andrew Tridgell 1994 - 1998
Copyright ( C ) Andrew Bartlett 2002
Copyright ( C ) Rodrigo Fernandez - Vizarra 2005
Copyright ( C ) James Peach 2008
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
1999-12-17 04:48:16 +03:00
2005-05-09 20:04:27 +04:00
# include "includes.h"
2011-02-26 01:20:06 +03:00
# include "system/filesys.h"
2011-02-25 19:14:22 +03:00
# include "system/passwd.h"
2017-07-11 10:41:08 +03:00
# include "system/kerberos.h"
2011-05-06 13:47:43 +04:00
# include "libsmb/libsmb.h"
2017-07-24 13:27:50 +03:00
# include "lib/param/param.h"
2018-12-05 13:06:20 +03:00
# include "lib/krb5_wrap/krb5_samba.h"
2005-05-09 20:04:27 +04:00
2008-04-21 20:16:01 +04:00
/*
2008-04-21 21:57:09 +04:00
* Starting with CUPS 1.3 , Kerberos support is provided by cupsd including
* the forwarding of user credentials via the authenticated session between
* user and server and the KRB5CCNAME environment variable which will point
* to a temporary file or an in - memory representation depending on the version
* of Kerberos you use . As a result , all of the ticket code that used to
* live here has been removed , and we depend on the user session ( if you
* run smbspool by hand ) or cupsd to provide the necessary Kerberos info .
*
* Also , the AUTH_USERNAME and AUTH_PASSWORD environment variables provide
* for per - job authentication for non - Kerberized printing . We use those
* if there is no username and password specified in the device URI .
*
* Finally , if we have an authentication failure we return exit code 2
* which tells CUPS to hold the job for authentication and bug the user
* to get the necessary credentials .
*/
2008-04-21 20:16:01 +04:00
2005-11-18 17:33:12 +03:00
# define MAX_RETRY_CONNECT 3
1999-12-17 04:48:16 +03:00
/*
* Globals . . .
*/
/*
* Local functions . . .
*/
2019-05-14 12:35:46 +03:00
static int get_exit_code ( NTSTATUS nt_status ) ;
2008-04-21 21:10:29 +04:00
static void list_devices ( void ) ;
2019-05-14 12:35:46 +03:00
static NTSTATUS
smb_connect ( struct cli_state * * output_cli ,
const char * workgroup ,
const char * server ,
const int port ,
const char * share ,
const char * username ,
const char * password ,
const char * jobusername ) ;
2019-03-12 12:09:14 +03:00
static int smb_print ( struct cli_state * , const char * , FILE * ) ;
2008-04-21 21:10:29 +04:00
static char * uri_unescape_alloc ( const char * ) ;
2008-01-05 11:23:35 +03:00
#if 0
2008-04-21 21:10:29 +04:00
static bool smb_encrypt ;
2008-01-05 11:23:35 +03:00
# endif
1999-12-17 04:48:16 +03:00
2019-01-04 11:21:24 +03:00
static const char * auth_info_required ;
1999-12-17 04:48:16 +03:00
/*
* ' main ( ) ' - Main entry for SMB backend .
*/
2008-04-21 21:10:29 +04:00
int /* O - Exit status */
main ( int argc , /* I - Number of command-line arguments */
char * argv [ ] )
{ /* I - Command-line arguments */
int i ; /* Looping var */
int copies ; /* Number of copies */
int port ; /* Port number */
char uri [ 1024 ] , /* URI */
* sep , /* Pointer to separator */
2019-05-13 19:54:02 +03:00
* tmp , * tmp2 ; /* Temp pointers to do escaping */
const char * password = NULL ; /* Password */
2019-05-14 12:35:46 +03:00
const char * username = NULL ; /* Username */
char * server , /* Server name */
2008-04-21 21:10:29 +04:00
* printer ; /* Printer name */
const char * workgroup ; /* Workgroup */
FILE * fp ; /* File to print */
int status = 1 ; /* Status of LPD job */
2019-05-14 12:35:46 +03:00
NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL ;
struct cli_state * cli = NULL ; /* SMB interface */
2008-04-21 21:10:29 +04:00
int tries = 0 ;
2019-03-12 13:40:30 +03:00
const char * dev_uri = NULL ;
const char * env = NULL ;
2017-07-24 13:27:50 +03:00
const char * config_file = NULL ;
2008-04-21 21:10:29 +04:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2019-03-12 13:40:30 +03:00
const char * print_user = NULL ;
const char * print_title = NULL ;
2018-05-03 11:17:12 +03:00
const char * print_file = NULL ;
const char * print_copies = NULL ;
2018-01-05 12:50:57 +03:00
int cmp ;
int len ;
2008-04-21 21:10:29 +04:00
if ( argc = = 1 ) {
/*
2008-04-21 21:57:09 +04:00
* NEW ! In CUPS 1.1 the backends are run with no arguments
* to list the available devices . These can be devices
* served by this backend or any other backends ( i . e . you
* can have an SNMP backend that is only used to enumerate
* the available network printers . . . : )
2008-04-21 21:10:29 +04:00
*/
list_devices ( ) ;
status = 0 ;
goto done ;
}
2008-04-21 21:57:09 +04:00
2018-05-03 11:17:12 +03:00
/*
* We need at least 5 options if the DEVICE_URI is passed via an env
* variable and printing data comes via stdin .
* We don ' t accept more than 7 options in total , including optional .
*/
if ( argc < 5 | | argc > 8 ) {
2008-04-21 21:57:09 +04:00
fprintf ( stderr ,
" Usage: %s [DEVICE_URI] job-id user title copies options [file] \n "
" The DEVICE_URI environment variable can also contain the \n "
" destination printer: \n "
" \n "
" smb://[username:password@][workgroup/]server[:port]/printer \n " ,
2008-04-21 21:10:29 +04:00
argv [ 0 ] ) ;
goto done ;
}
2008-04-21 21:57:09 +04:00
2008-04-21 21:10:29 +04:00
/*
2019-03-12 13:40:30 +03:00
* Find out if we have the device_uri in the command line .
*
* If we are started as a CUPS backend argv [ 0 ] is normally the
* device_uri !
2018-05-03 11:17:12 +03:00
*/
2019-03-12 13:40:30 +03:00
if ( argc = = 8 ) {
/*
* smbspool < uri > < job > < user > < title > < copies > < options > < file >
* 0 1 2 3 4 5 6 7
*/
dev_uri = argv [ 1 ] ;
print_user = argv [ 3 ] ;
print_title = argv [ 4 ] ;
print_copies = argv [ 5 ] ;
print_file = argv [ 7 ] ;
} else if ( argc = = 7 ) {
int cmp1 ;
int cmp2 ;
/*
* < uri > < job > < user > < title > < copies > < options > < file >
* smbspool < uri > < job > < user > < title > < copies > < options >
* smbspool < job > < user > < title > < copies > < options > < file > | DEVICE_URI
*/
cmp1 = strncmp ( argv [ 0 ] , " smb:// " , 6 ) ;
cmp2 = strncmp ( argv [ 1 ] , " smb:// " , 6 ) ;
if ( cmp1 = = 0 ) {
/*
* < uri > < job > < user > < title > < copies > < options > < file >
* 0 1 2 3 4 5 6
*/
dev_uri = argv [ 0 ] ;
print_user = argv [ 2 ] ;
print_title = argv [ 3 ] ;
print_copies = argv [ 4 ] ;
print_file = argv [ 6 ] ;
} else if ( cmp2 = = 0 ) {
/*
* smbspool < uri > < job > < user > < title > < copies > < options >
* 0 1 2 3 4 5 6
*/
dev_uri = argv [ 1 ] ;
print_user = argv [ 3 ] ;
print_title = argv [ 4 ] ;
print_copies = argv [ 5 ] ;
print_file = NULL ;
2018-05-03 11:17:12 +03:00
} else {
2019-03-12 13:40:30 +03:00
/*
* smbspool < job > < user > < title > < copies > < options > < file > | DEVICE_URI
* 0 1 2 3 4 5 6
*/
print_user = argv [ 2 ] ;
print_title = argv [ 3 ] ;
2018-05-03 11:17:12 +03:00
print_copies = argv [ 4 ] ;
print_file = argv [ 6 ] ;
}
2019-03-12 13:40:30 +03:00
} else if ( argc = = 6 ) {
/*
* < uri > < job > < user > < title > < copies > < options >
* smbspool < job > < user > < title > < copies > < options > | DEVICE_URI
* 0 1 2 3 4 5
*/
cmp = strncmp ( argv [ 0 ] , " smb:// " , 6 ) ;
if ( cmp = = 0 ) {
dev_uri = argv [ 0 ] ;
}
print_user = argv [ 2 ] ;
print_title = argv [ 3 ] ;
print_copies = argv [ 4 ] ;
2018-05-03 11:17:12 +03:00
}
2008-04-21 21:10:29 +04:00
2018-05-03 11:17:12 +03:00
if ( print_file ! = NULL ) {
2015-01-22 11:57:58 +03:00
char * endp ;
2018-05-03 11:17:12 +03:00
fp = fopen ( print_file , " rb " ) ;
if ( fp = = NULL ) {
2019-05-13 17:48:31 +03:00
fprintf ( stderr ,
" ERROR: Unable to open print file: %s " ,
print_file ) ;
2018-05-03 11:17:12 +03:00
goto done ;
}
copies = strtol ( print_copies , & endp , 10 ) ;
if ( print_copies = = endp ) {
2015-01-22 11:57:58 +03:00
perror ( " ERROR: Unable to determine number of copies " ) ;
goto done ;
}
2018-05-03 11:17:12 +03:00
} else {
fp = stdin ;
copies = 1 ;
2008-04-21 21:57:09 +04:00
}
2008-04-21 21:10:29 +04:00
/*
2018-01-05 12:50:57 +03:00
* Find the URI . . .
2019-09-16 22:35:06 +03:00
*
* The URI in argv [ 0 ] is sanitized to remove username / password , so
* use DEVICE_URI if available . Otherwise keep the URI already
* discovered in argv .
*/
env = getenv ( " DEVICE_URI " ) ;
if ( env ! = NULL & & env [ 0 ] ! = ' \0 ' ) {
dev_uri = env ;
}
2008-04-21 21:10:29 +04:00
2019-03-12 13:40:30 +03:00
if ( dev_uri = = NULL ) {
fprintf ( stderr ,
" ERROR: No valid device URI has been specified \n " ) ;
goto done ;
2019-01-04 11:21:24 +03:00
}
2018-01-05 12:50:57 +03:00
cmp = strncmp ( dev_uri , " smb:// " , 6 ) ;
if ( cmp ! = 0 ) {
fprintf ( stderr ,
" ERROR: No valid device URI has been specified \n " ) ;
goto done ;
}
len = snprintf ( uri , sizeof ( uri ) , " %s " , dev_uri ) ;
if ( len > = sizeof ( uri ) ) {
fprintf ( stderr ,
" ERROR: The URI is too long. \n " ) ;
goto done ;
}
2008-04-21 21:10:29 +04:00
2019-03-12 13:40:30 +03:00
auth_info_required = getenv ( " AUTH_INFO_REQUIRED " ) ;
if ( auth_info_required = = NULL ) {
2019-10-28 11:35:34 +03:00
auth_info_required = " samba " ;
2019-03-12 13:40:30 +03:00
}
2008-04-21 21:10:29 +04:00
/*
* Extract the destination from the URI . . .
*/
if ( ( sep = strrchr_m ( uri , ' @ ' ) ) ! = NULL ) {
tmp = uri + 6 ;
* sep + + = ' \0 ' ;
/* username is in tmp */
server = sep ;
/*
* Extract password as needed . . .
*/
if ( ( tmp2 = strchr_m ( tmp , ' : ' ) ) ! = NULL ) {
* tmp2 + + = ' \0 ' ;
password = uri_unescape_alloc ( tmp2 ) ;
}
username = uri_unescape_alloc ( tmp ) ;
} else {
2019-05-14 12:35:46 +03:00
env = getenv ( " AUTH_USERNAME " ) ;
if ( env ! = NULL & & strlen ( env ) > 0 ) {
username = env ;
2008-04-21 21:57:09 +04:00
}
2008-04-21 21:10:29 +04:00
2019-05-13 19:54:02 +03:00
env = getenv ( " AUTH_PASSWORD " ) ;
if ( env ! = NULL & & strlen ( env ) > 0 ) {
password = env ;
2008-04-21 21:57:09 +04:00
}
2008-04-21 21:10:29 +04:00
server = uri + 6 ;
}
2019-05-13 19:54:02 +03:00
if ( password ! = NULL ) {
2019-01-04 11:21:24 +03:00
auth_info_required = " username,password " ;
}
2008-04-21 21:10:29 +04:00
tmp = server ;
if ( ( sep = strchr_m ( tmp , ' / ' ) ) = = NULL ) {
fputs ( " ERROR: Bad URI - need printer name! \n " , stderr ) ;
goto done ;
}
2008-04-21 21:57:09 +04:00
2008-04-21 21:10:29 +04:00
* sep + + = ' \0 ' ;
tmp2 = sep ;
if ( ( sep = strchr_m ( tmp2 , ' / ' ) ) ! = NULL ) {
/*
* Convert to smb : //[username:password@]workgroup/server/printer...
*/
* sep + + = ' \0 ' ;
workgroup = uri_unescape_alloc ( tmp ) ;
server = uri_unescape_alloc ( tmp2 ) ;
printer = uri_unescape_alloc ( sep ) ;
} else {
workgroup = NULL ;
server = uri_unescape_alloc ( tmp ) ;
printer = uri_unescape_alloc ( tmp2 ) ;
}
if ( ( sep = strrchr_m ( server , ' : ' ) ) ! = NULL ) {
* sep + + = ' \0 ' ;
port = atoi ( sep ) ;
2008-04-21 21:57:09 +04:00
} else {
2008-08-13 23:27:55 +04:00
port = 0 ;
2008-04-21 21:57:09 +04:00
}
2008-04-21 21:10:29 +04:00
/*
* Setup the SAMBA server state . . .
*/
2016-05-25 14:39:29 +03:00
setup_logging ( " smbspool " , DEBUG_STDERR ) ;
2008-04-21 21:10:29 +04:00
2015-03-21 22:00:06 +03:00
smb_init_locale ( ) ;
2008-04-21 21:10:29 +04:00
2017-07-24 13:27:50 +03:00
config_file = lp_default_path ( ) ;
if ( ! lp_load_client ( config_file ) ) {
fprintf ( stderr ,
" ERROR: Can't load %s - run testparm to debug it \n " ,
config_file ) ;
2008-04-21 21:10:29 +04:00
goto done ;
}
2008-04-21 21:57:09 +04:00
if ( workgroup = = NULL ) {
2008-04-21 21:10:29 +04:00
workgroup = lp_workgroup ( ) ;
2008-04-21 21:57:09 +04:00
}
2008-04-21 21:10:29 +04:00
load_interfaces ( ) ;
do {
2019-05-14 12:35:46 +03:00
nt_status = smb_connect ( & cli ,
workgroup ,
server ,
port ,
printer ,
username ,
password ,
print_user ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
status = get_exit_code ( nt_status ) ;
if ( status = = 2 ) {
fprintf ( stderr ,
" DEBUG: Unable to connect to CIFS "
" host: %s " ,
nt_errstr ( nt_status ) ) ;
goto done ;
2008-04-21 22:19:22 +04:00
} else if ( getenv ( " CLASS " ) = = NULL ) {
2019-05-14 12:35:46 +03:00
fprintf ( stderr ,
" ERROR: Unable to connect to CIFS "
" host: %s. Will retry in 60 "
" seconds... \n " ,
nt_errstr ( nt_status ) ) ;
2008-04-21 21:10:29 +04:00
sleep ( 60 ) ;
tries + + ;
} else {
2019-05-14 12:35:46 +03:00
fprintf ( stderr ,
" ERROR: Unable to connect to CIFS "
" host: %s. Trying next printer... \n " ,
nt_errstr ( nt_status ) ) ;
2008-04-21 21:10:29 +04:00
goto done ;
}
}
2019-05-14 12:35:46 +03:00
} while ( ! NT_STATUS_IS_OK ( nt_status ) & & ( tries < MAX_RETRY_CONNECT ) ) ;
2008-04-21 21:10:29 +04:00
if ( cli = = NULL ) {
fprintf ( stderr , " ERROR: Unable to connect to CIFS host after (tried %d times) \n " , tries ) ;
goto done ;
}
2008-04-21 21:57:09 +04:00
2008-04-21 21:10:29 +04:00
/*
* Now that we are connected to the server , ignore SIGTERM so that we
* can finish out any page data the driver sends ( e . g . to eject the
* current page . . . Only ignore SIGTERM if we are printing data from
* stdin ( otherwise you can ' t cancel raw jobs . . . )
*/
2008-04-21 21:57:09 +04:00
if ( argc < 7 ) {
2008-04-21 21:10:29 +04:00
CatchSignal ( SIGTERM , SIG_IGN ) ;
2008-04-21 21:57:09 +04:00
}
2008-04-21 21:10:29 +04:00
/*
* Queue the job . . .
*/
2008-04-21 21:57:09 +04:00
for ( i = 0 ; i < copies ; i + + ) {
2019-03-12 13:40:30 +03:00
status = smb_print ( cli , print_title , fp ) ;
2008-04-21 21:57:09 +04:00
if ( status ! = 0 ) {
2008-04-21 21:10:29 +04:00
break ;
2008-04-21 21:57:09 +04:00
}
}
2008-04-21 21:10:29 +04:00
cli_shutdown ( cli ) ;
/*
* Return the queue status . . .
*/
done :
TALLOC_FREE ( frame ) ;
return ( status ) ;
1999-12-17 04:48:16 +03:00
}
2008-04-21 20:19:51 +04:00
/*
* ' get_exit_code ( ) ' - Get the backend exit code based on the current error .
*/
static int
2019-05-14 12:35:46 +03:00
get_exit_code ( NTSTATUS nt_status )
2008-04-21 20:19:51 +04:00
{
2019-05-14 12:35:46 +03:00
size_t i ;
2008-04-21 21:57:09 +04:00
/* List of NTSTATUS errors that are considered
* authentication errors
*/
2008-04-21 21:10:29 +04:00
static const NTSTATUS auth_errors [ ] =
2008-04-21 21:57:09 +04:00
{
2020-02-07 15:06:46 +03:00
NT_STATUS_ACCESS_DENIED ,
NT_STATUS_ACCESS_VIOLATION ,
NT_STATUS_ACCOUNT_DISABLED ,
2020-02-07 15:08:43 +03:00
NT_STATUS_ACCOUNT_LOCKED_OUT ,
2020-02-07 15:06:46 +03:00
NT_STATUS_ACCOUNT_RESTRICTION ,
2020-02-07 15:08:43 +03:00
NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ,
2020-02-07 15:06:46 +03:00
NT_STATUS_INVALID_ACCOUNT_NAME ,
2020-02-07 15:08:43 +03:00
NT_STATUS_INVALID_COMPUTER_NAME ,
2020-02-07 15:06:46 +03:00
NT_STATUS_INVALID_LOGON_HOURS ,
2020-02-07 15:08:43 +03:00
NT_STATUS_INVALID_WORKSTATION ,
2020-02-07 15:06:46 +03:00
NT_STATUS_LOGON_FAILURE ,
NT_STATUS_NO_SUCH_USER ,
2020-02-07 15:08:43 +03:00
NT_STATUS_NO_SUCH_DOMAIN ,
NT_STATUS_NO_LOGON_SERVERS ,
2020-02-07 15:06:46 +03:00
NT_STATUS_PASSWORD_EXPIRED ,
NT_STATUS_PRIVILEGE_NOT_HELD ,
NT_STATUS_SHARING_VIOLATION ,
NT_STATUS_WRONG_PASSWORD ,
2008-04-21 21:10:29 +04:00
} ;
2019-05-14 12:35:46 +03:00
fprintf ( stderr ,
" DEBUG: get_exit_code(nt_status=%s [%x]) \n " ,
nt_errstr ( nt_status ) , NT_STATUS_V ( nt_status ) ) ;
2008-04-21 21:10:29 +04:00
2008-04-21 21:57:09 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( auth_errors ) ; i + + ) {
if ( ! NT_STATUS_EQUAL ( nt_status , auth_errors [ i ] ) ) {
continue ;
}
2008-04-21 21:10:29 +04:00
2019-05-14 12:35:46 +03:00
fprintf ( stderr , " ATTR: auth-info-required=%s \n " , auth_info_required ) ;
2008-04-21 21:57:09 +04:00
/*
* 2 = authentication required . . .
*/
return ( 2 ) ;
}
2008-04-21 21:10:29 +04:00
/*
* 1 = fail
*/
return ( 1 ) ;
2008-04-21 20:19:51 +04:00
}
2001-03-16 22:17:04 +03:00
/*
* ' list_devices ( ) ' - List the available printers seen on the network . . .
*/
static void
list_devices ( void )
{
2008-04-21 21:10:29 +04:00
/*
* Eventually , search the local workgroup for available hosts and printers .
*/
2001-03-16 22:17:04 +03:00
2008-04-21 21:10:29 +04:00
puts ( " network smb \" Unknown \" \" Windows Printer via SAMBA \" " ) ;
2001-03-16 22:17:04 +03:00
}
2019-05-14 12:35:46 +03:00
static NTSTATUS
smb_complete_connection ( struct cli_state * * output_cli ,
const char * myname ,
2008-04-21 21:10:29 +04:00
const char * server ,
int port ,
const char * username ,
const char * password ,
const char * workgroup ,
const char * share ,
2019-11-11 19:47:42 +03:00
bool use_kerberos ,
bool fallback_after_kerberos )
1999-12-17 04:48:16 +03:00
{
2008-04-21 21:10:29 +04:00
struct cli_state * cli ; /* New connection */
NTSTATUS nt_status ;
2016-10-28 14:33:58 +03:00
struct cli_credentials * creds = NULL ;
2008-04-21 21:10:29 +04:00
/* Start the SMB connection */
nt_status = cli_start_connection ( & cli , myname , server , NULL , port ,
2019-11-11 19:47:42 +03:00
SMB_SIGNING_DEFAULT , 0 ) ;
2008-04-21 21:10:29 +04:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
fprintf ( stderr , " ERROR: Connection failed: %s \n " , nt_errstr ( nt_status ) ) ;
2019-05-14 12:35:46 +03:00
return nt_status ;
2008-04-21 21:10:29 +04:00
}
2008-04-21 21:57:09 +04:00
2016-10-28 14:33:58 +03:00
creds = cli_session_creds_init ( cli ,
username ,
workgroup ,
NULL , /* realm */
password ,
2016-10-30 18:21:31 +03:00
use_kerberos ,
2019-05-13 19:54:02 +03:00
fallback_after_kerberos ,
2016-10-30 18:21:31 +03:00
false , /* use_ccache */
false ) ; /* password_is_nt_hash */
2016-10-28 14:33:58 +03:00
if ( creds = = NULL ) {
fprintf ( stderr , " ERROR: cli_session_creds_init failed \n " ) ;
cli_shutdown ( cli ) ;
2019-05-14 12:35:46 +03:00
return NT_STATUS_NO_MEMORY ;
2016-10-28 14:33:58 +03:00
}
nt_status = cli_session_setup_creds ( cli , creds ) ;
2008-04-21 21:10:29 +04:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
fprintf ( stderr , " ERROR: Session setup failed: %s \n " , nt_errstr ( nt_status ) ) ;
cli_shutdown ( cli ) ;
2019-05-14 12:35:46 +03:00
return nt_status ;
2008-04-21 21:10:29 +04:00
}
2008-04-21 21:57:09 +04:00
2016-12-08 08:54:29 +03:00
nt_status = cli_tree_connect_creds ( cli , share , " ????? " , creds ) ;
2009-01-26 10:37:13 +03:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
fprintf ( stderr , " ERROR: Tree connect failed (%s) \n " ,
nt_errstr ( nt_status ) ) ;
2008-04-21 21:10:29 +04:00
cli_shutdown ( cli ) ;
2019-05-14 12:35:46 +03:00
return nt_status ;
2008-04-21 21:10:29 +04:00
}
2008-01-05 11:23:35 +03:00
2019-05-14 12:35:46 +03:00
* output_cli = cli ;
return NT_STATUS_OK ;
2005-05-09 20:04:27 +04:00
}
2017-07-11 10:41:08 +03:00
static bool kerberos_ccache_is_valid ( void ) {
krb5_context ctx ;
const char * ccache_name = NULL ;
krb5_ccache ccache = NULL ;
krb5_error_code code ;
2018-12-05 13:06:20 +03:00
code = smb_krb5_init_context_common ( & ctx ) ;
2017-07-11 10:41:08 +03:00
if ( code ! = 0 ) {
2018-12-05 13:06:20 +03:00
DBG_ERR ( " kerberos init context failed (%s) \n " ,
error_message ( code ) ) ;
2017-07-11 10:41:08 +03:00
return false ;
}
ccache_name = krb5_cc_default_name ( ctx ) ;
if ( ccache_name = = NULL ) {
2019-05-16 19:24:32 +03:00
DBG_ERR ( " Failed to get default ccache name \n " ) ;
2018-11-21 12:21:46 +03:00
krb5_free_context ( ctx ) ;
2017-07-11 10:41:08 +03:00
return false ;
}
code = krb5_cc_resolve ( ctx , ccache_name , & ccache ) ;
if ( code ! = 0 ) {
2019-05-16 19:24:32 +03:00
DBG_ERR ( " Failed to resolve ccache name: %s \n " ,
ccache_name ) ;
2017-07-11 10:41:08 +03:00
krb5_free_context ( ctx ) ;
return false ;
} else {
krb5_principal default_princ = NULL ;
2019-05-16 14:41:02 +03:00
char * princ_name = NULL ;
2017-07-11 10:41:08 +03:00
code = krb5_cc_get_principal ( ctx ,
ccache ,
& default_princ ) ;
if ( code ! = 0 ) {
2019-05-16 19:24:32 +03:00
DBG_ERR ( " Failed to get default principal from "
" ccache: %s \n " ,
ccache_name ) ;
2017-07-11 10:41:08 +03:00
krb5_cc_close ( ctx , ccache ) ;
krb5_free_context ( ctx ) ;
return false ;
}
2019-05-16 14:41:02 +03:00
code = krb5_unparse_name ( ctx ,
default_princ ,
& princ_name ) ;
if ( code = = 0 ) {
fprintf ( stderr ,
" DEBUG: Try to authenticate as %s \n " ,
princ_name ) ;
krb5_free_unparsed_name ( ctx , princ_name ) ;
}
2017-07-11 10:41:08 +03:00
krb5_free_principal ( ctx , default_princ ) ;
}
krb5_cc_close ( ctx , ccache ) ;
krb5_free_context ( ctx ) ;
return true ;
}
2005-05-09 20:04:27 +04:00
/*
* ' smb_connect ( ) ' - Return a connection to a server .
*/
2019-05-14 12:35:46 +03:00
static NTSTATUS
smb_connect ( struct cli_state * * output_cli ,
const char * workgroup , /* I - Workgroup */
2008-04-21 21:10:29 +04:00
const char * server , /* I - Server */
const int port , /* I - Port */
const char * share , /* I - Printer */
const char * username , /* I - Username */
const char * password , /* I - Password */
2019-05-14 12:35:46 +03:00
const char * jobusername ) /* I - User who issued the print job */
{
struct cli_state * cli = NULL ; /* New connection */
2008-04-21 21:10:29 +04:00
char * myname = NULL ; /* Client name */
struct passwd * pwd ;
2019-05-13 19:54:02 +03:00
bool use_kerberos = false ;
2019-11-11 19:47:42 +03:00
bool fallback_after_kerberos = false ;
2019-05-13 19:54:02 +03:00
const char * user = username ;
2019-05-14 12:35:46 +03:00
NTSTATUS nt_status ;
2008-04-21 21:10:29 +04:00
/*
* Get the names and addresses of the client and server . . .
*/
2009-02-13 12:56:34 +03:00
myname = get_myname ( talloc_tos ( ) ) ;
2008-04-21 21:10:29 +04:00
if ( ! myname ) {
2019-05-14 12:35:46 +03:00
return NT_STATUS_NO_MEMORY ;
2008-04-21 21:10:29 +04:00
}
2008-04-21 21:57:09 +04:00
2008-04-21 21:10:29 +04:00
2019-05-14 12:35:46 +03:00
if ( strcmp ( auth_info_required , " negotiate " ) = = 0 ) {
2019-05-13 19:54:02 +03:00
if ( ! kerberos_ccache_is_valid ( ) ) {
2019-05-14 12:35:46 +03:00
fprintf ( stderr ,
2019-11-03 01:47:51 +03:00
" ERROR: No valid Kerberos credential cache found! "
" Using smbspool_krb5_wrapper may help. \n " ) ;
2019-05-14 12:35:46 +03:00
return NT_STATUS_LOGON_FAILURE ;
2008-04-21 21:10:29 +04:00
}
2019-05-13 19:54:02 +03:00
user = jobusername ;
use_kerberos = true ;
fprintf ( stderr ,
" DEBUG: Try to connect using Kerberos ... \n " ) ;
2019-05-14 12:35:46 +03:00
} else if ( strcmp ( auth_info_required , " username,password " ) = = 0 ) {
if ( username = = NULL ) {
return NT_STATUS_INVALID_ACCOUNT_NAME ;
2019-05-13 19:54:02 +03:00
}
/* Fallback to NTLM */
2019-11-11 19:47:42 +03:00
fallback_after_kerberos = true ;
2019-05-13 19:54:02 +03:00
fprintf ( stderr ,
" DEBUG: Try to connect using username/password ... \n " ) ;
2019-10-28 11:35:34 +03:00
} else if ( strcmp ( auth_info_required , " none " ) = = 0 ) {
goto anonymous ;
} else if ( strcmp ( auth_info_required , " samba " ) = = 0 ) {
2019-05-14 12:35:46 +03:00
if ( username ! = NULL ) {
2019-11-11 19:47:42 +03:00
fallback_after_kerberos = true ;
2019-05-14 12:35:46 +03:00
} else if ( kerberos_ccache_is_valid ( ) ) {
auth_info_required = " negotiate " ;
2019-05-13 19:54:02 +03:00
2019-05-14 12:35:46 +03:00
user = jobusername ;
use_kerberos = true ;
} else {
fprintf ( stderr ,
" DEBUG: This backend requires credentials! \n " ) ;
return NT_STATUS_ACCESS_DENIED ;
}
2019-10-28 11:35:34 +03:00
} else {
return NT_STATUS_ACCESS_DENIED ;
2008-04-21 21:10:29 +04:00
}
2008-04-21 21:57:09 +04:00
2019-05-14 12:35:46 +03:00
nt_status = smb_complete_connection ( & cli ,
myname ,
server ,
port ,
user ,
password ,
workgroup ,
share ,
2019-11-11 19:47:42 +03:00
true , /* try kerberos */
fallback_after_kerberos ) ;
2019-05-14 12:35:46 +03:00
if ( NT_STATUS_IS_OK ( nt_status ) ) {
2019-05-13 19:54:02 +03:00
fprintf ( stderr , " DEBUG: SMB connection established. \n " ) ;
2019-05-14 12:35:46 +03:00
* output_cli = cli ;
return NT_STATUS_OK ;
2017-07-11 10:41:08 +03:00
}
2019-05-13 19:54:02 +03:00
if ( ! use_kerberos ) {
fprintf ( stderr , " ERROR: SMB connection failed! \n " ) ;
2019-05-14 12:35:46 +03:00
return nt_status ;
2008-04-21 21:10:29 +04:00
}
2008-04-21 21:57:09 +04:00
2008-04-21 21:10:29 +04:00
/* give a chance for a passwordless NTLMSSP session setup */
pwd = getpwuid ( geteuid ( ) ) ;
if ( pwd = = NULL ) {
2019-05-14 12:35:46 +03:00
return NT_STATUS_ACCESS_DENIED ;
}
nt_status = smb_complete_connection ( & cli ,
myname ,
server ,
port ,
pwd - > pw_name ,
" " ,
workgroup ,
share ,
2019-11-11 19:47:42 +03:00
false , false ) ;
2019-05-14 12:35:46 +03:00
if ( NT_STATUS_IS_OK ( nt_status ) ) {
2008-04-21 21:10:29 +04:00
fputs ( " DEBUG: Connected with NTLMSSP... \n " , stderr ) ;
2019-05-14 12:35:46 +03:00
* output_cli = cli ;
return NT_STATUS_OK ;
2008-04-21 21:10:29 +04:00
}
2008-04-21 21:57:09 +04:00
2008-04-21 21:10:29 +04:00
/*
* last try . Use anonymous authentication
*/
2019-10-28 11:35:34 +03:00
anonymous :
2019-05-14 12:35:46 +03:00
nt_status = smb_complete_connection ( & cli ,
myname ,
server ,
port ,
" " ,
" " ,
workgroup ,
share ,
2019-11-11 19:47:42 +03:00
false , false ) ;
2019-05-14 12:35:46 +03:00
if ( NT_STATUS_IS_OK ( nt_status ) ) {
* output_cli = cli ;
return NT_STATUS_OK ;
}
return nt_status ;
1999-12-17 04:48:16 +03:00
}
/*
* ' smb_print ( ) ' - Queue a job for printing using the SMB protocol .
*/
2008-04-21 21:10:29 +04:00
static int /* O - 0 = success, non-0 = failure */
smb_print ( struct cli_state * cli , /* I - SMB connection */
2019-03-12 12:09:14 +03:00
const char * print_title , /* I - Title/job name */
2008-04-21 21:10:29 +04:00
FILE * fp )
{ /* I - File to print */
2009-05-01 02:26:43 +04:00
uint16_t fnum ; /* File number */
2008-04-21 21:10:29 +04:00
int nbytes , /* Number of bytes read */
tbytes ; /* Total bytes read */
char buffer [ 8192 ] , /* Buffer for copy */
2008-04-21 21:57:09 +04:00
* ptr ; /* Pointer into title */
2019-03-12 12:09:14 +03:00
char title [ 1024 ] = { 0 } ;
int len ;
2011-01-16 23:13:29 +03:00
NTSTATUS nt_status ;
2008-04-21 21:10:29 +04:00
/*
2019-03-12 12:09:14 +03:00
* Sanitize the title . . .
*/
len = snprintf ( title , sizeof ( title ) , " %s " , print_title ) ;
if ( len ! = strlen ( print_title ) ) {
return 2 ;
}
2008-04-21 21:10:29 +04:00
2008-04-21 21:57:09 +04:00
for ( ptr = title ; * ptr ; ptr + + ) {
if ( ! isalnum ( ( int ) * ptr ) & & ! isspace ( ( int ) * ptr ) ) {
2008-04-21 21:10:29 +04:00
* ptr = ' _ ' ;
2008-04-21 21:57:09 +04:00
}
}
2008-04-21 21:10:29 +04:00
/*
* Open the printer device . . .
*/
2011-12-04 09:36:47 +04:00
nt_status = cli_open ( cli , title , O_RDWR | O_CREAT | O_TRUNC , DENY_NONE ,
2011-01-16 23:13:29 +03:00
& fnum ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
2008-04-21 21:10:29 +04:00
fprintf ( stderr , " ERROR: %s opening remote spool %s \n " ,
2011-01-16 23:13:29 +03:00
nt_errstr ( nt_status ) , title ) ;
2019-05-14 12:35:46 +03:00
return get_exit_code ( nt_status ) ;
2008-04-21 21:10:29 +04:00
}
2008-04-21 21:57:09 +04:00
2008-04-21 21:10:29 +04:00
/*
* Copy the file to the printer . . .
*/
if ( fp ! = stdin )
rewind ( fp ) ;
tbytes = 0 ;
while ( ( nbytes = fread ( buffer , 1 , sizeof ( buffer ) , fp ) ) > 0 ) {
2011-04-02 13:46:30 +04:00
NTSTATUS status ;
status = cli_writeall ( cli , fnum , 0 , ( uint8_t * ) buffer ,
tbytes , nbytes , NULL ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2019-05-14 12:35:46 +03:00
int ret = get_exit_code ( status ) ;
2011-04-02 13:46:30 +04:00
fprintf ( stderr , " ERROR: Error writing spool: %s \n " ,
nt_errstr ( status ) ) ;
fprintf ( stderr , " DEBUG: Returning status %d... \n " ,
ret ) ;
2008-04-21 21:10:29 +04:00
cli_close ( cli , fnum ) ;
2011-04-02 13:46:30 +04:00
return ( ret ) ;
2008-04-21 21:10:29 +04:00
}
tbytes + = nbytes ;
}
2011-01-16 23:13:29 +03:00
nt_status = cli_close ( cli , fnum ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
2008-04-21 21:10:29 +04:00
fprintf ( stderr , " ERROR: %s closing remote spool %s \n " ,
2011-01-16 23:13:29 +03:00
nt_errstr ( nt_status ) , title ) ;
2019-05-14 12:35:46 +03:00
return get_exit_code ( nt_status ) ;
2008-04-21 21:57:09 +04:00
} else {
2008-04-21 21:10:29 +04:00
return ( 0 ) ;
2008-04-21 21:57:09 +04:00
}
1999-12-17 04:48:16 +03:00
}
2007-06-16 22:54:13 +04:00
2008-04-21 21:57:09 +04:00
static char *
2008-04-21 21:10:29 +04:00
uri_unescape_alloc ( const char * uritok )
2007-06-16 22:54:13 +04:00
{
2008-04-21 21:57:09 +04:00
char * ret ;
2018-02-17 00:46:44 +03:00
char * end ;
2008-04-21 21:10:29 +04:00
ret = ( char * ) SMB_STRDUP ( uritok ) ;
2008-04-21 21:57:09 +04:00
if ( ! ret ) {
2008-04-21 21:10:29 +04:00
return NULL ;
2008-04-21 21:57:09 +04:00
}
2007-06-16 22:54:13 +04:00
2018-02-17 00:46:44 +03:00
end = rfc1738_unescape ( ret ) ;
if ( end = = NULL ) {
free ( ret ) ;
return NULL ;
}
2007-06-16 22:54:13 +04:00
return ret ;
}