|
|
/*++ BUILD Version: 0009 // Increment this if a change has global effects
Copyright (c) 1987-1993 Microsoft Corporation
Module Name:
smbutils.c
Abstract:
This module implements the routines that aid in the assembly/disassembly of SMB's
Author:
Balan Sethu Raman (SethuR) 06-Mar-95 Created
--*/
#include "precomp.h"
#pragma hdrstop
#define BASE_DOS_ERROR ((NTSTATUS )0xC0010000L)
#include "lmerr.h"
#include "nb30.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, SmbPutString)
#pragma alloc_text(PAGE, SmbPutUnicodeString)
#pragma alloc_text(PAGE, SmbPutUnicodeStringAndUpcase)
#pragma alloc_text(PAGE, SmbPutUnicodeStringAsOemString)
#pragma alloc_text(PAGE, SmbPutUnicodeStringAsOemStringAndUpcase)
#endif
NTSTATUS SmbPutString( PBYTE *pBufferPointer, PSTRING pString, PULONG pSize) { NTSTATUS Status; PBYTE pBuffer = *pBufferPointer;
PAGED_CODE();
if (*pSize > pString->Length) { RtlCopyMemory( pBuffer, pString->Buffer, pString->Length);
*pSize -= pString->Length; *pBufferPointer = pBuffer + pString->Length; Status = STATUS_SUCCESS; } else { Status = STATUS_BUFFER_OVERFLOW; }
return Status; }
NTSTATUS SmbPutUnicodeString( PBYTE *pBufferPointer, PUNICODE_STRING pUnicodeString, PULONG pSize) { NTSTATUS Status; PBYTE pBuffer = *pBufferPointer;
PAGED_CODE();
if (*pSize >= (pUnicodeString->Length + sizeof(WCHAR))) { WCHAR NullChar = L'\0';
RtlCopyMemory( pBuffer, pUnicodeString->Buffer, pUnicodeString->Length);
RtlCopyMemory( (pBuffer + pUnicodeString->Length), &NullChar, sizeof(WCHAR));
*pSize -= (pUnicodeString->Length + sizeof(WCHAR)); *pBufferPointer = pBuffer + (pUnicodeString->Length + sizeof(WCHAR)); Status = STATUS_SUCCESS; } else { Status = STATUS_BUFFER_OVERFLOW; }
return Status; }
NTSTATUS SmbPutUnicodeStringAndUpcase( PBYTE *pBufferPointer, PUNICODE_STRING pUnicodeString, PULONG pSize) { NTSTATUS Status; PBYTE pBuffer = *pBufferPointer;
PAGED_CODE();
if (*pSize >= (pUnicodeString->Length + sizeof(WCHAR))) { UNICODE_STRING BufferAsUnicode; WCHAR NullChar = L'\0';
BufferAsUnicode.Buffer = (PWCHAR)pBuffer; BufferAsUnicode.Length = pUnicodeString->Length; BufferAsUnicode.MaximumLength = BufferAsUnicode.Length;
RtlUpcaseUnicodeString( &BufferAsUnicode, pUnicodeString, FALSE);
RtlCopyMemory( (pBuffer + pUnicodeString->Length), &NullChar, sizeof(WCHAR));
*pSize -= (pUnicodeString->Length + sizeof(WCHAR)); *pBufferPointer = pBuffer + (pUnicodeString->Length + sizeof(WCHAR)); Status = STATUS_SUCCESS; } else { Status = STATUS_BUFFER_OVERFLOW; }
return Status; }
NTSTATUS SmbPutUnicodeStringAsOemString( PBYTE *pBufferPointer, PUNICODE_STRING pUnicodeString, PULONG pSize) { NTSTATUS Status; OEM_STRING OemString; PBYTE pBuffer = *pBufferPointer;
PAGED_CODE();
OemString.MaximumLength = (USHORT)*pSize; OemString.Buffer = pBuffer;
// The Rtl routine pads the converted string with a NULL.
Status = RtlUnicodeStringToOemString( &OemString, // destination string
pUnicodeString, // source string
FALSE); // No memory allocation for destination
if (NT_SUCCESS(Status)) { if (OemString.Length < *pSize) { // put the null
pBuffer += (OemString.Length + 1); *pBufferPointer = pBuffer; *pSize -= (OemString.Length + 1); // the NULL is not included in the length by the RTL routine.
} else { Status = RX_MAP_STATUS(BUFFER_OVERFLOW); } }
return Status; }
NTSTATUS SmbPutUnicodeStringAsOemStringAndUpcase( PBYTE *pBufferPointer, PUNICODE_STRING pUnicodeString, PULONG pSize) { NTSTATUS Status; OEM_STRING OemString; PBYTE pBuffer = *pBufferPointer;
PAGED_CODE();
OemString.MaximumLength = (USHORT)*pSize; OemString.Buffer = pBuffer;
// The Rtl routine pads the converted string with a NULL.
Status = RtlUpcaseUnicodeStringToOemString( &OemString, // destination string
pUnicodeString, // source string
FALSE); // No memory allocation for destination
if (NT_SUCCESS(Status)) { if (OemString.Length < *pSize) { // put the null
pBuffer += (OemString.Length + 1); *pBufferPointer = pBuffer; *pSize -= (OemString.Length + 1); // the NULL is not included in the length by the RTL routine.
} else { Status = STATUS_BUFFER_OVERFLOW; } }
return Status; }
//
// The maps for mapping various error codes into NTSTATUSs
//
typedef struct _STATUS_MAP { USHORT ErrorCode; NTSTATUS ResultingStatus; } STATUS_MAP, *PSTATUS_MAP;
STATUS_MAP SmbErrorMap[] = { { SMB_ERR_BAD_PASSWORD, STATUS_WRONG_PASSWORD }, { SMB_ERR_ACCESS, STATUS_NETWORK_ACCESS_DENIED }, { SMB_ERR_BAD_TID, STATUS_NETWORK_NAME_DELETED }, { SMB_ERR_BAD_NET_NAME, STATUS_BAD_NETWORK_NAME }, // Invalid network name
{ SMB_ERR_BAD_DEVICE, STATUS_BAD_DEVICE_TYPE }, // Invalid device request
{ SMB_ERR_QUEUE_FULL, STATUS_PRINT_QUEUE_FULL }, // Print queue full
{ SMB_ERR_QUEUE_TOO_BIG, STATUS_NO_SPOOL_SPACE }, // No space on print dev
{ SMB_ERR_BAD_PRINT_FID, STATUS_PRINT_CANCELLED }, // Invalid printfile FID
{ SMB_ERR_SERVER_PAUSED, STATUS_SHARING_PAUSED }, // Server is paused
{ SMB_ERR_MESSAGE_OFF, STATUS_REQUEST_NOT_ACCEPTED }, // Server not receiving msgs
{ SMB_ERR_BAD_TYPE, STATUS_BAD_DEVICE_TYPE }, // Reserved
{ SMB_ERR_BAD_SMB_COMMAND, STATUS_NOT_IMPLEMENTED }, // SMB command not recognized
{ SMB_ERR_BAD_PERMITS, STATUS_NETWORK_ACCESS_DENIED }, // Access permissions invalid
{ SMB_ERR_NO_ROOM, STATUS_DISK_FULL }, // No room for buffer message
{ SMB_ERR_NO_RESOURCE, STATUS_REQUEST_NOT_ACCEPTED }, // No resources available for request
{ SMB_ERR_TOO_MANY_UIDS, STATUS_TOO_MANY_SESSIONS }, // Too many UIDs active in session
{ SMB_ERR_BAD_UID, STATUS_USER_SESSION_DELETED }, // UID not known as a valid UID
{ SMB_ERR_USE_MPX, STATUS_SMB_USE_MPX }, // Can't support Raw; use MPX
{ SMB_ERR_USE_STANDARD, STATUS_SMB_USE_STANDARD }, // Can't support Raw, use standard r/w
{ SMB_ERR_INVALID_NAME, STATUS_OBJECT_NAME_INVALID }, { SMB_ERR_INVALID_NAME_RANGE, STATUS_OBJECT_NAME_INVALID }, { SMB_ERR_NO_SUPPORT,STATUS_NOT_SUPPORTED }, // Function not supported
{ NERR_PasswordExpired, STATUS_PASSWORD_EXPIRED }, { NERR_AccountExpired, STATUS_ACCOUNT_DISABLED }, { NERR_InvalidLogonHours, STATUS_INVALID_LOGON_HOURS }, { NERR_InvalidWorkstation, STATUS_INVALID_WORKSTATION }, { NERR_DuplicateShare, STATUS_LOGON_FAILURE }
// { SMB_ERR_QUEUE_EOF, STATUS_UNEXPECTED_NETWORK_ERROR },// EOF on print queue dump
// { SMB_ERR_SERVER_ERROR, STATUS_UNEXPECTED_NETWORK_ERROR}, // Internal server error
// { SMB_ERR_FILE_SPECS, STATUS_UNEXPECTED_NETWORK_ERROR }, // FID and pathname were incompatible
// { SMB_ERR_BAD_ATTRIBUTE_MODE, STATUS_UNEXPECTED_NETWORK_ERROR }, // Invalid attribute mode specified
// { SMB_ERR_NO_SUPPORT_INTERNAL,STATUS_UNEXPECTED_NETWORK_ERROR }, // Internal code for NO_SUPPORT--
// // allows codes to be stored in a byte
// { SMB_ERR_ERROR, STATUS_UNEXPECTED_NETWORK_ERROR },
// { SMB_ERR_CONTINUE_MPX, STATUS_UNEXPECTED_NETWORK_ERROR }, // Reserved
// { SMB_ERR_TOO_MANY_NAMES, STATUS_UNEXPECTED_NETWORK_ERROR }, // Too many remote user names
// { SMB_ERR_TIMEOUT, STATUS_UNEXPECTED_NETWORK_ERROR }, // Operation was timed out
// { SMB_ERR_RESERVED2, STATUS_UNEXPECTED_NETWORK_ERROR },
// { SMB_ERR_RESERVED3, STATUS_UNEXPECTED_NETWORK_ERROR },
// { SMB_ERR_RESERVED4, STATUS_UNEXPECTED_NETWORK_ERROR },
// { SMB_ERR_RESERVED5, STATUS_UNEXPECTED_NETWORK_ERROR },
};
ULONG SmbErrorMapLength = sizeof(SmbErrorMap) / sizeof(SmbErrorMap[0]);
STATUS_MAP Os2ErrorMap[] = { { ERROR_INVALID_FUNCTION, STATUS_NOT_IMPLEMENTED }, { ERROR_FILE_NOT_FOUND, STATUS_NO_SUCH_FILE }, { ERROR_PATH_NOT_FOUND, STATUS_OBJECT_PATH_NOT_FOUND }, { ERROR_TOO_MANY_OPEN_FILES,STATUS_TOO_MANY_OPENED_FILES }, { ERROR_ACCESS_DENIED, STATUS_ACCESS_DENIED }, { ERROR_INVALID_HANDLE, STATUS_INVALID_HANDLE }, { ERROR_NOT_ENOUGH_MEMORY, STATUS_INSUFFICIENT_RESOURCES }, { ERROR_INVALID_ACCESS, STATUS_ACCESS_DENIED }, { ERROR_INVALID_DATA, STATUS_DATA_ERROR },
{ ERROR_CURRENT_DIRECTORY, STATUS_DIRECTORY_NOT_EMPTY }, { ERROR_NOT_SAME_DEVICE, STATUS_NOT_SAME_DEVICE }, { ERROR_NO_MORE_FILES, STATUS_NO_MORE_FILES }, { ERROR_WRITE_PROTECT, STATUS_MEDIA_WRITE_PROTECTED}, { ERROR_NOT_READY, STATUS_DEVICE_NOT_READY }, { ERROR_CRC, STATUS_CRC_ERROR }, { ERROR_BAD_LENGTH, STATUS_DATA_ERROR }, { ERROR_NOT_DOS_DISK, STATUS_DISK_CORRUPT_ERROR }, //***
{ ERROR_SECTOR_NOT_FOUND, STATUS_NONEXISTENT_SECTOR }, { ERROR_OUT_OF_PAPER, STATUS_DEVICE_PAPER_EMPTY}, { ERROR_SHARING_VIOLATION, STATUS_SHARING_VIOLATION }, { ERROR_LOCK_VIOLATION, STATUS_FILE_LOCK_CONFLICT }, { ERROR_WRONG_DISK, STATUS_WRONG_VOLUME }, { ERROR_NOT_SUPPORTED, STATUS_NOT_SUPPORTED }, { ERROR_REM_NOT_LIST, STATUS_REMOTE_NOT_LISTENING }, { ERROR_DUP_NAME, STATUS_DUPLICATE_NAME }, { ERROR_BAD_NETPATH, STATUS_BAD_NETWORK_PATH }, { ERROR_NETWORK_BUSY, STATUS_NETWORK_BUSY }, { ERROR_DEV_NOT_EXIST, STATUS_DEVICE_DOES_NOT_EXIST }, { ERROR_TOO_MANY_CMDS, STATUS_TOO_MANY_COMMANDS }, { ERROR_ADAP_HDW_ERR, STATUS_ADAPTER_HARDWARE_ERROR }, { ERROR_BAD_NET_RESP, STATUS_INVALID_NETWORK_RESPONSE }, { ERROR_UNEXP_NET_ERR, STATUS_UNEXPECTED_NETWORK_ERROR }, { ERROR_BAD_REM_ADAP, STATUS_BAD_REMOTE_ADAPTER }, { ERROR_PRINTQ_FULL, STATUS_PRINT_QUEUE_FULL }, { ERROR_NO_SPOOL_SPACE, STATUS_NO_SPOOL_SPACE }, { ERROR_PRINT_CANCELLED, STATUS_PRINT_CANCELLED }, { ERROR_NETNAME_DELETED, STATUS_NETWORK_NAME_DELETED }, { ERROR_NETWORK_ACCESS_DENIED, STATUS_NETWORK_ACCESS_DENIED }, { ERROR_BAD_DEV_TYPE, STATUS_BAD_DEVICE_TYPE }, { ERROR_BAD_NET_NAME, STATUS_BAD_NETWORK_NAME }, { ERROR_TOO_MANY_NAMES, STATUS_TOO_MANY_NAMES }, { ERROR_TOO_MANY_SESS, STATUS_TOO_MANY_SESSIONS }, { ERROR_SHARING_PAUSED, STATUS_SHARING_PAUSED }, { ERROR_REQ_NOT_ACCEP, STATUS_REQUEST_NOT_ACCEPTED }, { ERROR_REDIR_PAUSED, STATUS_REDIRECTOR_PAUSED },
{ ERROR_FILE_EXISTS, STATUS_OBJECT_NAME_COLLISION }, { ERROR_INVALID_PASSWORD, STATUS_WRONG_PASSWORD }, { ERROR_INVALID_PARAMETER, STATUS_INVALID_PARAMETER }, { ERROR_NET_WRITE_FAULT, STATUS_NET_WRITE_FAULT },
{ ERROR_BROKEN_PIPE, STATUS_PIPE_BROKEN },
{ ERROR_OPEN_FAILED, STATUS_OPEN_FAILED }, { ERROR_BUFFER_OVERFLOW, STATUS_BUFFER_OVERFLOW }, { ERROR_DISK_FULL, STATUS_DISK_FULL }, { ERROR_SEM_TIMEOUT, STATUS_IO_TIMEOUT }, { ERROR_INSUFFICIENT_BUFFER,STATUS_BUFFER_TOO_SMALL }, { ERROR_INVALID_NAME, STATUS_OBJECT_NAME_INVALID }, { ERROR_INVALID_LEVEL, STATUS_INVALID_LEVEL }, { ERROR_BAD_PATHNAME, STATUS_OBJECT_PATH_INVALID }, //*
{ ERROR_BAD_PIPE, STATUS_INVALID_PARAMETER }, { ERROR_PIPE_BUSY, STATUS_PIPE_NOT_AVAILABLE }, { ERROR_NO_DATA, STATUS_PIPE_EMPTY }, { ERROR_PIPE_NOT_CONNECTED, STATUS_PIPE_DISCONNECTED }, { ERROR_MORE_DATA, STATUS_BUFFER_OVERFLOW }, { ERROR_VC_DISCONNECTED, STATUS_VIRTUAL_CIRCUIT_CLOSED }, { ERROR_INVALID_EA_NAME, STATUS_INVALID_EA_NAME }, { ERROR_EA_LIST_INCONSISTENT,STATUS_EA_LIST_INCONSISTENT }, // { ERROR_EA_LIST_TOO_LONG, STATUS_EA_LIST_TO_LONG },
{ ERROR_EAS_DIDNT_FIT, STATUS_EA_TOO_LARGE }, { ERROR_EA_FILE_CORRUPT, STATUS_EA_CORRUPT_ERROR }, { ERROR_EA_TABLE_FULL, STATUS_EA_CORRUPT_ERROR }, { ERROR_INVALID_EA_HANDLE, STATUS_EA_CORRUPT_ERROR } // { ERROR_BAD_UNIT, STATUS_UNSUCCESSFUL}, // ***
// { ERROR_BAD_COMMAND, STATUS_UNSUCCESSFUL}, // ***
// { ERROR_SEEK, STATUS_UNSUCCESSFUL },// ***
// { ERROR_WRITE_FAULT, STATUS_UNSUCCESSFUL}, // ***
// { ERROR_READ_FAULT, STATUS_UNSUCCESSFUL}, // ***
// { ERROR_GEN_FAILURE, STATUS_UNSUCCESSFUL }, // ***
};
ULONG Os2ErrorMapLength = sizeof(Os2ErrorMap) / sizeof(Os2ErrorMap[0]);
NTSTATUS GetSmbResponseNtStatus( PSMB_HEADER pSmbHeader, PSMB_EXCHANGE pExchange ) { NTSTATUS Status; USHORT Error; USHORT i;
ASSERT( pSmbHeader != NULL );
// If this SMB contains an NT status for the operation, return
// that, otherwise map the resulting error.
if (SmbGetUshort(&pSmbHeader->Flags2) & SMB_FLAGS2_NT_STATUS) {
Status = SmbGetUlong( & ((PNT_SMB_HEADER)pSmbHeader)->Status.NtStatus );
if ((Status == STATUS_SUCCESS) || NT_ERROR(Status) || NT_WARNING(Status)) { if (Status == STATUS_RETRY) { Status = STATUS_UNEXPECTED_NETWORK_ERROR; }
return Status; } // else fall through and treat it as an SMB error ..
// This needs to be done because in certain cases NT servers return SMB
// specific error codes eventhough the NTSTATUS flag is set
}
if (pSmbHeader->ErrorClass == SMB_ERR_SUCCESS) { return STATUS_SUCCESS; }
Error = SmbGetUshort(&pSmbHeader->Error); if (Error == SMB_ERR_SUCCESS) { // Umm, non success ErrorClass but success Error code.
Status = STATUS_UNEXPECTED_NETWORK_ERROR; } else { // Map the error code depending on Error Class
switch (pSmbHeader->ErrorClass) { case SMB_ERR_CLASS_DOS: case SMB_ERR_CLASS_HARDWARE: Status = BASE_DOS_ERROR + Error; for (i = 0; i < Os2ErrorMapLength; i++) { if (Os2ErrorMap[i].ErrorCode == Error) { Status = Os2ErrorMap[i].ResultingStatus; break; } } break;
case SMB_ERR_CLASS_SERVER: Status = STATUS_UNEXPECTED_NETWORK_ERROR; for (i = 0; i < SmbErrorMapLength; i++) { if (SmbErrorMap[i].ErrorCode == Error) { //The error of STATUS_NETWORK_ACCESS_DENIED should be mapped as STATUS_NO_SUCH_FILE for
//the non-NT servers in case it tries to access the PIPE.
if (SmbErrorMap[i].ResultingStatus == STATUS_NETWORK_ACCESS_DENIED) { SMBCE_SERVER Server = pExchange->SmbCeContext.pServerEntry->Server; NET_ROOT_TYPE NetRootType = pExchange->SmbCeContext.pVNetRoot->pNetRoot->Type;
if (NetRootType == NET_ROOT_PIPE) { if ( (Server.Dialect != NTLANMAN_DIALECT) || !FlagOn(Server.DialectFlags,DF_NT_STATUS) ) { Status = STATUS_NO_SUCH_FILE; break; } } } Status = SmbErrorMap[i].ResultingStatus; break; } } break;
default: Status = STATUS_UNEXPECTED_NETWORK_ERROR; break; } }
return Status; }
BOOLEAN IsValidShortFileName( PUNICODE_STRING Name ) { BOOLEAN IsValidName = TRUE; int NumberOfChars; int CurrentNameStart = 0; int CurrentNameEnd = 0; int CurrentDot = 0; int i;
if (Name == NULL) { return TRUE; }
NumberOfChars = Name->Length/sizeof(UNICODE_NULL);
while(IsValidName && CurrentNameStart < NumberOfChars) { CurrentNameEnd = NumberOfChars;
for (i=CurrentNameStart+1;i<NumberOfChars;i++) { if (Name->Buffer[i] == L'\\') { CurrentNameEnd = i; break; } }
if (CurrentNameEnd - CurrentNameStart > 13) { IsValidName = FALSE; }
if (IsValidName) { CurrentDot = CurrentNameEnd;
for (i=CurrentNameStart;i<CurrentNameEnd;i++) { if (Name->Buffer[i] == L'.') { if (CurrentDot == CurrentNameEnd) { CurrentDot = i; } else { IsValidName = FALSE; } } }
if (IsValidName) { if (CurrentDot - CurrentNameStart > 9 || CurrentNameEnd - CurrentDot > 4) { IsValidName = FALSE; } } }
CurrentNameStart = CurrentNameEnd; }
return IsValidName; }
|