493 lines
17 KiB
C
493 lines
17 KiB
C
/*++ 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;
|
||
}
|
||
|