1998-08-17 17:11:34 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1998-08-17 17:11:34 +04:00
error packet handling
Copyright ( C ) Andrew Tridgell 1992 - 1998
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
1998-08-17 17:11:34 +04:00
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
1998-08-17 17:11:34 +04:00
*/
# include "includes.h"
2009-01-08 14:03:45 +03:00
# include "smbd/globals.h"
1998-08-17 17:11:34 +04:00
2002-01-17 00:27:57 +03:00
/* From lib/error.c */
extern struct unix_error_map unix_dos_nt_errmap [ ] ;
2007-10-19 04:40:25 +04:00
bool use_nt_status ( void )
2006-07-11 22:01:26 +04:00
{
return lp_nt_status_support ( ) & & ( global_client_caps & CAP_STATUS32 ) ;
}
1998-08-17 17:11:34 +04:00
/****************************************************************************
2002-01-17 00:27:57 +03:00
Create an error packet . Normally called using the ERROR ( ) macro .
2005-04-02 03:11:28 +04:00
Setting eclass and ecode only and status to NT_STATUS_OK forces DOS errors .
Setting status only and eclass and ecode to zero forces NT errors .
If the override errors are set they take precedence over any passed in values .
1998-08-17 17:11:34 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-01-17 00:27:57 +03:00
2006-08-14 20:53:14 +04:00
void error_packet_set ( char * outbuf , uint8 eclass , uint32 ecode , NTSTATUS ntstatus , int line , const char * file )
1998-08-17 17:11:34 +04:00
{
2007-10-19 04:40:25 +04:00
bool force_nt_status = False ;
bool force_dos_status = False ;
2005-04-02 03:11:28 +04:00
if ( eclass = = ( uint8 ) - 1 ) {
force_nt_status = True ;
2006-07-11 22:01:26 +04:00
} else if ( NT_STATUS_IS_DOS ( ntstatus ) ) {
2005-04-02 03:11:28 +04:00
force_dos_status = True ;
}
if ( force_nt_status | | ( ! force_dos_status & & lp_nt_status_support ( ) & & ( global_client_caps & CAP_STATUS32 ) ) ) {
/* We're returning an NT error. */
if ( NT_STATUS_V ( ntstatus ) = = 0 & & eclass ) {
2001-08-27 12:19:43 +04:00
ntstatus = dos_to_ntstatus ( eclass , ecode ) ;
2005-04-02 03:11:28 +04:00
}
2001-08-27 21:52:23 +04:00
SIVAL ( outbuf , smb_rcls , NT_STATUS_V ( ntstatus ) ) ;
2001-08-27 12:19:43 +04:00
SSVAL ( outbuf , smb_flg2 , SVAL ( outbuf , smb_flg2 ) | FLAGS2_32_BIT_ERROR_CODES ) ;
2001-09-05 14:18:58 +04:00
DEBUG ( 3 , ( " error packet at %s(%d) cmd=%d (%s) %s \n " ,
file , line ,
2001-08-27 12:19:43 +04:00
( int ) CVAL ( outbuf , smb_com ) ,
smb_fn_name ( CVAL ( outbuf , smb_com ) ) ,
2002-03-17 07:36:35 +03:00
nt_errstr ( ntstatus ) ) ) ;
2005-04-02 03:11:28 +04:00
} else {
/* We're returning a DOS error only. */
2006-07-11 22:01:26 +04:00
if ( NT_STATUS_IS_DOS ( ntstatus ) ) {
eclass = NT_STATUS_DOS_CLASS ( ntstatus ) ;
ecode = NT_STATUS_DOS_CODE ( ntstatus ) ;
} else if ( eclass = = 0 & & NT_STATUS_V ( ntstatus ) ) {
2005-04-02 03:11:28 +04:00
ntstatus_to_dos ( ntstatus , & eclass , & ecode ) ;
}
SSVAL ( outbuf , smb_flg2 , SVAL ( outbuf , smb_flg2 ) & ~ FLAGS2_32_BIT_ERROR_CODES ) ;
SSVAL ( outbuf , smb_rcls , eclass ) ;
SSVAL ( outbuf , smb_err , ecode ) ;
DEBUG ( 3 , ( " error packet at %s(%d) cmd=%d (%s) eclass=%d ecode=%d \n " ,
file , line ,
( int ) CVAL ( outbuf , smb_com ) ,
smb_fn_name ( CVAL ( outbuf , smb_com ) ) ,
eclass ,
ecode ) ) ;
}
2006-08-14 20:53:14 +04:00
}
2001-08-27 12:19:43 +04:00
2008-01-04 23:56:23 +03:00
int error_packet ( char * outbuf , uint8 eclass , uint32 ecode , NTSTATUS ntstatus , int line , const char * file )
2006-08-14 20:53:14 +04:00
{
2008-01-04 23:56:23 +03:00
int outsize = srv_set_message ( outbuf , 0 , 0 , True ) ;
2006-08-14 20:53:14 +04:00
error_packet_set ( outbuf , eclass , ecode , ntstatus , line , file ) ;
2001-08-27 12:19:43 +04:00
return outsize ;
1998-08-17 17:11:34 +04:00
}
2007-07-23 13:36:09 +04:00
void reply_nt_error ( struct smb_request * req , NTSTATUS ntstatus ,
int line , const char * file )
{
TALLOC_FREE ( req - > outbuf ) ;
reply_outbuf ( req , 0 , 0 ) ;
error_packet_set ( ( char * ) req - > outbuf , 0 , 0 , ntstatus , line , file ) ;
}
2007-08-10 14:28:09 +04:00
void reply_force_nt_error ( struct smb_request * req , NTSTATUS ntstatus ,
int line , const char * file )
{
TALLOC_FREE ( req - > outbuf ) ;
reply_outbuf ( req , 0 , 0 ) ;
error_packet_set ( ( char * ) req - > outbuf , - 1 , - 1 , ntstatus , line , file ) ;
}
2007-07-23 13:36:09 +04:00
void reply_dos_error ( struct smb_request * req , uint8 eclass , uint32 ecode ,
int line , const char * file )
{
TALLOC_FREE ( req - > outbuf ) ;
reply_outbuf ( req , 0 , 0 ) ;
error_packet_set ( ( char * ) req - > outbuf , eclass , ecode , NT_STATUS_OK , line ,
file ) ;
}
void reply_both_error ( struct smb_request * req , uint8 eclass , uint32 ecode ,
NTSTATUS status , int line , const char * file )
{
TALLOC_FREE ( req - > outbuf ) ;
reply_outbuf ( req , 0 , 0 ) ;
error_packet_set ( ( char * ) req - > outbuf , eclass , ecode , status ,
line , file ) ;
}
2007-07-30 14:23:26 +04:00
2007-12-27 04:12:36 +03:00
void reply_openerror ( struct smb_request * req , NTSTATUS status )
{
if ( NT_STATUS_EQUAL ( status , NT_STATUS_OBJECT_NAME_COLLISION ) ) {
/*
* We hit an existing file , and if we ' re returning DOS
* error codes OBJECT_NAME_COLLISION would map to
* ERRDOS / 183 , we need to return ERRDOS / 80 , see bug
* 4852.
*/
reply_botherror ( req , NT_STATUS_OBJECT_NAME_COLLISION ,
ERRDOS , ERRfilexists ) ;
} else {
reply_nterror ( req , status ) ;
}
}