You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
721 lines
20 KiB
721 lines
20 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
srvstat.c
|
|
|
|
Abstract:
|
|
|
|
Contains data and modules for error handling.
|
|
|
|
Author:
|
|
|
|
David Treadwell (davidtr) 10-May-1990
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#include "srvstat.tmh"
|
|
#pragma hdrstop
|
|
|
|
#define DISK_HARD_ERROR 0x38
|
|
|
|
NTSTATUS DbgBreakError = STATUS_SUCCESS;
|
|
|
|
VOID
|
|
MapErrorForDosClient (
|
|
IN PWORK_CONTEXT WorkContext,
|
|
IN ULONG Error,
|
|
OUT PUSHORT DosError,
|
|
OUT PUCHAR DosErrorClass
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text( PAGE, _SrvSetSmbError2 )
|
|
#pragma alloc_text( PAGE, MapErrorForDosClient )
|
|
#pragma alloc_text( PAGE8FIL, SrvSetBufferOverflowError )
|
|
#endif
|
|
|
|
|
|
VOID
|
|
_SrvSetSmbError2 (
|
|
IN PWORK_CONTEXT WorkContext,
|
|
IN NTSTATUS Status,
|
|
IN BOOLEAN HeaderOnly,
|
|
IN ULONG Line,
|
|
IN PCHAR File
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Loads error information into a response SMB. If the client is
|
|
NT, the status is placed directly into the outgoing SMB. If
|
|
the client is DOS or OS/2 and this is a special status code that
|
|
has the DOS/OS|2/SMB error code embedded, put the code and class
|
|
from the status code into the outgoing SMB. If that doesn't work,
|
|
use RtlNtStatusToDosError to try to map the status to an OS/2
|
|
error code, then map to DOS if necessary. If we still haven't
|
|
mapped it, use our own array to try to find a mapping. And,
|
|
finally, if that doesn't work, return the generic error code.
|
|
|
|
Arguments:
|
|
|
|
WorkContext - Supplies a pointer to the work context block for the
|
|
current SMB. In particular, the Connection block pointer is
|
|
used to find the negotiated dialect for the connection, and
|
|
the ResponseHeader and ResponseParameter pointers are used
|
|
to determine where to write the error information.
|
|
|
|
Status - Supplies an NT status code.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PSMB_HEADER header = WorkContext->ResponseHeader;
|
|
PSMB_PARAMS params = WorkContext->ResponseParameters;
|
|
SMB_DIALECT smbDialect;
|
|
|
|
ULONG error;
|
|
CCHAR errorClass;
|
|
USHORT errorCode;
|
|
USHORT flags;
|
|
|
|
PAGED_CODE( );
|
|
|
|
if( (DbgBreakError != STATUS_SUCCESS) &&
|
|
(Status == DbgBreakError) )
|
|
{
|
|
DbgPrint( "Caught error %x\n", DbgBreakError );
|
|
DbgPrint( "WorkContext = %p, Line = %d, File = %x\n", WorkContext, Line, File );
|
|
DbgBreakPoint();
|
|
}
|
|
|
|
IF_DEBUG( ERRORS ) { \
|
|
KdPrint(( "SrvSetSmbError %X (%s,%d)\n",Status,File,Line )); \
|
|
}
|
|
|
|
smbDialect = WorkContext->Connection->SmbDialect;
|
|
|
|
//
|
|
// Update the SMB body, if necessary.
|
|
//
|
|
|
|
if ( !HeaderOnly ) {
|
|
params->WordCount = 0;
|
|
SmbPutUshort( ¶ms->ByteCount, 0 );
|
|
WorkContext->ResponseParameters = (PVOID)(params + 1);
|
|
}
|
|
|
|
//
|
|
// If the status code is a real NT status, then either return it
|
|
// directly to the client or map it to a Win32 error code.
|
|
//
|
|
|
|
if ( !SrvIsSrvStatus( Status ) ) {
|
|
|
|
//
|
|
// Map STATUS_INSUFFICIENT_RESOURCES to the server form. If we
|
|
// get an insufficient resources error from the system, we
|
|
// report it as a server shortage. This helps keep things
|
|
// clearer for the client.
|
|
//
|
|
|
|
if ( Status == STATUS_WORKING_SET_QUOTA ) {
|
|
Status = STATUS_INSUFF_SERVER_RESOURCES;
|
|
if( WorkContext->Rfcb )
|
|
{
|
|
PNT_SMB_HEADER pHeader = (PNT_SMB_HEADER)WorkContext->RequestHeader;
|
|
BOOL PagingIo = (pHeader->Flags2 & SMB_FLAGS2_PAGING_IO) ? TRUE : FALSE;
|
|
IF_SYSCACHE_RFCB( WorkContext->Rfcb ) {
|
|
KdPrint(("Op on %p failed with C00000A1, Paging=%d, Ofst=%x, Ln=%x\n", WorkContext->Rfcb, PagingIo,
|
|
WorkContext->Parameters.WriteAndX.Offset.u.LowPart, WorkContext->Parameters.WriteAndX.CurrentWriteLength ));
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( Status == STATUS_INSUFFICIENT_RESOURCES ) {
|
|
Status = STATUS_INSUFF_SERVER_RESOURCES;
|
|
}
|
|
|
|
if ( CLIENT_CAPABLE_OF(NT_STATUS, WorkContext->Connection) ) {
|
|
|
|
//
|
|
// The client understands NT status codes. Load the status
|
|
// directly into the SMB header.
|
|
//
|
|
|
|
SmbPutUlong( (PULONG)&header->ErrorClass, Status );
|
|
|
|
flags = SmbGetAlignedUshort( &header->Flags2 ) | SMB_FLAGS2_NT_STATUS;
|
|
SmbPutAlignedUshort( &header->Flags2, flags );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// This is an NT status, but the client doesn't understand them.
|
|
// Indicate that we're not returning an NT status code. Then
|
|
// map the NT status to a Win32 status. Some NT status codes
|
|
// require special mapping.
|
|
//
|
|
|
|
flags = SmbGetAlignedUshort( &header->Flags2 ) & ~SMB_FLAGS2_NT_STATUS;
|
|
SmbPutAlignedUshort( &header->Flags2, flags );
|
|
|
|
switch ( Status ) {
|
|
|
|
case STATUS_TIMEOUT:
|
|
header->ErrorClass = SMB_ERR_CLASS_SERVER;
|
|
SmbPutUshort( &header->Error, SMB_ERR_TIMEOUT );
|
|
return;
|
|
|
|
case STATUS_INVALID_SYSTEM_SERVICE:
|
|
|
|
//
|
|
// This status code is returned by XACTSRV when an invalid API
|
|
// number is specified.
|
|
//
|
|
|
|
header->ErrorClass = SMB_ERR_CLASS_DOS;
|
|
SmbPutUshort( &header->Error, NERR_InvalidAPI );
|
|
return;
|
|
|
|
case STATUS_PATH_NOT_COVERED:
|
|
//
|
|
// This code indicates that the server does not cover this part
|
|
// of the DFS namespace.
|
|
//
|
|
header->ErrorClass = SMB_ERR_CLASS_SERVER;
|
|
SmbPutUshort( &header->Error, SMB_ERR_BAD_PATH );
|
|
return;
|
|
|
|
default:
|
|
|
|
//
|
|
// This is not a special status code. Map the NT status
|
|
// code to a Win32 error code. If there is no mapping,
|
|
// return the generic SMB error.
|
|
//
|
|
|
|
error = RtlNtStatusToDosErrorNoTeb( Status );
|
|
|
|
if ( error == ERROR_MR_MID_NOT_FOUND || error == (ULONG)Status ) {
|
|
header->ErrorClass = SMB_ERR_CLASS_HARDWARE;
|
|
SmbPutUshort( &header->Error, SMB_ERR_GENERAL );
|
|
return;
|
|
}
|
|
|
|
//
|
|
// We now have a Win32 error. Drop through to the code
|
|
// that maps Win32 errors for downlevel clients.
|
|
//
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// The status code is not an NT status. Deal with it based on
|
|
// the error class.
|
|
//
|
|
|
|
errorClass = SrvErrorClass( Status );
|
|
|
|
//
|
|
// Clear the FLAGS2_NT_STATUS bit to indicate that this is *not* an
|
|
// NT_STATUS
|
|
//
|
|
|
|
flags = SmbGetAlignedUshort( &header->Flags2 ) & ~SMB_FLAGS2_NT_STATUS;
|
|
SmbPutAlignedUshort( &header->Flags2, flags );
|
|
|
|
switch ( errorClass ) {
|
|
|
|
case SMB_ERR_CLASS_DOS:
|
|
case SMB_ERR_CLASS_SERVER:
|
|
case SMB_ERR_CLASS_HARDWARE:
|
|
|
|
//
|
|
// The status code has the SMB error class and code
|
|
// embedded.
|
|
//
|
|
|
|
header->ErrorClass = errorClass;
|
|
|
|
//
|
|
// Because SMB_ERR_NO_SUPPORT in the SERVER class is 0xFFFF
|
|
// (16 bits), we must special-case for it. The code
|
|
// SMB_ERR_NO_SUPPORT_INTERNAL in the error code field of
|
|
// the status, along with class = 2 (SERVER), indicates that
|
|
// we should use SMB_ERR_NO_SUPPORT.
|
|
//
|
|
|
|
if ( errorClass == SMB_ERR_CLASS_SERVER &&
|
|
SrvErrorCode( Status ) == SMB_ERR_NO_SUPPORT_INTERNAL ) {
|
|
SmbPutUshort( &header->Error, SMB_ERR_NO_SUPPORT );
|
|
} else {
|
|
SmbPutUshort( &header->Error, SrvErrorCode( Status ) );
|
|
}
|
|
|
|
return;
|
|
|
|
case 0xF:
|
|
|
|
//
|
|
// The error code is defined in OS/2 but not in the SMB
|
|
// protocol. If the client is speaking a dialect after
|
|
// LanMan 1.0 and is not a DOS client, send the OS/2 error
|
|
// code. Otherwise, send the generic SMB error code.
|
|
//
|
|
|
|
if ( smbDialect <= SmbDialectLanMan10 &&
|
|
!IS_DOS_DIALECT(smbDialect) ) {
|
|
header->ErrorClass = SMB_ERR_CLASS_DOS;
|
|
SmbPutUshort( &header->Error, SrvErrorCode( Status ) );
|
|
} else {
|
|
header->ErrorClass = SMB_ERR_CLASS_HARDWARE;
|
|
SmbPutUshort( &header->Error, SMB_ERR_GENERAL );
|
|
}
|
|
|
|
return;
|
|
|
|
case 0xE:
|
|
|
|
//
|
|
// This is a Win32 error. Drop through to the code that
|
|
// maps Win32 errors for downlevel clients.
|
|
//
|
|
|
|
error = SrvErrorCode( Status );
|
|
|
|
break;
|
|
|
|
case 0x0:
|
|
default:
|
|
|
|
//
|
|
// This is an internal server error (class 0) or some other
|
|
// undefined class. We should never get here. But since we
|
|
// did, return the generic error.
|
|
//
|
|
|
|
KdPrint(( "SRV: Unmapped error: %lx\n", Status ));
|
|
header->ErrorClass = SMB_ERR_CLASS_HARDWARE;
|
|
SmbPutUshort( &header->Error, SMB_ERR_GENERAL );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// At this point we have a Win32 error code and need to map it for
|
|
// the downlevel client. Some errors need to be specially mapped.
|
|
//
|
|
|
|
errorClass = SMB_ERR_CLASS_DOS;
|
|
|
|
switch ( error ) {
|
|
|
|
case ERROR_NOT_ENOUGH_SERVER_MEMORY:
|
|
error = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
|
|
case ERROR_INSUFFICIENT_BUFFER:
|
|
error = ERROR_BUFFER_OVERFLOW;
|
|
break;
|
|
|
|
case ERROR_ACCOUNT_LOCKED_OUT:
|
|
case ERROR_PRIVILEGE_NOT_HELD:
|
|
case ERROR_NO_SUCH_USER:
|
|
case ERROR_LOGON_FAILURE:
|
|
case ERROR_LOGON_TYPE_NOT_GRANTED:
|
|
case ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT:
|
|
case ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT:
|
|
case ERROR_NOLOGON_SERVER_TRUST_ACCOUNT:
|
|
case ERROR_TRUSTED_RELATIONSHIP_FAILURE:
|
|
case ERROR_TRUSTED_DOMAIN_FAILURE:
|
|
case ERROR_TRUST_FAILURE:
|
|
case ERROR_NO_TRUST_SAM_ACCOUNT:
|
|
case ERROR_NO_TRUST_LSA_SECRET:
|
|
error = ERROR_ACCESS_DENIED;
|
|
break;
|
|
|
|
//
|
|
// For the following four errors, we return an ERROR_ACCESS_DENIED
|
|
// for clients older than doslm20. The error class for these
|
|
// must be SMB_ERR_CLASS_SERVER.
|
|
//
|
|
|
|
case ERROR_INVALID_LOGON_HOURS:
|
|
if ( IS_DOS_DIALECT(smbDialect) && (smbDialect > SmbDialectDosLanMan20) ) {
|
|
error = ERROR_ACCESS_DENIED;
|
|
} else {
|
|
errorClass = SMB_ERR_CLASS_SERVER;
|
|
error = NERR_InvalidLogonHours;
|
|
}
|
|
break;
|
|
|
|
case ERROR_INVALID_WORKSTATION:
|
|
if ( IS_DOS_DIALECT(smbDialect) && (smbDialect > SmbDialectDosLanMan20) ) {
|
|
error = ERROR_ACCESS_DENIED;
|
|
} else {
|
|
errorClass = SMB_ERR_CLASS_SERVER;
|
|
error = NERR_InvalidWorkstation;
|
|
}
|
|
break;
|
|
|
|
case ERROR_ACCOUNT_DISABLED:
|
|
case ERROR_ACCOUNT_EXPIRED:
|
|
if ( IS_DOS_DIALECT(smbDialect) && (smbDialect > SmbDialectDosLanMan20) ) {
|
|
error = ERROR_ACCESS_DENIED;
|
|
} else {
|
|
errorClass = SMB_ERR_CLASS_SERVER;
|
|
error = NERR_AccountExpired;
|
|
}
|
|
break;
|
|
|
|
case ERROR_PASSWORD_MUST_CHANGE:
|
|
case ERROR_PASSWORD_EXPIRED:
|
|
if ( IS_DOS_DIALECT(smbDialect) && (smbDialect > SmbDialectDosLanMan20) ) {
|
|
error = ERROR_ACCESS_DENIED;
|
|
} else {
|
|
errorClass = SMB_ERR_CLASS_SERVER;
|
|
error = NERR_PasswordExpired;
|
|
}
|
|
break;
|
|
|
|
//
|
|
// The only NERR codes that DOSLM20 understands are the 4 above.
|
|
// According to larryo, the rest of the NERR codes have to be
|
|
// mapped to ERROR_ACCESS_DENIED.
|
|
//
|
|
|
|
case ERROR_NETLOGON_NOT_STARTED:
|
|
if ( IS_DOS_DIALECT(smbDialect) && (smbDialect > SmbDialectDosLanMan21) ) {
|
|
error = ERROR_ACCESS_DENIED;
|
|
} else {
|
|
error = NERR_NetlogonNotStarted;
|
|
}
|
|
break;
|
|
|
|
case ERROR_NO_LOGON_SERVERS:
|
|
if ( IS_DOS_DIALECT(smbDialect) ) {
|
|
error = ERROR_ACCESS_DENIED;
|
|
} else {
|
|
error = NERR_LogonServerNotFound;
|
|
}
|
|
break;
|
|
|
|
case ERROR_DIR_NOT_EMPTY:
|
|
if ( IS_DOS_DIALECT(smbDialect) ) {
|
|
error = ERROR_ACCESS_DENIED;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// Now map the error to a DOS or OS/2 error code.
|
|
//
|
|
|
|
if ( error == ERROR_ACCESS_DENIED &&
|
|
smbDialect == SmbDialectDosLanMan21 &&
|
|
WorkContext->ShareAclFailure ) {
|
|
|
|
//
|
|
// WfW & DOS LM2.1 want SMB_ERR_ACCESS to be in the server
|
|
// error class when it's due to ACL restrictions, but in the
|
|
// DOS class otherwise.
|
|
//
|
|
errorClass = SMB_ERR_CLASS_SERVER;
|
|
errorCode = SMB_ERR_ACCESS;
|
|
|
|
} else if ( smbDialect > SmbDialectLanMan10 ) {
|
|
|
|
MapErrorForDosClient(
|
|
WorkContext,
|
|
error,
|
|
&errorCode,
|
|
&errorClass
|
|
);
|
|
|
|
} else if ( (error > ERROR_ARITHMETIC_OVERFLOW) &&
|
|
((error < NERR_BASE) || (error > MAX_NERR)) ) {
|
|
|
|
//
|
|
// Win32 errors above ERROR_ARITHMETIC_OVERFLOW (but not in the
|
|
// NERR_xxx range) do not map to DOS or OS/2 errors, so we
|
|
// return the generic error for those.
|
|
//
|
|
|
|
errorClass = SMB_ERR_CLASS_HARDWARE;
|
|
errorCode = SMB_ERR_GENERAL;
|
|
|
|
} else {
|
|
|
|
errorCode = (USHORT)error;
|
|
|
|
}
|
|
|
|
header->ErrorClass = errorClass;
|
|
SmbPutUshort( &header->Error, errorCode );
|
|
|
|
return;
|
|
|
|
} // _SrvSetSmbError2
|
|
|
|
|
|
VOID
|
|
MapErrorForDosClient (
|
|
IN PWORK_CONTEXT WorkContext,
|
|
IN ULONG Error,
|
|
OUT PUSHORT DosError,
|
|
OUT PUCHAR DosErrorClass
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Maps an Win32 error to a DOS error.
|
|
|
|
Arguments:
|
|
|
|
WorkContext - Supplies a pointer to the work context block for the
|
|
current SMB.
|
|
|
|
Error - the Win32 error code to map.
|
|
|
|
DosError - the corresponding DOS error.
|
|
|
|
DosErrorClass - the error class to put in the outgoing SMB.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PSMB_HEADER header = WorkContext->ResponseHeader;
|
|
|
|
PAGED_CODE( );
|
|
|
|
//
|
|
// Default to using the initial error code and the win32 error.
|
|
//
|
|
|
|
*DosError = (USHORT)Error;
|
|
*DosErrorClass = SMB_ERR_CLASS_DOS;
|
|
|
|
//
|
|
// If the error is more recent and not part of the set of DOS errors
|
|
// (value greater than ERROR_NET_WRITE_FAULT) and the SMB command is
|
|
// not a newer SMB (errors for these get mapped by the newer DOS
|
|
// redir that sent them), then map the OS/2 error to the DOS range.
|
|
// This code was lifted from the ring 3 OS/2 server.
|
|
//
|
|
|
|
if ( Error > ERROR_NET_WRITE_FAULT &&
|
|
!( header->Command == SMB_COM_COPY ||
|
|
header->Command == SMB_COM_MOVE ||
|
|
header->Command == SMB_COM_TRANSACTION ||
|
|
header->Command == SMB_COM_TRANSACTION_SECONDARY ) ) {
|
|
|
|
switch( Error ) {
|
|
|
|
case ERROR_OPEN_FAILED:
|
|
|
|
*DosError = ERROR_FILE_NOT_FOUND;
|
|
break;
|
|
|
|
case ERROR_BUFFER_OVERFLOW:
|
|
case ERROR_INSUFFICIENT_BUFFER:
|
|
case ERROR_INVALID_NAME:
|
|
case ERROR_INVALID_LEVEL:
|
|
case ERROR_SEEK_ON_DEVICE:
|
|
|
|
//
|
|
// These don't get mapped to anything. No explanation was
|
|
// given in the ring 3 code.
|
|
//
|
|
|
|
break;
|
|
|
|
case ERROR_BAD_EXE_FORMAT:
|
|
case ERROR_INVALID_STARTING_CODESEG:
|
|
case ERROR_INVALID_STACKSEG:
|
|
case ERROR_INVALID_MODULETYPE:
|
|
case ERROR_INVALID_EXE_SIGNATURE:
|
|
case ERROR_EXE_MARKED_INVALID:
|
|
case ERROR_ITERATED_DATA_EXCEEDS_64k:
|
|
case ERROR_INVALID_MINALLOCSIZE:
|
|
case ERROR_DYNLINK_FROM_INVALID_RING:
|
|
case ERROR_IOPL_NOT_ENABLED:
|
|
case ERROR_INVALID_SEGDPL:
|
|
case ERROR_AUTODATASEG_EXCEEDS_64k:
|
|
case ERROR_RING2SEG_MUST_BE_MOVABLE:
|
|
case ERROR_RELOC_CHAIN_XEEDS_SEGLIM:
|
|
case ERROR_INFLOOP_IN_RELOC_CHAIN:
|
|
//case ERROR_BAD_DYNALINK:
|
|
case ERROR_TOO_MANY_MODULES:
|
|
|
|
//
|
|
// About these, the ring 3 server code says "map to bad
|
|
// format errors." Whatever that means. It doesn't do
|
|
// anything with them, so we don't either.
|
|
//
|
|
|
|
break;
|
|
|
|
case ERROR_DISK_CHANGE:
|
|
|
|
*DosErrorClass = SMB_ERR_CLASS_HARDWARE;
|
|
*DosError = ERROR_WRONG_DISK;
|
|
break;
|
|
|
|
case ERROR_DRIVE_LOCKED:
|
|
|
|
*DosErrorClass = SMB_ERR_CLASS_HARDWARE;
|
|
*DosError = ERROR_NOT_READY;
|
|
break;
|
|
|
|
case ERROR_ALREADY_EXISTS:
|
|
|
|
*DosError = ERROR_FILE_EXISTS;
|
|
break;
|
|
|
|
case ERROR_DISK_FULL:
|
|
|
|
//
|
|
// Per LarryO, map to the "old" disk full error code.
|
|
//
|
|
|
|
*DosErrorClass = SMB_ERR_CLASS_HARDWARE;
|
|
*DosError = ERROR_HANDLE_DISK_FULL;
|
|
break;
|
|
|
|
case ERROR_NO_MORE_SEARCH_HANDLES:
|
|
|
|
*DosError = ERROR_OUT_OF_STRUCTURES;
|
|
break;
|
|
|
|
case ERROR_INVALID_TARGET_HANDLE:
|
|
|
|
*DosError = ERROR_INVALID_HANDLE;
|
|
break;
|
|
|
|
case ERROR_BROKEN_PIPE:
|
|
case ERROR_BAD_PIPE:
|
|
case ERROR_PIPE_BUSY:
|
|
case ERROR_NO_DATA:
|
|
case ERROR_PIPE_NOT_CONNECTED:
|
|
case ERROR_MORE_DATA:
|
|
|
|
//
|
|
// If this is a pipe share, return these unmolested. If
|
|
// it's not a pipe share, so map to the generic error.
|
|
//
|
|
|
|
if ( (WorkContext->Rfcb != NULL &&
|
|
WorkContext->Rfcb->ShareType == ShareTypePipe)
|
|
||
|
|
(WorkContext->TreeConnect != NULL &&
|
|
WorkContext->TreeConnect->Share->ShareType == ShareTypePipe) ) {
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
*DosErrorClass = SMB_ERR_CLASS_HARDWARE;
|
|
*DosError = SMB_ERR_GENERAL;
|
|
}
|
|
|
|
break;
|
|
|
|
case ERROR_BAD_PATHNAME:
|
|
break;
|
|
|
|
//
|
|
// The following error mappings (not including default) were not
|
|
// copied from the OS/2 server mapping.
|
|
//
|
|
|
|
case ERROR_LOCK_FAILED:
|
|
case ERROR_NOT_LOCKED:
|
|
*DosError = ERROR_LOCK_VIOLATION;
|
|
break;
|
|
|
|
case NERR_InvalidLogonHours:
|
|
case NERR_InvalidWorkstation:
|
|
case NERR_PasswordExpired:
|
|
case NERR_AccountUndefined:
|
|
case ERROR_ACCESS_DENIED:
|
|
*DosError = ERROR_ACCESS_DENIED;
|
|
break;
|
|
|
|
default:
|
|
|
|
*DosErrorClass = SMB_ERR_CLASS_HARDWARE;
|
|
*DosError = SMB_ERR_GENERAL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// The DOS redirector uses the reserved field for the hard error action.
|
|
// Set it now.
|
|
//
|
|
|
|
if ( *DosErrorClass == SMB_ERR_CLASS_HARDWARE ) {
|
|
WorkContext->ResponseHeader->Reserved = DISK_HARD_ERROR;
|
|
}
|
|
|
|
} // MapErrorForDosClient
|
|
|
|
|
|
VOID
|
|
SrvSetBufferOverflowError (
|
|
IN PWORK_CONTEXT WorkContext
|
|
)
|
|
{
|
|
PSMB_HEADER header = WorkContext->ResponseHeader;
|
|
USHORT flags = SmbGetAlignedUshort( &header->Flags2 );
|
|
|
|
UNLOCKABLE_CODE( 8FIL );
|
|
|
|
if ( CLIENT_CAPABLE_OF(NT_STATUS, WorkContext->Connection) ) {
|
|
SmbPutUlong(
|
|
(PULONG)&header->ErrorClass,
|
|
(ULONG)STATUS_BUFFER_OVERFLOW
|
|
);
|
|
flags |= SMB_FLAGS2_NT_STATUS;
|
|
} else {
|
|
header->ErrorClass = SMB_ERR_CLASS_DOS;
|
|
SmbPutUshort( &header->Error, ERROR_MORE_DATA );
|
|
flags &= ~SMB_FLAGS2_NT_STATUS;
|
|
}
|
|
SmbPutAlignedUshort( &header->Flags2, flags );
|
|
|
|
return;
|
|
|
|
} // SrvSetBufferOverflowError
|
|
|
|
|