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"
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 . . .
*/
2008-04-21 21:10:29 +04:00
static int get_exit_code ( struct cli_state * cli , NTSTATUS nt_status ) ;
static void list_devices ( void ) ;
2008-04-21 22:19:22 +04:00
static struct cli_state * smb_complete_connection ( const char * , const char * ,
int , const char * , const char * , const char * , const char * , int , bool * need_auth ) ;
static struct cli_state * smb_connect ( const char * , const char * , int , const
char * , const char * , const char * , const char * , bool * need_auth ) ;
2008-04-21 21:10:29 +04:00
static int smb_print ( struct cli_state * , char * , FILE * ) ;
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
/*
* ' 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 */
* tmp , * tmp2 , /* Temp pointers to do escaping */
* password ; /* Password */
char * username , /* Username */
* server , /* Server name */
* printer ; /* Printer name */
const char * workgroup ; /* Workgroup */
FILE * fp ; /* File to print */
int status = 1 ; /* Status of LPD job */
struct cli_state * cli ; /* SMB interface */
char null_str [ 1 ] ;
int tries = 0 ;
2008-04-21 22:19:22 +04:00
bool need_auth = true ;
2008-04-21 21:10:29 +04:00
const char * dev_uri ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
null_str [ 0 ] = ' \0 ' ;
/*
* we expect the URI in argv [ 0 ] . Detect the case where it is in
* argv [ 1 ] and cope
*/
2008-04-21 21:57:09 +04:00
if ( argc > 2 & & strncmp ( argv [ 0 ] , " smb:// " , 6 ) & &
strncmp ( argv [ 1 ] , " smb:// " , 6 ) = = 0 ) {
2008-04-21 21:10:29 +04:00
argv + + ;
argc - - ;
}
2008-04-21 21:57:09 +04:00
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
2008-04-21 21:10:29 +04:00
if ( argc < 6 | | argc > 7 ) {
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
/*
* If we have 7 arguments , print the file named on the command - line .
* Otherwise , print data from stdin . . .
*/
if ( argc = = 6 ) {
/*
* Print from Copy stdin to a temporary file . . .
*/
fp = stdin ;
copies = 1 ;
} else if ( ( fp = fopen ( argv [ 6 ] , " rb " ) ) = = NULL ) {
perror ( " ERROR: Unable to open print file " ) ;
goto done ;
2008-04-21 21:57:09 +04:00
} else {
2008-04-21 21:10:29 +04:00
copies = atoi ( argv [ 4 ] ) ;
2008-04-21 21:57:09 +04:00
}
2008-04-21 21:10:29 +04:00
/*
* Find the URI . . .
*/
dev_uri = getenv ( " DEVICE_URI " ) ;
2008-04-21 21:57:09 +04:00
if ( dev_uri ) {
2008-04-21 21:10:29 +04:00
strncpy ( uri , dev_uri , sizeof ( uri ) - 1 ) ;
2008-04-21 21:57:09 +04:00
} else if ( strncmp ( argv [ 0 ] , " smb:// " , 6 ) = = 0 ) {
2008-04-21 21:10:29 +04:00
strncpy ( uri , argv [ 0 ] , sizeof ( uri ) - 1 ) ;
2008-04-21 21:57:09 +04:00
} else {
2008-04-21 21:10:29 +04:00
fputs ( " ERROR: No device URI found in DEVICE_URI environment variable or argv[0] ! \n " , stderr ) ;
goto done ;
}
uri [ sizeof ( uri ) - 1 ] = ' \0 ' ;
/*
* 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 ) ;
} else {
password = null_str ;
}
username = uri_unescape_alloc ( tmp ) ;
} else {
2008-04-21 21:57:09 +04:00
if ( ( username = getenv ( " AUTH_USERNAME " ) ) = = NULL ) {
2008-04-21 21:10:29 +04:00
username = null_str ;
2008-04-21 21:57:09 +04:00
}
2008-04-21 21:10:29 +04:00
2008-04-21 21:57:09 +04:00
if ( ( password = getenv ( " AUTH_PASSWORD " ) ) = = NULL ) {
2008-04-21 21:10:29 +04:00
password = null_str ;
2008-04-21 21:57:09 +04:00
}
2008-04-21 21:10:29 +04:00
server = uri + 6 ;
}
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 . . .
*/
setup_logging ( " smbspool " , True ) ;
lp_set_in_client ( True ) ; /* Make sure that we tell lp_load we are */
load_case_tables ( ) ;
if ( ! lp_load ( get_dyn_CONFIGFILE ( ) , True , False , False , True ) ) {
fprintf ( stderr , " ERROR: Can't load %s - run testparm to debug it \n " , get_dyn_CONFIGFILE ( ) ) ;
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 {
2008-04-21 21:57:09 +04:00
cli = smb_connect ( workgroup , server , port , printer ,
username , password , argv [ 2 ] , & need_auth ) ;
if ( cli = = NULL ) {
2008-04-21 22:19:22 +04:00
if ( need_auth ) {
2008-04-21 21:10:29 +04:00
exit ( 2 ) ;
2008-04-21 22:19:22 +04:00
} else if ( getenv ( " CLASS " ) = = NULL ) {
2008-04-21 21:10:29 +04:00
fprintf ( stderr , " ERROR: Unable to connect to CIFS host, will retry in 60 seconds... \n " ) ;
sleep ( 60 ) ;
tries + + ;
} else {
fprintf ( stderr , " ERROR: Unable to connect to CIFS host, trying next printer... \n " ) ;
goto done ;
}
}
2008-04-21 21:57:09 +04:00
} while ( ( cli = = NULL ) & & ( 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 + + ) {
status = smb_print ( cli , argv [ 3 ] /* title */ , fp ) ;
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
2008-04-21 21:10:29 +04:00
get_exit_code ( struct cli_state * cli ,
NTSTATUS nt_status )
2008-04-21 20:19:51 +04:00
{
2008-04-21 21:57:09 +04:00
int i ;
/* 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
{
2008-04-21 21:10:29 +04:00
NT_STATUS_ACCESS_DENIED , NT_STATUS_ACCESS_VIOLATION ,
NT_STATUS_SHARING_VIOLATION , NT_STATUS_PRIVILEGE_NOT_HELD ,
NT_STATUS_INVALID_ACCOUNT_NAME , NT_STATUS_NO_SUCH_USER ,
NT_STATUS_WRONG_PASSWORD , NT_STATUS_LOGON_FAILURE ,
NT_STATUS_ACCOUNT_RESTRICTION , NT_STATUS_INVALID_LOGON_HOURS ,
NT_STATUS_PASSWORD_EXPIRED , NT_STATUS_ACCOUNT_DISABLED
} ;
2008-04-21 22:19:22 +04:00
fprintf ( stderr , " DEBUG: get_exit_code(cli=%p, nt_status=%x) \n " ,
cli , 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
2008-04-21 21:57:09 +04:00
if ( cli ) {
2008-08-08 04:55:57 +04:00
if ( cli - > use_kerberos & & cli - > got_kerberos_mechanism )
2008-04-21 21:57:09 +04:00
fputs ( " ATTR: auth-info-required=negotiate \n " , stderr ) ;
else
fputs ( " ATTR: auth-info-required=username,password \n " , stderr ) ;
2008-04-21 21:10:29 +04:00
}
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
}
2008-04-21 21:57:09 +04:00
static struct cli_state *
2008-04-21 21:10:29 +04:00
smb_complete_connection ( const char * myname ,
const char * server ,
int port ,
const char * username ,
const char * password ,
const char * workgroup ,
const char * share ,
int flags ,
2008-04-21 22:19:22 +04:00
bool * need_auth )
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 ;
/* Start the SMB connection */
2008-04-21 22:19:22 +04:00
* need_auth = false ;
2008-04-21 21:10:29 +04:00
nt_status = cli_start_connection ( & cli , myname , server , NULL , port ,
Undefined , flags , NULL ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
fprintf ( stderr , " ERROR: Connection failed: %s \n " , nt_errstr ( nt_status ) ) ;
return NULL ;
}
2008-04-21 21:57:09 +04:00
2008-04-21 21:10:29 +04:00
/*
* We pretty much guarantee password must be valid or a pointer to a
* 0 char .
*/
if ( ! password ) {
2008-04-21 22:19:22 +04:00
* need_auth = true ;
2008-04-21 21:10:29 +04:00
return NULL ;
}
2008-04-21 21:57:09 +04:00
2008-04-21 21:10:29 +04:00
nt_status = cli_session_setup ( cli , username ,
password , strlen ( password ) + 1 ,
password , strlen ( password ) + 1 ,
workgroup ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
fprintf ( stderr , " ERROR: Session setup failed: %s \n " , nt_errstr ( nt_status ) ) ;
2008-04-21 21:57:09 +04:00
if ( get_exit_code ( cli , nt_status ) = = 2 ) {
2008-04-21 22:19:22 +04:00
* need_auth = true ;
2008-04-21 21:57:09 +04:00
}
2008-04-21 21:10:29 +04:00
cli_shutdown ( cli ) ;
return NULL ;
}
2008-04-21 21:57:09 +04:00
2008-04-21 21:10:29 +04:00
if ( ! cli_send_tconX ( cli , share , " ????? " , password , strlen ( password ) + 1 ) ) {
fprintf ( stderr , " ERROR: Tree connect failed (%s) \n " , cli_errstr ( cli ) ) ;
2008-04-21 21:57:09 +04:00
if ( get_exit_code ( cli , cli_nt_error ( cli ) ) = = 2 ) {
2008-04-21 22:19:22 +04:00
* need_auth = true ;
2008-04-21 21:57:09 +04:00
}
2008-04-21 21:10:29 +04:00
cli_shutdown ( cli ) ;
return NULL ;
}
2008-01-05 11:23:35 +03:00
#if 0
2008-04-21 21:10:29 +04:00
/* Need to work out how to specify this on the URL. */
if ( smb_encrypt ) {
if ( ! cli_cm_force_encryption ( cli ,
username ,
password ,
workgroup ,
share ) ) {
fprintf ( stderr , " ERROR: encryption setup failed \n " ) ;
cli_shutdown ( cli ) ;
return NULL ;
}
}
2008-01-05 11:23:35 +03:00
# endif
2008-04-21 21:10:29 +04:00
return cli ;
2005-05-09 20:04:27 +04:00
}
/*
* ' smb_connect ( ) ' - Return a connection to a server .
*/
2008-04-21 21:10:29 +04:00
static struct cli_state * /* O - SMB connection */
2008-04-21 20:16:01 +04:00
smb_connect ( 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 */
const char * jobusername , /* I - User who issued the print job */
2008-04-21 22:19:22 +04:00
bool * need_auth )
2008-04-21 21:10:29 +04:00
{ /* O - Need authentication? */
struct cli_state * cli ; /* New connection */
char * myname = NULL ; /* Client name */
struct passwd * pwd ;
/*
* Get the names and addresses of the client and server . . .
*/
myname = get_myname ( talloc_tos ( ) ) ;
if ( ! myname ) {
return NULL ;
}
2008-04-21 21:57:09 +04:00
2008-04-21 21:10:29 +04:00
/*
* See if we have a username first . This is for backwards compatible
* behavior with 3.0 .14 a
*/
if ( username & & * username & & ! getenv ( " KRB5CCNAME " ) ) {
cli = smb_complete_connection ( myname , server , port , username ,
password , workgroup , share , 0 , need_auth ) ;
if ( cli ) {
fputs ( " DEBUG: Connected with username/password... \n " , stderr ) ;
return ( cli ) ;
}
}
2008-04-21 21:57:09 +04:00
2008-04-21 21:10:29 +04:00
/*
* Try to use the user kerberos credentials ( if any ) to authenticate
*/
cli = smb_complete_connection ( myname , server , port , jobusername , " " ,
workgroup , share ,
CLI_FULL_CONNECTION_USE_KERBEROS , need_auth ) ;
if ( cli ) {
fputs ( " DEBUG: Connected using Kerberos... \n " , stderr ) ;
return ( cli ) ;
}
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 ) {
return NULL ;
}
2008-04-21 21:57:09 +04:00
2008-04-21 21:10:29 +04:00
cli = smb_complete_connection ( myname , server , port , pwd - > pw_name , " " ,
workgroup , share , 0 , need_auth ) ;
if ( cli ) {
fputs ( " DEBUG: Connected with NTLMSSP... \n " , stderr ) ;
return ( cli ) ;
}
2008-04-21 21:57:09 +04:00
2008-04-21 21:10:29 +04:00
/*
* last try . Use anonymous authentication
*/
cli = smb_complete_connection ( myname , server , port , " " , " " ,
workgroup , share , 0 , need_auth ) ;
/*
* Return the new connection . . .
*/
return ( cli ) ;
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 */
char * title , /* I - Title/job name */
FILE * fp )
{ /* I - File to print */
int fnum ; /* File number */
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 */
2008-04-21 21:10:29 +04:00
/*
* Sanitize the title . . .
*/
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 . . .
*/
2008-04-21 21:57:09 +04:00
fnum = cli_open ( cli , title , O_RDWR | O_CREAT | O_TRUNC , DENY_NONE ) ;
if ( fnum = = - 1 ) {
2008-04-21 21:10:29 +04:00
fprintf ( stderr , " ERROR: %s opening remote spool %s \n " ,
cli_errstr ( cli ) , title ) ;
return ( get_exit_code ( cli , cli_nt_error ( cli ) ) ) ;
}
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 ) {
if ( cli_write ( cli , fnum , 0 , buffer , tbytes , nbytes ) ! = nbytes ) {
2008-04-21 21:57:09 +04:00
int status = get_exit_code ( cli , cli_nt_error ( cli ) ) ;
2008-04-21 21:10:29 +04:00
fprintf ( stderr , " ERROR: Error writing spool: %s \n " , cli_errstr ( cli ) ) ;
fprintf ( stderr , " DEBUG: Returning status %d... \n " , status ) ;
cli_close ( cli , fnum ) ;
return ( status ) ;
}
tbytes + = nbytes ;
}
if ( ! cli_close ( cli , fnum ) ) {
fprintf ( stderr , " ERROR: %s closing remote spool %s \n " ,
cli_errstr ( cli ) , title ) ;
return ( get_exit_code ( cli , cli_nt_error ( cli ) ) ) ;
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 ;
2007-06-16 22:54:13 +04:00
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
2007-06-17 02:52:51 +04:00
rfc1738_unescape ( ret ) ;
2007-06-16 22:54:13 +04:00
return ret ;
}