/*++ 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;iBuffer[i] == L'\\') { CurrentNameEnd = i; break; } } if (CurrentNameEnd - CurrentNameStart > 13) { IsValidName = FALSE; } if (IsValidName) { CurrentDot = CurrentNameEnd; for (i=CurrentNameStart;iBuffer[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; }