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.
785 lines
18 KiB
785 lines
18 KiB
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
api.c
|
|
|
|
Abstract:
|
|
|
|
This module contains misc APIs that are used by the
|
|
NWC wksta.
|
|
|
|
Author:
|
|
|
|
ChuckC 2-Mar-94 Created
|
|
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include <stdlib.h>
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <nwcons.h>
|
|
#include <nwmisc.h>
|
|
#include <nwapi32.h>
|
|
#include "nwstatus.h"
|
|
#include "nwevent.h"
|
|
|
|
DWORD
|
|
NwMapStatus(
|
|
IN NTSTATUS NtStatus
|
|
);
|
|
|
|
DWORD
|
|
NwOpenPreferredServer(
|
|
PHANDLE ServerHandle
|
|
);
|
|
|
|
NTSTATUS
|
|
NwOpenHandle(
|
|
IN PUNICODE_STRING ObjectName,
|
|
IN BOOL ValidateFlag,
|
|
OUT PHANDLE ObjectHandle
|
|
);
|
|
|
|
NTSTATUS
|
|
NwCallNtOpenFile(
|
|
OUT PHANDLE ObjectHandle,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN PUNICODE_STRING ObjectName,
|
|
IN ULONG OpenOptions
|
|
);
|
|
|
|
|
|
//
|
|
// list of error mappings known for E3H calls. we do not have a single list
|
|
// because Netware reuses the numbers depending on call.
|
|
//
|
|
|
|
typedef struct _ERROR_MAP_ENTRY
|
|
{
|
|
UCHAR NetError;
|
|
NTSTATUS ResultingStatus;
|
|
} ERROR_MAP_ENTRY ;
|
|
|
|
ERROR_MAP_ENTRY Error_Map_Bindery[] =
|
|
{
|
|
|
|
//
|
|
// NetWare specific error mappings. Specific to E3H.
|
|
//
|
|
{ 1, STATUS_DISK_FULL },
|
|
{128, STATUS_SHARING_VIOLATION },
|
|
{129, STATUS_INSUFF_SERVER_RESOURCES },
|
|
{130, STATUS_ACCESS_DENIED },
|
|
{131, STATUS_DATA_ERROR },
|
|
{132, STATUS_ACCESS_DENIED },
|
|
{133, STATUS_ACCESS_DENIED },
|
|
{134, STATUS_ACCESS_DENIED },
|
|
{135, STATUS_OBJECT_NAME_INVALID },
|
|
{136, STATUS_INVALID_HANDLE },
|
|
{137, STATUS_ACCESS_DENIED },
|
|
{138, STATUS_ACCESS_DENIED },
|
|
{139, STATUS_ACCESS_DENIED },
|
|
{140, STATUS_ACCESS_DENIED },
|
|
{141, STATUS_SHARING_VIOLATION },
|
|
{142, STATUS_SHARING_VIOLATION },
|
|
{143, STATUS_ACCESS_DENIED },
|
|
{144, STATUS_ACCESS_DENIED },
|
|
{145, STATUS_OBJECT_NAME_COLLISION },
|
|
{146, STATUS_OBJECT_NAME_COLLISION },
|
|
{147, STATUS_ACCESS_DENIED },
|
|
{148, STATUS_ACCESS_DENIED },
|
|
{150, STATUS_INSUFF_SERVER_RESOURCES },
|
|
{151, STATUS_NO_SPOOL_SPACE },
|
|
{152, STATUS_NO_SUCH_DEVICE },
|
|
{153, STATUS_DISK_FULL },
|
|
{154, STATUS_NOT_SAME_DEVICE },
|
|
{155, STATUS_INVALID_HANDLE },
|
|
{156, STATUS_OBJECT_PATH_NOT_FOUND },
|
|
{157, STATUS_INSUFF_SERVER_RESOURCES },
|
|
{158, STATUS_OBJECT_PATH_INVALID },
|
|
{159, STATUS_SHARING_VIOLATION },
|
|
{160, STATUS_DIRECTORY_NOT_EMPTY },
|
|
{161, STATUS_DATA_ERROR },
|
|
{162, STATUS_SHARING_VIOLATION },
|
|
{192, STATUS_ACCESS_DENIED },
|
|
{198, STATUS_ACCESS_DENIED },
|
|
{211, STATUS_ACCESS_DENIED },
|
|
{212, STATUS_PRINT_QUEUE_FULL },
|
|
{213, STATUS_PRINT_CANCELLED },
|
|
{214, STATUS_ACCESS_DENIED },
|
|
{215, STATUS_PASSWORD_RESTRICTION },
|
|
{216, STATUS_PASSWORD_RESTRICTION },
|
|
{220, STATUS_ACCOUNT_DISABLED },
|
|
{222, STATUS_PASSWORD_EXPIRED },
|
|
{223, STATUS_PASSWORD_EXPIRED },
|
|
{239, STATUS_OBJECT_NAME_INVALID },
|
|
{240, STATUS_OBJECT_NAME_INVALID },
|
|
{251, STATUS_INVALID_PARAMETER },
|
|
{252, STATUS_NO_MORE_ENTRIES },
|
|
{253, STATUS_FILE_LOCK_CONFLICT },
|
|
{254, STATUS_FILE_LOCK_CONFLICT },
|
|
{255, STATUS_UNSUCCESSFUL}
|
|
};
|
|
|
|
|
|
ERROR_MAP_ENTRY Error_Map_General[] =
|
|
{
|
|
{ 1, STATUS_DISK_FULL },
|
|
{128, STATUS_SHARING_VIOLATION },
|
|
{129, STATUS_INSUFF_SERVER_RESOURCES },
|
|
{130, STATUS_ACCESS_DENIED },
|
|
{131, STATUS_DATA_ERROR },
|
|
{132, STATUS_ACCESS_DENIED },
|
|
{133, STATUS_ACCESS_DENIED },
|
|
{134, STATUS_ACCESS_DENIED },
|
|
{135, STATUS_OBJECT_NAME_INVALID },
|
|
{136, STATUS_INVALID_HANDLE },
|
|
{137, STATUS_ACCESS_DENIED },
|
|
{138, STATUS_ACCESS_DENIED },
|
|
{139, STATUS_ACCESS_DENIED },
|
|
{140, STATUS_ACCESS_DENIED },
|
|
{141, STATUS_SHARING_VIOLATION },
|
|
{142, STATUS_SHARING_VIOLATION },
|
|
{143, STATUS_ACCESS_DENIED },
|
|
{144, STATUS_ACCESS_DENIED },
|
|
{145, STATUS_OBJECT_NAME_COLLISION },
|
|
{146, STATUS_OBJECT_NAME_COLLISION },
|
|
{147, STATUS_ACCESS_DENIED },
|
|
{148, STATUS_ACCESS_DENIED },
|
|
{150, STATUS_INSUFF_SERVER_RESOURCES },
|
|
{151, STATUS_NO_SPOOL_SPACE },
|
|
{152, STATUS_NO_SUCH_DEVICE },
|
|
{153, STATUS_DISK_FULL },
|
|
{154, STATUS_NOT_SAME_DEVICE },
|
|
{155, STATUS_INVALID_HANDLE },
|
|
{156, STATUS_OBJECT_PATH_NOT_FOUND },
|
|
{157, STATUS_INSUFF_SERVER_RESOURCES },
|
|
{158, STATUS_OBJECT_PATH_INVALID },
|
|
{159, STATUS_SHARING_VIOLATION },
|
|
{160, STATUS_DIRECTORY_NOT_EMPTY },
|
|
{161, STATUS_DATA_ERROR },
|
|
{162, STATUS_SHARING_VIOLATION },
|
|
{192, STATUS_ACCESS_DENIED },
|
|
{198, STATUS_ACCESS_DENIED },
|
|
{211, STATUS_ACCESS_DENIED },
|
|
{212, STATUS_PRINT_QUEUE_FULL },
|
|
{213, STATUS_PRINT_CANCELLED },
|
|
{214, STATUS_ACCESS_DENIED },
|
|
{215, STATUS_DEVICE_BUSY },
|
|
{216, STATUS_DEVICE_DOES_NOT_EXIST },
|
|
{220, STATUS_ACCOUNT_DISABLED },
|
|
{222, STATUS_PASSWORD_EXPIRED },
|
|
{223, STATUS_PASSWORD_EXPIRED },
|
|
{239, STATUS_OBJECT_NAME_INVALID },
|
|
{240, STATUS_OBJECT_NAME_INVALID },
|
|
{251, STATUS_INVALID_PARAMETER },
|
|
{252, STATUS_NO_MORE_ENTRIES },
|
|
{253, STATUS_FILE_LOCK_CONFLICT },
|
|
{254, STATUS_FILE_LOCK_CONFLICT },
|
|
{255, STATUS_UNSUCCESSFUL}
|
|
};
|
|
|
|
#define NUM_ERRORS(x) (sizeof(x)/sizeof(x[0]))
|
|
|
|
DWORD
|
|
NwMapBinderyCompletionCode(
|
|
IN NTSTATUS NtStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function takes a bindery completion code embedded in an NT status
|
|
code and maps it to the appropriate Win32 error code. Used specifically
|
|
for E3H operations.
|
|
|
|
Arguments:
|
|
|
|
NtStatus - Supplies the NT status (that contains the code in low 16 bits)
|
|
|
|
Return Value:
|
|
|
|
Returns the appropriate Win32 error.
|
|
|
|
--*/
|
|
{
|
|
DWORD i; UCHAR code ;
|
|
|
|
//
|
|
// A small optimization for the most common case.
|
|
//
|
|
if (NtStatus == STATUS_SUCCESS)
|
|
return NO_ERROR;
|
|
|
|
//
|
|
// Map connection errors specially.
|
|
//
|
|
|
|
if ( ( (NtStatus & 0xFFFF0000) == 0xC0010000) &&
|
|
( (NtStatus & 0xFF00) != 0 ) )
|
|
{
|
|
return ERROR_UNEXP_NET_ERR;
|
|
}
|
|
|
|
//
|
|
// if facility code not set, assume it is NT Status
|
|
//
|
|
if ( (NtStatus & 0xFFFF0000) != 0xC0010000)
|
|
return RtlNtStatusToDosError(NtStatus);
|
|
|
|
code = (UCHAR)(NtStatus & 0x000000FF);
|
|
for (i = 0; i < NUM_ERRORS(Error_Map_Bindery); i++)
|
|
{
|
|
if (Error_Map_Bindery[i].NetError == code)
|
|
return( NwMapStatus(Error_Map_Bindery[i].ResultingStatus));
|
|
}
|
|
|
|
//
|
|
// if cannot find let NwMapStatus do its best
|
|
//
|
|
return NwMapStatus(NtStatus);
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
NwMapStatus(
|
|
IN NTSTATUS NtStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function takes an NT status code and maps it to the appropriate
|
|
Win32 error code. If facility code is set, assume it is NW specific
|
|
|
|
Arguments:
|
|
|
|
NtStatus - Supplies the NT status.
|
|
|
|
Return Value:
|
|
|
|
Returns the appropriate Win32 error.
|
|
|
|
--*/
|
|
{
|
|
DWORD i; UCHAR code ;
|
|
|
|
//
|
|
// A small optimization for the most common case.
|
|
//
|
|
if (NtStatus == STATUS_SUCCESS)
|
|
return NO_ERROR;
|
|
|
|
//
|
|
// Map connection errors specially.
|
|
//
|
|
|
|
if ( ( (NtStatus & 0xFFFF0000) == 0xC0010000) &&
|
|
( (NtStatus & 0xFF00) != 0 ) )
|
|
{
|
|
return ERROR_UNEXP_NET_ERR;
|
|
}
|
|
|
|
//
|
|
// if facility code set, assume it is NW Completion code
|
|
//
|
|
if ( (NtStatus & 0xFFFF0000) == 0xC0010000)
|
|
{
|
|
code = (UCHAR)(NtStatus & 0x000000FF);
|
|
for (i = 0; i < NUM_ERRORS(Error_Map_General); i++)
|
|
{
|
|
if (Error_Map_General[i].NetError == code)
|
|
{
|
|
//
|
|
// map it to NTSTATUS and then drop thru to map to Win32
|
|
//
|
|
NtStatus = Error_Map_General[i].ResultingStatus ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (NtStatus) {
|
|
case STATUS_OBJECT_NAME_COLLISION:
|
|
return ERROR_ALREADY_ASSIGNED;
|
|
|
|
case STATUS_OBJECT_NAME_NOT_FOUND:
|
|
return ERROR_NOT_CONNECTED;
|
|
|
|
case STATUS_IMAGE_ALREADY_LOADED:
|
|
case STATUS_REDIRECTOR_STARTED:
|
|
return ERROR_SERVICE_ALREADY_RUNNING;
|
|
|
|
case STATUS_REDIRECTOR_HAS_OPEN_HANDLES:
|
|
return ERROR_REDIRECTOR_HAS_OPEN_HANDLES;
|
|
|
|
case STATUS_NO_MORE_FILES:
|
|
case STATUS_NO_MORE_ENTRIES:
|
|
return WN_NO_MORE_ENTRIES;
|
|
|
|
case STATUS_MORE_ENTRIES:
|
|
return WN_MORE_DATA;
|
|
|
|
case STATUS_CONNECTION_IN_USE:
|
|
return ERROR_DEVICE_IN_USE;
|
|
|
|
case NWRDR_PASSWORD_HAS_EXPIRED:
|
|
return NW_PASSWORD_HAS_EXPIRED;
|
|
|
|
case STATUS_INVALID_DEVICE_REQUEST:
|
|
return ERROR_CONNECTION_INVALID;
|
|
|
|
default:
|
|
return RtlNtStatusToDosError(NtStatus);
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
NwGetGraceLoginCount(
|
|
LPWSTR Server,
|
|
LPWSTR UserName,
|
|
LPDWORD lpResult
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get the number grace logins for a user.
|
|
|
|
Arguments:
|
|
|
|
Server - the server to authenticate against
|
|
|
|
UserName - the user account
|
|
|
|
Return Value:
|
|
|
|
Returns the appropriate Win32 error.
|
|
|
|
--*/
|
|
{
|
|
DWORD status ;
|
|
HANDLE hConn ;
|
|
CHAR UserNameO[NW_MAX_USERNAME_LEN+1] ;
|
|
BYTE LoginControl[128] ;
|
|
BYTE MoreFlags, PropFlags ;
|
|
|
|
//
|
|
// skip the backslashes if present
|
|
//
|
|
if (*Server == L'\\')
|
|
Server += 2 ;
|
|
|
|
//
|
|
// attach to the NW server
|
|
//
|
|
if (status = NWAttachToFileServerW(Server,
|
|
0,
|
|
&hConn))
|
|
{
|
|
return status ;
|
|
}
|
|
|
|
//
|
|
// convert unicode UserName to OEM, and then call the NCP
|
|
//
|
|
if ( !WideCharToMultiByte(CP_OEMCP,
|
|
0,
|
|
UserName,
|
|
-1,
|
|
UserNameO,
|
|
sizeof(UserNameO),
|
|
NULL,
|
|
NULL))
|
|
{
|
|
status = GetLastError() ;
|
|
}
|
|
else
|
|
{
|
|
status = NWReadPropertyValue( hConn,
|
|
UserNameO,
|
|
OT_USER,
|
|
"LOGIN_CONTROL",
|
|
1,
|
|
LoginControl,
|
|
&MoreFlags,
|
|
&PropFlags) ;
|
|
}
|
|
|
|
//
|
|
// dont need these anymore. if any error, bag out
|
|
//
|
|
(void) NWDetachFromFileServer(hConn) ;
|
|
|
|
|
|
if (status == NO_ERROR)
|
|
*lpResult = (DWORD) LoginControl[7] ;
|
|
|
|
return status ;
|
|
}
|
|
|
|
|
|
WORD
|
|
NwParseNdsUncPath(
|
|
IN OUT LPWSTR * Result,
|
|
IN LPWSTR ContainerName,
|
|
IN ULONG flag
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used to extract either the tree name, fully distinguished
|
|
name path to an object, or object name, out of a complete NDS UNC path.
|
|
|
|
Arguments:
|
|
|
|
Result - parsed result buffer.
|
|
ContainerName - Complete NDS UNC path that is to be parsed.
|
|
flag - Flag indicating operation to be performed:
|
|
|
|
PARSE_NDS_GET_TREE_NAME
|
|
PARSE_NDS_GET_PATH_NAME
|
|
PARSE_NDS_GET_OBJECT_NAME
|
|
|
|
|
|
Return Value:
|
|
|
|
Length of string in result buffer. If error occured, 0 is returned.
|
|
|
|
--*/ // NwParseNdsUncPath
|
|
{
|
|
unsigned short length = 2;
|
|
unsigned short totalLength = (USHORT) wcslen( ContainerName );
|
|
|
|
if ( totalLength < 2 )
|
|
return 0;
|
|
|
|
//
|
|
// First get length to indicate the character in the string that indicates the
|
|
// "\" in between the tree name and the rest of the UNC path.
|
|
//
|
|
// Example: \\<tree name>\<path to object>[\|.]<object>
|
|
// ^
|
|
// |
|
|
//
|
|
while ( length < totalLength && ContainerName[length] != L'\\' )
|
|
{
|
|
length++;
|
|
}
|
|
|
|
if ( flag == PARSE_NDS_GET_TREE_NAME )
|
|
{
|
|
*Result = (LPWSTR) ( ContainerName + 2 );
|
|
|
|
return ( length - 2 ) * sizeof( WCHAR ); // Take off 2 for the two \\'s
|
|
}
|
|
|
|
if ( flag == PARSE_NDS_GET_PATH_NAME && length == totalLength )
|
|
{
|
|
*Result = ContainerName;
|
|
|
|
return 0;
|
|
}
|
|
|
|
if ( flag == PARSE_NDS_GET_PATH_NAME )
|
|
{
|
|
*Result = ContainerName + length + 1;
|
|
|
|
return ( totalLength - length - 1 ) * sizeof( WCHAR );
|
|
}
|
|
|
|
*Result = ContainerName + totalLength - 1;
|
|
length = 1;
|
|
|
|
while ( **Result != L'\\' )
|
|
{
|
|
*Result--;
|
|
length++;
|
|
}
|
|
|
|
*Result++;
|
|
length--;
|
|
|
|
return length * sizeof( WCHAR );
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwOpenAServer(
|
|
PWCHAR pwszServName,
|
|
PHANDLE ServerHandle,
|
|
BOOL fVerify
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine opens a handle to a server.
|
|
|
|
Arguments:
|
|
|
|
ServerHandle - Receives an opened handle to the preferred or
|
|
nearest server.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR or reason for failure.
|
|
|
|
--*/
|
|
{
|
|
UNICODE_STRING AServer;
|
|
WCHAR wszName[sizeof(NW_RDR_NAME) + (48 * sizeof(WCHAR))];
|
|
DWORD wLen;
|
|
|
|
|
|
if(!pwszServName)
|
|
{
|
|
pwszServName = NW_RDR_PREFERRED_SERVER;
|
|
RtlInitUnicodeString(&AServer, wszName);
|
|
}
|
|
else
|
|
{
|
|
wLen = wcslen(pwszServName);
|
|
if(wLen > 47)
|
|
{
|
|
return(WSAEFAULT);
|
|
}
|
|
wcscpy(wszName, NW_RDR_NAME);
|
|
wcscat(wszName, pwszServName);
|
|
RtlInitUnicodeString(&AServer, wszName);
|
|
}
|
|
|
|
return RtlNtStatusToDosError(
|
|
NwOpenHandle(&AServer, fVerify, ServerHandle)
|
|
);
|
|
|
|
}
|
|
|
|
|
|
DWORD
|
|
NwOpenPreferredServer(
|
|
PHANDLE ServerHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine opens a handle to the preferred server. If the
|
|
preferred server has not been specified, a handle to the
|
|
nearest server is opened instead.
|
|
|
|
Arguments:
|
|
|
|
ServerHandle - Receives an opened handle to the preferred or
|
|
nearest server.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR or reason for failure.
|
|
|
|
--*/
|
|
{
|
|
UNICODE_STRING PreferredServer;
|
|
|
|
|
|
//
|
|
// The NetWare redirector recognizes "*" to mean the preferred
|
|
// or nearest server.
|
|
//
|
|
RtlInitUnicodeString(&PreferredServer, NW_RDR_PREFERRED_SERVER);
|
|
|
|
return RtlNtStatusToDosError(
|
|
NwOpenHandle(&PreferredServer, FALSE, ServerHandle)
|
|
);
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NwOpenHandle(
|
|
IN PUNICODE_STRING ObjectName,
|
|
IN BOOL ValidateFlag,
|
|
OUT PHANDLE ObjectHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function opens a handle to \Device\Nwrdr\<ObjectName>.
|
|
|
|
Arguments:
|
|
|
|
ObjectName - Supplies the name of the redirector object to open.
|
|
|
|
ValidateFlag - Supplies a flag which if TRUE, opens the handle to
|
|
the object by validating the default user account.
|
|
|
|
ObjectHandle - Receives a pointer to the opened object handle.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS or reason for failure.
|
|
|
|
--*/
|
|
{
|
|
ACCESS_MASK DesiredAccess = SYNCHRONIZE;
|
|
|
|
|
|
if (ValidateFlag) {
|
|
|
|
//
|
|
// The redirector only authenticates the default user credential
|
|
// if the remote resource is opened with write access.
|
|
//
|
|
DesiredAccess |= FILE_WRITE_DATA;
|
|
}
|
|
|
|
|
|
*ObjectHandle = NULL;
|
|
|
|
return NwCallNtOpenFile(
|
|
ObjectHandle,
|
|
DesiredAccess,
|
|
ObjectName,
|
|
FILE_SYNCHRONOUS_IO_NONALERT
|
|
);
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NwCallNtOpenFile(
|
|
OUT PHANDLE ObjectHandle,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN PUNICODE_STRING ObjectName,
|
|
IN ULONG OpenOptions
|
|
)
|
|
{
|
|
|
|
NTSTATUS ntstatus;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
ObjectName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
ntstatus = NtOpenFile(
|
|
ObjectHandle,
|
|
DesiredAccess,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_VALID_FLAGS,
|
|
OpenOptions
|
|
);
|
|
|
|
if (!NT_ERROR(ntstatus) &&
|
|
!NT_INFORMATION(ntstatus) &&
|
|
!NT_WARNING(ntstatus)) {
|
|
|
|
ntstatus = IoStatusBlock.Status;
|
|
|
|
}
|
|
|
|
return ntstatus;
|
|
}
|
|
|
|
|
|
BOOL
|
|
NwConvertToUnicode(
|
|
OUT LPWSTR *UnicodeOut,
|
|
IN LPSTR OemIn
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function converts the given OEM string to a Unicode string.
|
|
The Unicode string is returned in a buffer allocated by this
|
|
function and must be freed with LocalFree.
|
|
|
|
Arguments:
|
|
|
|
UnicodeOut - Receives a pointer to the Unicode string.
|
|
|
|
OemIn - This is a pointer to an ansi string that is to be converted.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The conversion was successful.
|
|
|
|
FALSE - The conversion was unsuccessful. In this case a buffer for
|
|
the unicode string was not allocated.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS ntstatus;
|
|
DWORD BufSize;
|
|
UNICODE_STRING UnicodeString;
|
|
OEM_STRING OemString;
|
|
|
|
|
|
//
|
|
// Allocate a buffer for the unicode string.
|
|
//
|
|
|
|
BufSize = (strlen(OemIn) + 1) * sizeof(WCHAR);
|
|
|
|
*UnicodeOut = LocalAlloc(LMEM_ZEROINIT, BufSize);
|
|
|
|
if (*UnicodeOut == NULL) {
|
|
KdPrint(("NWWORKSTATION: NwConvertToUnicode:LocalAlloc failed %lu\n",
|
|
GetLastError()));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Initialize the string structures
|
|
//
|
|
RtlInitAnsiString((PANSI_STRING) &OemString, OemIn);
|
|
|
|
UnicodeString.Buffer = *UnicodeOut;
|
|
UnicodeString.MaximumLength = (USHORT) BufSize;
|
|
UnicodeString.Length = 0;
|
|
|
|
//
|
|
// Call the conversion function.
|
|
//
|
|
ntstatus = RtlOemStringToUnicodeString(
|
|
&UnicodeString, // Destination
|
|
&OemString, // Source
|
|
FALSE // Allocate the destination
|
|
);
|
|
|
|
if (ntstatus != STATUS_SUCCESS) {
|
|
|
|
KdPrint(("NWWORKSTATION: NwConvertToUnicode: RtlOemStringToUnicodeString failure x%08lx\n",
|
|
ntstatus));
|
|
|
|
(void) LocalFree((HLOCAL) *UnicodeOut);
|
|
*UnicodeOut = NULL;
|
|
return FALSE;
|
|
}
|
|
|
|
*UnicodeOut = UnicodeString.Buffer;
|
|
|
|
return TRUE;
|
|
|
|
}
|