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 .
2009-12-19 01:28:22 +03:00
Setting eclass and ecode to zero and status to a valid NT error will
reply with an NT error if the client supports CAP_STATUS32 , otherwise
it maps to and returns a DOS error if the client doesn ' t support CAP_STATUS32 .
This is the normal mode of calling this function via reply_nterror ( req , status ) .
Setting eclass and ecode to non - zero and status to NT_STATUS_OK ( 0 ) will map
from a DOS error to an NT error and reply with an NT error if the client
supports CAP_STATUS32 , otherwise it replies with the given DOS error .
2009-12-21 22:16:38 +03:00
This mode is currently not used in the server .
2009-12-19 01:28:22 +03:00
Setting both eclass , ecode and status to non - zero values allows a non - default
mapping from NT error codes to DOS error codes , and will return one or the
other depending on the client supporting CAP_STATUS32 or not . This is the
path taken by calling reply_botherror ( req , eclass , ecode , status ) ;
Setting status to NT_STATUS_DOS ( eclass , ecode ) forces DOS errors even if the
client supports CAP_STATUS32 . This is the path taken to force a DOS error
2009-12-21 22:16:38 +03:00
reply by calling reply_force_doserror ( req , eclass , ecode ) .
2009-12-19 01:28:22 +03:00
Setting status only and eclass to - 1 forces NT errors even if the client
doesn ' t support CAP_STATUS32 . This mode is currently never used in the
server .
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 ) ;
}
2009-12-19 01:28:22 +03:00
/****************************************************************************
2009-12-21 22:16:38 +03:00
Forces a DOS error on the wire .
2009-12-19 01:28:22 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-08-10 14:28:09 +04:00
2009-12-21 22:16:38 +03:00
void reply_force_dos_error ( struct smb_request * req , uint8 eclass , uint32 ecode ,
2007-07-23 13:36:09 +04:00
int line , const char * file )
{
TALLOC_FREE ( req - > outbuf ) ;
reply_outbuf ( req , 0 , 0 ) ;
2009-12-19 01:28:22 +03:00
error_packet_set ( ( char * ) req - > outbuf ,
eclass , ecode ,
2009-12-21 22:16:38 +03:00
NT_STATUS_DOS ( eclass , ecode ) ,
2009-12-19 01:28:22 +03:00
line ,
file ) ;
2007-07-23 13:36:09 +04:00
}
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 ) ;
2009-12-18 05:31:44 +03:00
} else if ( NT_STATUS_EQUAL ( status , NT_STATUS_TOO_MANY_OPENED_FILES ) ) {
/* EMFILE always seems to be returned as a DOS error.
2009-12-19 01:28:22 +03:00
* See bug 6837. NOTE this forces a DOS error on the wire
* even though it ' s calling reply_nterror ( ) . */
2009-12-21 22:16:38 +03:00
reply_force_doserror ( req , ERRDOS , ERRnofids ) ;
2007-12-27 04:12:36 +03:00
} else {
reply_nterror ( req , status ) ;
}
}