windows-nt/Source/XPSP1/NT/base/fs/rdr2/rdbss/smb.mrx/smbutils.c
2020-09-26 16:20:57 +08:00

493 lines
17 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++ 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)) {
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;
}