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.
1743 lines
43 KiB
1743 lines
43 KiB
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <lmcons.h>
|
|
|
|
#include <lmerr.h>
|
|
#include <align.h>
|
|
#include <netdebug.h>
|
|
#include <lmapibuf.h>
|
|
#define DEBUG_ALLOCATE
|
|
#include <nldebug.h>
|
|
#undef DEBUG_ALLOCATE
|
|
#ifndef SECURITY_WIN32
|
|
#define SECURITY_WIN32
|
|
#endif // SECURITY_WIN32
|
|
#include <security.h>
|
|
#include "ntcalls.h"
|
|
#include <icanon.h>
|
|
#include <tstring.h>
|
|
|
|
#define _DECL_DLLMAIN
|
|
|
|
BOOL WINAPI DllMain(
|
|
HANDLE hInstance,
|
|
ULONG dwReason,
|
|
PVOID lpReserved
|
|
)
|
|
{
|
|
NET_API_STATUS Status = NO_ERROR;
|
|
|
|
if (dwReason == DLL_PROCESS_ATTACH)
|
|
{
|
|
Status = DCNameInitialize();
|
|
#if NETLOGONDBG
|
|
NlGlobalTrace = 0xFFFFFFFF;
|
|
#endif // NETLOGONDBG
|
|
if (Status != NO_ERROR)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
else if (dwReason == DLL_PROCESS_DETACH)
|
|
{
|
|
DCNameClose();
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
NetpAssertFailed(
|
|
IN LPDEBUG_STRING FailedAssertion,
|
|
IN LPDEBUG_STRING FileName,
|
|
IN DWORD LineNumber,
|
|
IN LPDEBUG_STRING Message OPTIONAL
|
|
)
|
|
{
|
|
assert(FALSE);
|
|
}
|
|
|
|
VOID
|
|
NlAssertFailed(
|
|
IN PVOID FailedAssertion,
|
|
IN PVOID FileName,
|
|
IN ULONG LineNumber,
|
|
IN PCHAR Message OPTIONAL
|
|
)
|
|
{
|
|
assert(FALSE);
|
|
}
|
|
|
|
VOID
|
|
MyRtlAssert(
|
|
IN PVOID FailedAssertion,
|
|
IN PVOID FileName,
|
|
IN ULONG LineNumber,
|
|
IN PCHAR Message OPTIONAL
|
|
)
|
|
{
|
|
assert(FALSE);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
NET_API_STATUS
|
|
NetpGetComputerName (
|
|
OUT LPWSTR *ComputerNamePtr
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine obtains the computer name from a persistent database.
|
|
Currently that database is the NT.CFG file.
|
|
|
|
This routine makes no assumptions on the length of the computername.
|
|
Therefore, it allocates the storage for the name using NetApiBufferAllocate.
|
|
It is necessary for the user to free that space using NetApiBufferFree when
|
|
finished.
|
|
|
|
Arguments:
|
|
|
|
ComputerNamePtr - This is a pointer to the location where the pointer
|
|
to the computer name is to be placed.
|
|
|
|
Return Value:
|
|
|
|
NERR_Success - If the operation was successful.
|
|
|
|
It will return assorted Net or Win32 error messages if not.
|
|
|
|
--*/
|
|
{
|
|
NET_API_STATUS ApiStatus = NO_ERROR;
|
|
ULONG Index;
|
|
DWORD NameSize = MAX_COMPUTERNAME_LENGTH + 1; // updated by win32 API.
|
|
CHAR AnsiName[MAX_COMPUTERNAME_LENGTH + 1];
|
|
|
|
//
|
|
// Check for caller's errors.
|
|
//
|
|
if (ComputerNamePtr == NULL) {
|
|
ApiStatus = ERROR_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Allocate space for computer name.
|
|
//
|
|
*ComputerNamePtr = (LPWSTR)LocalAlloc( 0,
|
|
(MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR) );
|
|
|
|
if (*ComputerNamePtr == NULL) {
|
|
ApiStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Ask system what current computer name is.
|
|
//
|
|
if ( !GetComputerName(
|
|
AnsiName,
|
|
&NameSize ) ) {
|
|
|
|
ApiStatus = (NET_API_STATUS) GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
Index = MultiByteToWideChar(
|
|
CP_ACP,
|
|
MB_PRECOMPOSED,
|
|
AnsiName,
|
|
NameSize,
|
|
*ComputerNamePtr,
|
|
(MAX_COMPUTERNAME_LENGTH) * sizeof(WCHAR)
|
|
);
|
|
if (!Index)
|
|
{
|
|
ApiStatus = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
*(*ComputerNamePtr + Index) = UNICODE_NULL;
|
|
|
|
//
|
|
// All done.
|
|
//
|
|
|
|
Cleanup:
|
|
if (ApiStatus != NO_ERROR)
|
|
{
|
|
if (ComputerNamePtr)
|
|
{
|
|
if (*ComputerNamePtr)
|
|
{
|
|
LocalFree( *ComputerNamePtr );
|
|
*ComputerNamePtr = NULL;
|
|
}
|
|
}
|
|
}
|
|
return ApiStatus;
|
|
}
|
|
|
|
VOID
|
|
MyRtlInitUnicodeString(
|
|
OUT PUNICODE_STRING DestinationString,
|
|
IN PCWSTR SourceString OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The RtlInitUnicodeString function initializes an NT counted
|
|
unicode string. The DestinationString is initialized to point to
|
|
the SourceString and the Length and MaximumLength fields of
|
|
DestinationString are initialized to the length of the SourceString,
|
|
which is zero if SourceString is not specified.
|
|
|
|
Arguments:
|
|
|
|
DestinationString - Pointer to the counted string to initialize
|
|
|
|
SourceString - Optional pointer to a null terminated unicode string that
|
|
the counted string is to point to.
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Length;
|
|
|
|
DestinationString->Buffer = (PWSTR)SourceString;
|
|
if (ARGUMENT_PRESENT( SourceString )) {
|
|
Length = wcslen( SourceString ) * sizeof( WCHAR );
|
|
DestinationString->Length = (USHORT)Length;
|
|
DestinationString->MaximumLength = (USHORT)(Length + sizeof(UNICODE_NULL));
|
|
}
|
|
else {
|
|
DestinationString->MaximumLength = 0;
|
|
DestinationString->Length = 0;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
MyRtlInitString(
|
|
OUT PSTRING DestinationString,
|
|
IN PCSTR SourceString OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The RtlInitString function initializes an NT counted string.
|
|
The DestinationString is initialized to point to the SourceString
|
|
and the Length and MaximumLength fields of DestinationString are
|
|
initialized to the length of the SourceString, which is zero if
|
|
SourceString is not specified.
|
|
|
|
Arguments:
|
|
|
|
DestinationString - Pointer to the counted string to initialize
|
|
|
|
SourceString - Optional pointer to a null terminated string that
|
|
the counted string is to point to.
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Length;
|
|
|
|
DestinationString->Buffer = (PCHAR)SourceString;
|
|
if (ARGUMENT_PRESENT( SourceString )) {
|
|
Length = strlen(SourceString);
|
|
DestinationString->Length = (USHORT)Length;
|
|
DestinationString->MaximumLength = (USHORT)(Length+1);
|
|
}
|
|
}
|
|
|
|
// from net\netlib\memalloc.c
|
|
|
|
// Define memory alloc/realloc flags. We are NOT using movable or zeroed
|
|
// on allocation here.
|
|
|
|
#define NETLIB_LOCAL_ALLOCATION_FLAGS LMEM_FIXED
|
|
LPVOID
|
|
NetpMemoryAllocate(
|
|
IN DWORD Size
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
NetpMemoryAllocate will allocate memory, or return NULL if not available.
|
|
|
|
Arguments:
|
|
|
|
Size - Supplies number of bytes of memory to allocate.
|
|
|
|
Return Value:
|
|
|
|
LPVOID - pointer to allocated memory.
|
|
NULL - no memory is available.
|
|
|
|
--*/
|
|
|
|
{
|
|
LPVOID NewAddress;
|
|
|
|
if (Size == 0) {
|
|
return (NULL);
|
|
}
|
|
#ifdef WIN32
|
|
{
|
|
HANDLE hMem;
|
|
hMem = LocalAlloc(
|
|
NETLIB_LOCAL_ALLOCATION_FLAGS,
|
|
Size); // size in bytes
|
|
NewAddress = (LPVOID) hMem;
|
|
}
|
|
#else // ndef WIN32
|
|
#ifndef CDEBUG
|
|
NewAddress = RtlAllocateHeap(
|
|
RtlProcessHeap( ), 0, // heap handle
|
|
Size )); // bytes wanted
|
|
#else // def CDEBUG
|
|
NetpAssert( Size == (DWORD) (size_t) Size );
|
|
NewAddress = malloc( (size_t) Size ));
|
|
#endif // def CDEBUG
|
|
#endif // ndef WIN32
|
|
|
|
NetpAssert( ROUND_UP_POINTER( NewAddress, ALIGN_WORST) == NewAddress);
|
|
return (NewAddress);
|
|
|
|
} // NetpMemoryAllocate
|
|
|
|
VOID
|
|
NetpMemoryFree(
|
|
IN LPVOID Address OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free memory at Address (must have been gotten from NetpMemoryAllocate or
|
|
NetpMemoryReallocate). (Address may be NULL.)
|
|
|
|
Arguments:
|
|
|
|
Address - points to an area allocated by NetpMemoryAllocate (or
|
|
NetpMemoryReallocate).
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
NetpAssert( ROUND_UP_POINTER( Address, ALIGN_WORST) == Address);
|
|
|
|
#ifdef WIN32
|
|
if (Address == NULL) {
|
|
return;
|
|
}
|
|
if (LocalFree(Address) != NULL) {
|
|
NetpAssert(FALSE);
|
|
}
|
|
#else // ndef WIN32
|
|
#ifndef CDEBUG
|
|
if (Address == NULL) {
|
|
return;
|
|
}
|
|
RtlFreeHeap(
|
|
RtlProcessHeap( ), 0, // heap handle
|
|
Address); // addr of alloc'ed space.
|
|
#else // def CDEBUG
|
|
free( Address );
|
|
#endif // def CDEBUG
|
|
#endif // ndef WIN32
|
|
} // netpMemoryFree
|
|
|
|
/*
|
|
ULONG
|
|
MyRtlxOemStringToUnicodeSize(
|
|
POEM_STRING OemString
|
|
)
|
|
{
|
|
return ((OemString->Length + sizeof((UCHAR)NULL)) * sizeof(WCHAR));
|
|
}
|
|
|
|
ULONG
|
|
RtlxUnicodeStringToOemSize(
|
|
PUNICODE_STRING UnicodeString
|
|
)
|
|
{
|
|
return ((UnicodeString->Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR));
|
|
}
|
|
|
|
*/
|
|
// from net\netlib\copystr.c
|
|
|
|
VOID
|
|
NetpCopyWStrToStr(
|
|
OUT LPSTR Dest,
|
|
IN LPWSTR Src
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
NetpCopyWStrToStr copies characters from a source string
|
|
to a destination, converting as it copies them.
|
|
|
|
Arguments:
|
|
|
|
Dest - is an LPSTR indicating where the converted characters are to go.
|
|
This string will be in the default codepage for the LAN.
|
|
|
|
Src - is in LPWSTR indicating the source string.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
OEM_STRING DestAnsi;
|
|
NTSTATUS NtStatus;
|
|
UNICODE_STRING SrcUnicode;
|
|
|
|
NetpAssert( Dest != NULL );
|
|
NetpAssert( Src != NULL );
|
|
NetpAssert( ((LPVOID)Dest) != ((LPVOID)Src) );
|
|
NetpAssert( ROUND_UP_POINTER( Src, ALIGN_WCHAR ) == Src );
|
|
|
|
*Dest = '\0';
|
|
|
|
RtlInitString(
|
|
& DestAnsi, // output: struct
|
|
Dest); // input: null terminated
|
|
|
|
// Tell RTL routines there's enough memory out there.
|
|
DestAnsi.MaximumLength = (USHORT) (wcslen(Src)+1);
|
|
|
|
RtlInitUnicodeString(
|
|
& SrcUnicode, // output: struct
|
|
Src); // input: null terminated
|
|
|
|
NtStatus = RtlUnicodeStringToOemString(
|
|
& DestAnsi, // output: struct
|
|
& SrcUnicode, // input: struct
|
|
(BOOLEAN) FALSE); // don't allocate string.
|
|
|
|
NetpAssert( NT_SUCCESS(NtStatus) );
|
|
|
|
} // NetpCopyWStrToStr
|
|
|
|
|
|
|
|
// from net\netlib\copystr.c
|
|
|
|
VOID
|
|
NetpCopyStrToWStr(
|
|
OUT LPWSTR Dest,
|
|
IN LPSTR Src
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
NetpCopyStrToWStr copies characters from a source string
|
|
to a destination, converting as it copies them.
|
|
|
|
Arguments:
|
|
|
|
Dest - is an LPWSTR indicating where the converted characters are to go.
|
|
|
|
Src - is in LPSTR indicating the source string. This must be a string in
|
|
the default codepage of the LAN.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
UNICODE_STRING DestUnicode;
|
|
NTSTATUS NtStatus;
|
|
OEM_STRING SrcAnsi;
|
|
|
|
NetpAssert( Dest != NULL );
|
|
NetpAssert( Src != NULL );
|
|
NetpAssert( ((LPVOID)Dest) != ((LPVOID)Src) );
|
|
NetpAssert( ROUND_UP_POINTER( Dest, ALIGN_WCHAR ) == Dest );
|
|
|
|
*Dest = L'\0';
|
|
|
|
RtlInitString(
|
|
& SrcAnsi, // output: struct
|
|
Src); // input: null terminated
|
|
|
|
RtlInitUnicodeString(
|
|
& DestUnicode, // output: struct
|
|
Dest); // input: null terminated
|
|
|
|
// Tell RTL routines there's enough memory out there.
|
|
DestUnicode.MaximumLength = (USHORT)
|
|
((USHORT) (strlen(Src)+1)) * (USHORT) sizeof(wchar_t);
|
|
|
|
NtStatus = RtlOemStringToUnicodeString(
|
|
& DestUnicode, // output: struct
|
|
& SrcAnsi, // input: struct
|
|
(BOOLEAN) FALSE); // don't allocate string.
|
|
|
|
NetpAssert( NT_SUCCESS(NtStatus) );
|
|
|
|
} // NetpCopyStrToWStr
|
|
|
|
//
|
|
// Inline functions to convert between FILETIME and TimeStamp
|
|
//
|
|
#pragma warning( disable : 4035) // Don't complain about no return
|
|
|
|
TimeStamp __inline
|
|
FileTimeToTimeStamp(
|
|
const FILETIME *pft)
|
|
{
|
|
_asm {
|
|
mov edx, pft
|
|
mov eax, [edx].dwLowDateTime
|
|
mov edx, [edx].dwHighDateTime
|
|
}
|
|
}
|
|
|
|
#pragma warning( default : 4035) // Reenable warning
|
|
|
|
NTSTATUS
|
|
MyNtQuerySystemTime (
|
|
OUT PTimeStamp SystemTimeStamp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the current system time (UTC), as a timestamp
|
|
(a 64-bit unsigned integer, in 100-nanosecond increments).
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
The current system time.
|
|
|
|
--*/
|
|
|
|
{
|
|
SYSTEMTIME SystemTime;
|
|
FILETIME FileTime;
|
|
|
|
GetSystemTime(&SystemTime);
|
|
SystemTimeToFileTime(&SystemTime, &FileTime);
|
|
|
|
*SystemTimeStamp = FileTimeToTimeStamp(&FileTime);
|
|
|
|
return STATUS_SUCCESS; // WIN32_CHICAGO do something useful here
|
|
}
|
|
|
|
ULONG
|
|
MyUnicodeStringToMultibyteSize(
|
|
IN PUNICODE_STRING UnicodeString,
|
|
IN UINT CodePage
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function computes the number of bytes required to store
|
|
a NULL terminated oem/ansi string that is equivalent to the specified
|
|
unicode string. If an oem/ansi string can not be formed or the specified
|
|
unicode string is empty, the return value is 0.
|
|
|
|
Arguments:
|
|
|
|
UnicodeString - Supplies a unicode string whose equivalent size as
|
|
an oem string is to be calculated.
|
|
|
|
CodePage - Specifies the code page used to perform the conversion.
|
|
|
|
Return Value:
|
|
|
|
0 - The operation failed, the unicode string can not be translated
|
|
into oem/ansi using the OEM/ANSI code page therefore no storage is
|
|
needed for the oem/ansi string.
|
|
|
|
!0 - The operation was successful. The return value specifies the
|
|
number of bytes required to hold an NULL terminated oem/ansi string
|
|
equivalent to the specified unicode string.
|
|
|
|
--*/
|
|
|
|
{
|
|
int cbMultiByteString = 0;
|
|
|
|
if (UnicodeString->Length != 0) {
|
|
cbMultiByteString = WideCharToMultiByte(
|
|
CodePage,
|
|
0, // WIN32_CHICAGO this is something else
|
|
UnicodeString->Buffer,
|
|
UnicodeString->Length / sizeof (WCHAR),
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL );
|
|
}
|
|
|
|
if ( cbMultiByteString > 0 ) {
|
|
|
|
//
|
|
// Add one byte for the NULL terminating character
|
|
//
|
|
return (ULONG) (cbMultiByteString + 1);
|
|
|
|
} else {
|
|
return 0;
|
|
}
|
|
|
|
}
|
|
|
|
ULONG
|
|
MyMultibyteStringToUnicodeSize(
|
|
IN PSTRING MultibyteString,
|
|
IN UINT CodePage
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function computes the number of bytes required to store
|
|
a NULL terminated unicode string that is equivalent to the specified
|
|
oem/ansi string. If a unicode string can not be formed or the specified
|
|
ansi/oem string is empty, the return value is 0.
|
|
|
|
Arguments:
|
|
|
|
UnicodeString - Supplies a unicode string whose equivalent size as
|
|
an oem string is to be calculated.
|
|
|
|
CodePage - Specifies the code page used to perform the conversion.
|
|
|
|
Return Value:
|
|
|
|
0 - The operation failed, the oem/ansi string can not be translated
|
|
into unicode using the OEM/ANSI code page therefore no storage is
|
|
needed for the unicode string.
|
|
|
|
!0 - The operation was successful. The return value specifies the
|
|
number of bytes required to hold an NULL terminated unicode string
|
|
equivalent to the specified oem/ansi string.
|
|
|
|
--*/
|
|
|
|
{
|
|
int ccUnicodeString = 0;
|
|
|
|
if (MultibyteString->Length != 0) {
|
|
ccUnicodeString = MultiByteToWideChar(
|
|
CodePage,
|
|
MB_PRECOMPOSED,
|
|
MultibyteString->Buffer,
|
|
MultibyteString->Length,
|
|
NULL,
|
|
0 );
|
|
}
|
|
|
|
if ( ccUnicodeString > 0 ) {
|
|
|
|
//
|
|
// Add the NULL terminating character
|
|
//
|
|
return (ULONG) ((ccUnicodeString + 1) * sizeof(WCHAR));
|
|
|
|
} else {
|
|
return 0;
|
|
}
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
MyRtlOemStringToUnicodeString(
|
|
OUT PUNICODE_STRING DestinationString,
|
|
IN POEM_STRING SourceString,
|
|
IN BOOLEAN AllocateDestinationString
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This functions converts the specified oem source string into a
|
|
Unicode string. The translation is done with respect to the
|
|
current system locale information.
|
|
|
|
Arguments:
|
|
|
|
DestinationString - Returns a unicode string that is equivalent to
|
|
the oem source string. The maximum length field is only
|
|
set if AllocateDestinationString is TRUE.
|
|
|
|
SourceString - Supplies the oem source string that is to be
|
|
converted to unicode.
|
|
|
|
AllocateDestinationString - Supplies a flag that controls whether or
|
|
not this API allocates the buffer space for the destination
|
|
string. If it does, then the buffer must be deallocated using
|
|
RtlFreeUnicodeString (note that only storage for
|
|
DestinationString->Buffer is allocated by this API).
|
|
|
|
Return Value:
|
|
|
|
SUCCESS - The conversion was successful
|
|
|
|
!SUCCESS - The operation failed. No storage was allocated and no
|
|
conversion was done. None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG UnicodeLength;
|
|
ULONG Index = 0;
|
|
NTSTATUS st = STATUS_SUCCESS;
|
|
|
|
UnicodeLength = MyMultibyteStringToUnicodeSize( SourceString, CP_OEMCP );
|
|
if ( UnicodeLength > MAXUSHORT || UnicodeLength == 0 ) {
|
|
return STATUS_INVALID_PARAMETER_2;
|
|
}
|
|
|
|
DestinationString->Length = (USHORT)(UnicodeLength - sizeof(UNICODE_NULL));
|
|
if ( AllocateDestinationString ) {
|
|
DestinationString->MaximumLength = (USHORT)UnicodeLength;
|
|
DestinationString->Buffer = (PWSTR) LocalAlloc(0, UnicodeLength);
|
|
if ( !DestinationString->Buffer ) {
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
else {
|
|
if ( DestinationString->Length >= DestinationString->MaximumLength ) {
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
}
|
|
|
|
if (SourceString->Length != 0)
|
|
{
|
|
Index = MultiByteToWideChar(
|
|
CP_OEMCP,
|
|
MB_PRECOMPOSED,
|
|
SourceString->Buffer,
|
|
SourceString->Length,
|
|
DestinationString->Buffer,
|
|
DestinationString->MaximumLength
|
|
);
|
|
|
|
if (Index == 0) {
|
|
if ( AllocateDestinationString ) {
|
|
LocalFree(DestinationString->Buffer);
|
|
}
|
|
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
|
|
DestinationString->Buffer[Index] = UNICODE_NULL;
|
|
|
|
return st;
|
|
}
|
|
|
|
NTSTATUS
|
|
MyRtlUnicodeStringToOemString(
|
|
OUT POEM_STRING DestinationString,
|
|
IN PUNICODE_STRING SourceString,
|
|
IN BOOLEAN AllocateDestinationString
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This functions converts the specified unicode source string into an
|
|
oem string. The translation is done with respect to the
|
|
current system locale information.
|
|
|
|
Arguments:
|
|
|
|
DestinationString - Returns an oem string that is equivalent to the
|
|
unicode source string. If the translation can not be done,
|
|
an error is returned. The maximum length field is only set if
|
|
AllocateDestinationString is TRUE.
|
|
|
|
SourceString - Supplies the unicode source string that is to be
|
|
converted to oem.
|
|
|
|
AllocateDestinationString - Supplies a flag that controls whether or
|
|
not this API allocates the buffer space for the destination
|
|
string. If it does, then the buffer must be deallocated using
|
|
RtlFreeAnsiString (note that only storage for
|
|
DestinationString->Buffer is allocated by this API).
|
|
|
|
Return Value:
|
|
|
|
SUCCESS - The conversion was successful
|
|
|
|
!SUCCESS - The operation failed. No storage was allocated and no
|
|
conversion was done. None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG OemLength;
|
|
ULONG Index = 0;
|
|
NTSTATUS ReturnStatus = STATUS_SUCCESS;
|
|
BOOL fUsed;
|
|
|
|
OemLength = MyUnicodeStringToMultibyteSize( SourceString, CP_OEMCP );
|
|
if ( OemLength > MAXUSHORT || OemLength == 0 ) {
|
|
return STATUS_INVALID_PARAMETER_2;
|
|
}
|
|
|
|
DestinationString->Length = (USHORT)(OemLength - 1);
|
|
if ( AllocateDestinationString ) {
|
|
DestinationString->MaximumLength = (USHORT)OemLength;
|
|
DestinationString->Buffer = (LPSTR)LocalAlloc(0, OemLength);
|
|
if ( !DestinationString->Buffer ) {
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
else {
|
|
if ( DestinationString->Length >= DestinationString->MaximumLength ) {
|
|
/*
|
|
* Return STATUS_BUFFER_OVERFLOW, but translate as much as
|
|
* will fit into the buffer first. This is the expected
|
|
* behavior for routines such as GetProfileStringA.
|
|
* Set the length of the buffer to one less than the maximum
|
|
* (so that the trail byte of a double byte char is not
|
|
* overwritten by doing DestinationString->Buffer[Index] = '\0').
|
|
* RtlUnicodeToMultiByteN is careful not to truncate a
|
|
* multibyte character.
|
|
*/
|
|
if (!DestinationString->MaximumLength) {
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
ReturnStatus = STATUS_BUFFER_OVERFLOW;
|
|
DestinationString->Length = DestinationString->MaximumLength - 1;
|
|
}
|
|
}
|
|
|
|
if (SourceString->Length != 0)
|
|
{
|
|
Index = WideCharToMultiByte(
|
|
CP_OEMCP,
|
|
0, // WIN32_CHICAGO this is something else
|
|
SourceString->Buffer,
|
|
SourceString->Length / sizeof (WCHAR),
|
|
DestinationString->Buffer,
|
|
DestinationString->MaximumLength,
|
|
NULL,
|
|
&fUsed
|
|
);
|
|
|
|
if (Index == 0)
|
|
{ // WIN32_CHICAGO do something useful here
|
|
if ( AllocateDestinationString ) {
|
|
LocalFree(DestinationString->Buffer);
|
|
}
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
|
|
DestinationString->Buffer[Index] = '\0';
|
|
|
|
return ReturnStatus;
|
|
}
|
|
|
|
NTSTATUS
|
|
MyRtlUnicodeStringToAnsiString(
|
|
OUT PANSI_STRING DestinationString,
|
|
IN PUNICODE_STRING SourceString,
|
|
IN BOOLEAN AllocateDestinationString
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This functions converts the specified unicode source string into an
|
|
ansi string. The translation is done with respect to the
|
|
current system locale information.
|
|
|
|
Arguments:
|
|
|
|
DestinationString - Returns an ansi string that is equivalent to the
|
|
unicode source string. If the translation can not be done,
|
|
an error is returned. The maximum length field is only set if
|
|
AllocateDestinationString is TRUE.
|
|
|
|
SourceString - Supplies the unicode source string that is to be
|
|
converted to ansi.
|
|
|
|
AllocateDestinationString - Supplies a flag that controls whether or
|
|
not this API allocates the buffer space for the destination
|
|
string. If it does, then the buffer must be deallocated using
|
|
RtlFreeAnsiString (note that only storage for
|
|
DestinationString->Buffer is allocated by this API).
|
|
|
|
Return Value:
|
|
|
|
SUCCESS - The conversion was successful
|
|
|
|
!SUCCESS - The operation failed. No storage was allocated and no
|
|
conversion was done. None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG AnsiLength;
|
|
ULONG Index = 0;
|
|
NTSTATUS ReturnStatus = STATUS_SUCCESS;
|
|
BOOL fUsed;
|
|
|
|
AnsiLength = MyUnicodeStringToMultibyteSize( SourceString, CP_ACP );
|
|
if ( AnsiLength > MAXUSHORT || AnsiLength == 0 ) {
|
|
return STATUS_INVALID_PARAMETER_2;
|
|
}
|
|
|
|
DestinationString->Length = (USHORT)(AnsiLength - 1);
|
|
if ( AllocateDestinationString ) {
|
|
DestinationString->MaximumLength = (USHORT)AnsiLength;
|
|
DestinationString->Buffer = (LPSTR)LocalAlloc(0, AnsiLength);
|
|
if ( !DestinationString->Buffer ) {
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
else {
|
|
if ( DestinationString->Length >= DestinationString->MaximumLength ) {
|
|
/*
|
|
* Return STATUS_BUFFER_OVERFLOW, but translate as much as
|
|
* will fit into the buffer first. This is the expected
|
|
* behavior for routines such as GetProfileStringA.
|
|
* Set the length of the buffer to one less than the maximum
|
|
* (so that the trail byte of a double byte char is not
|
|
* overwritten by doing DestinationString->Buffer[Index] = '\0').
|
|
* RtlUnicodeToMultiByteN is careful not to truncate a
|
|
* multibyte character.
|
|
*/
|
|
if (!DestinationString->MaximumLength) {
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
ReturnStatus = STATUS_BUFFER_OVERFLOW;
|
|
DestinationString->Length = DestinationString->MaximumLength - 1;
|
|
}
|
|
}
|
|
|
|
if (SourceString->Length != 0)
|
|
{
|
|
Index = WideCharToMultiByte(
|
|
CP_ACP,
|
|
0, // WIN32_CHICAGO this is something else
|
|
SourceString->Buffer,
|
|
SourceString->Length / sizeof (WCHAR),
|
|
DestinationString->Buffer,
|
|
DestinationString->MaximumLength,
|
|
NULL,
|
|
&fUsed
|
|
);
|
|
|
|
if (Index == 0)
|
|
{ // WIN32_CHICAGO do something useful here
|
|
if ( AllocateDestinationString ) {
|
|
LocalFree(DestinationString->Buffer);
|
|
}
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
|
|
DestinationString->Buffer[Index] = '\0';
|
|
|
|
return ReturnStatus;
|
|
}
|
|
|
|
NTSTATUS
|
|
MyRtlAnsiStringToUnicodeString(
|
|
OUT PUNICODE_STRING DestinationString,
|
|
IN PANSI_STRING SourceString,
|
|
IN BOOLEAN AllocateDestinationString
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This functions converts the specified ansi source string into a
|
|
Unicode string. The translation is done with respect to the
|
|
current system locale information.
|
|
|
|
Arguments:
|
|
|
|
DestinationString - Returns a unicode string that is equivalent to
|
|
the ansi source string. The maximum length field is only
|
|
set if AllocateDestinationString is TRUE.
|
|
|
|
SourceString - Supplies the ansi source string that is to be
|
|
converted to unicode.
|
|
|
|
AllocateDestinationString - Supplies a flag that controls whether or
|
|
not this API allocates the buffer space for the destination
|
|
string. If it does, then the buffer must be deallocated using
|
|
RtlFreeUnicodeString (note that only storage for
|
|
DestinationString->Buffer is allocated by this API).
|
|
|
|
Return Value:
|
|
|
|
SUCCESS - The conversion was successful
|
|
|
|
!SUCCESS - The operation failed. No storage was allocated and no
|
|
conversion was done. None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG UnicodeLength;
|
|
ULONG Index = 0;
|
|
NTSTATUS st = STATUS_SUCCESS;
|
|
|
|
UnicodeLength = MyMultibyteStringToUnicodeSize( SourceString, CP_ACP );
|
|
if ( UnicodeLength > MAXUSHORT || UnicodeLength == 0 ) {
|
|
return STATUS_INVALID_PARAMETER_2;
|
|
}
|
|
|
|
DestinationString->Length = (USHORT)(UnicodeLength - sizeof(UNICODE_NULL));
|
|
if ( AllocateDestinationString ) {
|
|
DestinationString->MaximumLength = (USHORT)UnicodeLength;
|
|
DestinationString->Buffer = (PWSTR) LocalAlloc(0, UnicodeLength);
|
|
if ( !DestinationString->Buffer ) {
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
else {
|
|
if ( DestinationString->Length >= DestinationString->MaximumLength ) {
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
}
|
|
|
|
if (SourceString->Length != 0)
|
|
{
|
|
Index = MultiByteToWideChar(
|
|
CP_ACP,
|
|
MB_PRECOMPOSED,
|
|
SourceString->Buffer,
|
|
SourceString->Length,
|
|
DestinationString->Buffer,
|
|
DestinationString->MaximumLength
|
|
);
|
|
|
|
if (Index == 0) {
|
|
if ( AllocateDestinationString ) {
|
|
LocalFree(DestinationString->Buffer);
|
|
}
|
|
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
|
|
DestinationString->Buffer[Index] = UNICODE_NULL;
|
|
|
|
return st;
|
|
}
|
|
|
|
// from ntos\rtl\random.c
|
|
|
|
#define Multiplier ((ULONG)(0x80000000ul - 19)) // 2**31 - 19
|
|
#define Increment ((ULONG)(0x80000000ul - 61)) // 2**31 - 61
|
|
#define Modulus ((ULONG)(0x80000000ul - 1)) // 2**31 - 1
|
|
|
|
ULONG
|
|
MyRtlUniform (
|
|
IN OUT PULONG Seed
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A simple uniform random number generator, based on D.H. Lehmer's 1948
|
|
alrogithm.
|
|
|
|
Arguments:
|
|
|
|
Seed - Supplies a pointer to the random number generator seed.
|
|
|
|
Return Value:
|
|
|
|
ULONG - returns a random number uniformly distributed over [0..MAXLONG]
|
|
|
|
--*/
|
|
|
|
{
|
|
*Seed = ((Multiplier * (*Seed)) + Increment) % Modulus;
|
|
return *Seed;
|
|
}
|
|
|
|
// from net\netlib\allocstr.c
|
|
|
|
LPSTR
|
|
NetpAllocAStrFromWStr (
|
|
IN LPCWSTR Unicode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Convert an UNICODE (zero terminated) string to the corresponding ASCII
|
|
string.
|
|
|
|
Arguments:
|
|
|
|
Unicode - Specifies the UNICODE zero terminated string to convert.
|
|
|
|
|
|
Return Value:
|
|
|
|
NULL - There was some error in the conversion.
|
|
|
|
Otherwise, it returns a pointer to the zero terminated ASCII string in
|
|
an allocated buffer. The buffer must be freed using NetApiBufferFree.
|
|
|
|
--*/
|
|
|
|
{
|
|
OEM_STRING AnsiString = {0};
|
|
UNICODE_STRING UnicodeString;
|
|
|
|
RtlInitUnicodeString( &UnicodeString, Unicode );
|
|
|
|
if(!NT_SUCCESS( RtlUnicodeStringToAnsiString( &AnsiString,
|
|
&UnicodeString,
|
|
TRUE))){
|
|
return NULL;
|
|
}
|
|
|
|
return AnsiString.Buffer;
|
|
|
|
} // NetpAllocAStrFromWStr
|
|
|
|
// from net\netlib\allocstr.c
|
|
|
|
LPWSTR
|
|
NetpAllocWStrFromAStr(
|
|
IN LPCSTR Ansi
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Convert an ASCII (zero terminated) string to the corresponding UNICODE
|
|
string.
|
|
|
|
Arguments:
|
|
|
|
Ansi - Specifies the ASCII zero terminated string to convert.
|
|
|
|
|
|
Return Value:
|
|
|
|
NULL - There was some error in the conversion.
|
|
|
|
Otherwise, it returns a pointer to the zero terminated UNICODE string in
|
|
an allocated buffer. The buffer must be freed using NetApiBufferFree.
|
|
|
|
--*/
|
|
|
|
{
|
|
OEM_STRING AnsiString;
|
|
UNICODE_STRING UnicodeString = {0};
|
|
|
|
RtlInitString( &AnsiString, Ansi );
|
|
|
|
if(!NT_SUCCESS( RtlAnsiStringToUnicodeString( &UnicodeString,
|
|
&AnsiString,
|
|
TRUE))){
|
|
return NULL;
|
|
}
|
|
|
|
return UnicodeString.Buffer;
|
|
|
|
} // NetpAllocWStrFromAStr
|
|
|
|
LPWSTR
|
|
NetpAllocWStrFromOemStr(
|
|
IN LPCSTR Oem
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Convert an OEM (zero terminated) string to the corresponding UNICODE
|
|
string.
|
|
|
|
Arguments:
|
|
|
|
Oem - Specifies the OEM zero terminated string to convert.
|
|
|
|
|
|
Return Value:
|
|
|
|
NULL - There was some error in the conversion.
|
|
|
|
Otherwise, it returns a pointer to the zero terminated UNICODE string in
|
|
an allocated buffer. The buffer must be freed using NetApiBufferFree.
|
|
|
|
--*/
|
|
|
|
{
|
|
OEM_STRING OemString;
|
|
UNICODE_STRING UnicodeString = {0};
|
|
|
|
RtlInitString( &OemString, Oem );
|
|
|
|
if(!NT_SUCCESS( RtlOemStringToUnicodeString( &UnicodeString,
|
|
&OemString,
|
|
TRUE))){
|
|
return NULL;
|
|
}
|
|
|
|
return UnicodeString.Buffer;
|
|
|
|
} // NetpAllocWStrFromOemStr
|
|
|
|
// from net\netlib\allocstr.c
|
|
|
|
LPWSTR
|
|
NetpAllocWStrFromWStr(
|
|
IN LPWSTR Unicode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate and copy unicode string (wide character strdup)
|
|
|
|
Arguments:
|
|
|
|
Unicode - pointer to wide character string to make copy of
|
|
|
|
|
|
Return Value:
|
|
|
|
NULL - There was some error in the conversion.
|
|
|
|
Otherwise, it returns a pointer to the zero terminated UNICODE string in
|
|
an allocated buffer. The buffer must be freed using NetApiBufferFree.
|
|
|
|
--*/
|
|
|
|
{
|
|
NET_API_STATUS status;
|
|
DWORD size;
|
|
LPWSTR ptr;
|
|
|
|
size = wcslen(Unicode);
|
|
size = (size + 1) * sizeof (WCHAR);
|
|
status = NetApiBufferAllocate(size, (LPVOID *) (LPVOID) &ptr);
|
|
if (status != NO_ERROR) {
|
|
return NULL;
|
|
}
|
|
RtlCopyMemory(ptr, Unicode, size);
|
|
return ptr;
|
|
} // NetpAllocWStrFromWStr
|
|
|
|
NET_API_STATUS
|
|
NetpGetDomainNameExEx (
|
|
OUT LPWSTR *DomainNamePtr,
|
|
OUT LPWSTR *DnsDomainNamePtr OPTIONAL,
|
|
OUT PBOOLEAN IsworkgroupName
|
|
)
|
|
{
|
|
NET_API_STATUS NetStatus = NO_ERROR;
|
|
return NetStatus;
|
|
}
|
|
|
|
// from net\api\canonapi.c
|
|
NET_API_STATUS
|
|
NET_API_FUNCTION
|
|
NetpNameCanonicalize(
|
|
IN LPWSTR ServerName OPTIONAL,
|
|
IN LPWSTR Name,
|
|
OUT LPWSTR Outbuf,
|
|
IN DWORD OutbufLen,
|
|
IN DWORD NameType,
|
|
IN DWORD Flags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Canonicalizes a name
|
|
|
|
Arguments:
|
|
|
|
ServerName - where to run this API
|
|
Name - name to canonicalize
|
|
Outbuf - where to put canonicalized name
|
|
OutbufLen - length of Outbuf
|
|
NameType - type of name to canonicalize
|
|
Flags - control flags
|
|
|
|
Return Value:
|
|
|
|
NET_API_STATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
NET_API_STATUS status = 0;
|
|
DWORD location;
|
|
WCHAR serverName[MAX_PATH];
|
|
DWORD val;
|
|
WCHAR ch;
|
|
|
|
//
|
|
// validate parameters
|
|
//
|
|
|
|
try {
|
|
if (ARGUMENT_PRESENT(ServerName)) {
|
|
// val = STRLEN(ServerName);
|
|
val = wcslen(ServerName);
|
|
}
|
|
if (ARGUMENT_PRESENT(Name)) {
|
|
// val = STRLEN(Name);
|
|
val = wcslen(Name);
|
|
}
|
|
if (ARGUMENT_PRESENT(Outbuf)) {
|
|
ch = (volatile WCHAR)*Outbuf;
|
|
*Outbuf = ch;
|
|
ch = (volatile WCHAR)*(Outbuf + OutbufLen/sizeof(*Outbuf) - sizeof(*Outbuf));
|
|
*(Outbuf + OutbufLen/sizeof(*Outbuf) - sizeof(*Outbuf)) = ch;
|
|
} else {
|
|
status = ERROR_INVALID_PARAMETER;
|
|
}
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
status = ERROR_INVALID_PARAMETER;
|
|
}
|
|
if (status) {
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// call client-side RPC routine or local canonicalization routine
|
|
//
|
|
|
|
return NetpwNameCanonicalize(Name, Outbuf, OutbufLen, NameType, Flags);
|
|
// return NetpwNameValidate(Name, NameType, 0);
|
|
}
|
|
|
|
// from net\netlib\names.c
|
|
BOOL
|
|
NetpIsDomainNameValid(
|
|
IN LPWSTR DomainName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
NetpIsDomainNameValid checks for "domain" format.
|
|
The name is only checked syntactically; no attempt is made to determine
|
|
whether or not a domain with that name actually exists.
|
|
|
|
Arguments:
|
|
|
|
DomainName - Supplies an alleged Domain name.
|
|
|
|
Return Value:
|
|
|
|
BOOL - TRUE if name is syntactically valid, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
NET_API_STATUS ApiStatus = NO_ERROR;
|
|
WCHAR CanonBuf[DNLEN+1];
|
|
|
|
if (DomainName == (LPWSTR) NULL) {
|
|
return (FALSE);
|
|
}
|
|
if ( (*DomainName) == TCHAR_EOS ) {
|
|
return (FALSE);
|
|
}
|
|
|
|
ApiStatus = NetpNameCanonicalize(
|
|
NULL, // no server name
|
|
DomainName, // name to validate
|
|
CanonBuf, // output buffer
|
|
(DNLEN+1) * sizeof(WCHAR), // output buffer size
|
|
NAMETYPE_DOMAIN, // type
|
|
0 ); // flags: none
|
|
|
|
return (ApiStatus == NO_ERROR);
|
|
|
|
} // NetpIsDomainNameValid
|
|
|
|
VOID
|
|
MyRtlFreeAnsiString(
|
|
IN OUT PANSI_STRING AnsiString
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API is used to free storage allocated by
|
|
RtlUnicodeStringToAnsiString. Note that only AnsiString->Buffer
|
|
is free'd by this routine.
|
|
|
|
Arguments:
|
|
|
|
AnsiString - Supplies the address of the ansi string whose buffer
|
|
was previously allocated by RtlUnicodeStringToAnsiString.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (AnsiString->Buffer) {
|
|
LocalFree(AnsiString->Buffer);
|
|
ZeroMemory( AnsiString, sizeof( *AnsiString ) );
|
|
}
|
|
}
|
|
|
|
VOID
|
|
MyRtlFreeOemString(
|
|
IN OUT POEM_STRING OemString
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API is used to free storage allocated by
|
|
RtlUnicodeStringToOemString. Note that only OemString->Buffer
|
|
is free'd by this routine.
|
|
|
|
Arguments:
|
|
|
|
OemString - Supplies the address of the oem string whose buffer
|
|
was previously allocated by RtlUnicodeStringToOemString.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (OemString->Buffer) {
|
|
LocalFree(OemString->Buffer);
|
|
ZeroMemory( OemString, sizeof( *OemString ) );
|
|
}
|
|
}
|
|
|
|
VOID
|
|
MyRtlFreeUnicodeString(
|
|
IN OUT PUNICODE_STRING UnicodeString
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API is used to free storage allocated by
|
|
RtlAnsiStringToUnicodeString. Note that only UnicodeString->Buffer
|
|
is free'd by this routine.
|
|
|
|
Arguments:
|
|
|
|
UnicodeString - Supplies the address of the unicode string whose
|
|
buffer was previously allocated by RtlAnsiStringToUnicodeString.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
if (UnicodeString->Buffer) {
|
|
LocalFree(UnicodeString->Buffer);
|
|
ZeroMemory( UnicodeString, sizeof( *UnicodeString ) );
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
MyUniToUpper(WCHAR *dest, WCHAR *src, DWORD len)
|
|
{
|
|
WCHAR *wcp = dest;
|
|
|
|
while (*src != L'\0') {
|
|
*wcp++ = towupper(*src);
|
|
src++;
|
|
}
|
|
|
|
return(wcp - dest);
|
|
}
|
|
|
|
NTSTATUS
|
|
MyRtlUpcaseUnicodeToOemN(
|
|
IN PUNICODE_STRING SourceUnicodeString,
|
|
OUT POEM_STRING DestinationOemString )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This functions upper cases the specified unicode source string and
|
|
converts it into an oem string. The translation is done with respect
|
|
to the OEM Code Page (OCP) loaded at boot time. The resulting oem
|
|
string is allocated by this routine and should be deallocated using
|
|
MyRtlFreeOemString.
|
|
|
|
This function mimics the behavior of RtlUpcaseUnicodeToOemN. It first
|
|
converts the supplied unicode string into the oem string and then
|
|
converts the oem string back to a unicode string. This is done because
|
|
two different unicode strings may be converted into one oem string, but
|
|
converting back to unicode will create the right unicode string according
|
|
to the OEM Code Page (OCP) loaded at boot time. The resulting unicode
|
|
string is uppercased and then converted to the oem string returned to the
|
|
caller.
|
|
|
|
Arguments:
|
|
|
|
SourceUnicodeString - Supplies the unicode source string that is to be
|
|
converted to oem.
|
|
|
|
DestinationOemString - Returns an oem string that is equivalent to the
|
|
upper case of the unicode source string. If the translation can not
|
|
be done, an error is returned.
|
|
|
|
Return Value:
|
|
|
|
SUCCESS - The conversion was successful
|
|
Otherwise, an error is returned
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
OEM_STRING TmpOemString;
|
|
UNICODE_STRING TmpUnicodeString;
|
|
|
|
//
|
|
// Initialization
|
|
//
|
|
|
|
TmpOemString.Buffer = NULL;
|
|
TmpUnicodeString.Buffer = NULL;
|
|
|
|
|
|
//
|
|
// First convert the source unicode string into a
|
|
// temprary oem string
|
|
//
|
|
|
|
Status = MyRtlUnicodeStringToOemString( &TmpOemString,
|
|
SourceUnicodeString,
|
|
TRUE );
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Then convert the resulting oem string back to unicode
|
|
//
|
|
|
|
Status = MyRtlOemStringToUnicodeString( &TmpUnicodeString,
|
|
&TmpOemString,
|
|
TRUE );
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Now uppercase the resulting unicode string in place
|
|
//
|
|
|
|
MyUniToUpper( TmpUnicodeString.Buffer, TmpUnicodeString.Buffer, TmpUnicodeString.Length );
|
|
|
|
//
|
|
// Finally, convert the unicode string into the resulting oem string
|
|
//
|
|
|
|
Status = MyRtlUnicodeStringToOemString( DestinationOemString,
|
|
&TmpUnicodeString,
|
|
TRUE );
|
|
|
|
Cleanup:
|
|
|
|
MyRtlFreeOemString( &TmpOemString );
|
|
MyRtlFreeUnicodeString( &TmpUnicodeString );
|
|
|
|
return Status;
|
|
}
|
|
|
|
LPSTR
|
|
MyNetpLogonUnicodeToOem(
|
|
IN LPWSTR Unicode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Convert an UNICODE (zero terminated) string to the corresponding
|
|
uppercased oem string.
|
|
|
|
Arguments:
|
|
|
|
Unicode - Specifies the UNICODE zero terminated string to convert.
|
|
|
|
|
|
Return Value:
|
|
|
|
NULL - There was some error in the conversion.
|
|
|
|
Otherwise, it returns a pointer to the zero terminated uppercased
|
|
oem string in an allocated buffer. The buffer can be freed using
|
|
NetpMemoryFree.
|
|
|
|
--*/
|
|
|
|
{
|
|
OEM_STRING OemString;
|
|
UNICODE_STRING UnicodeString;
|
|
NTSTATUS Status;
|
|
|
|
MyRtlInitUnicodeString( &UnicodeString, Unicode );
|
|
|
|
Status = MyRtlUpcaseUnicodeToOemN( &UnicodeString, &OemString);
|
|
|
|
if( NT_SUCCESS(Status) ) {
|
|
return OemString.Buffer;
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
LONG
|
|
NlpChcg_wcsicmp(
|
|
IN LPCWSTR string1,
|
|
IN LPCWSTR string2
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Perform case insensitive, locale independent comparison of two
|
|
unicode strings. This matches the behavior of _wcsicmp that is
|
|
broken on Win9x because it has no unicode support.
|
|
|
|
Arguments:
|
|
|
|
string1, string2 - Specifies the UNICODE zero terminated strings to compare.
|
|
|
|
|
|
Return Value:
|
|
|
|
0 if the strings are equal
|
|
-1 if string1 is less than string2
|
|
1 if string1 is greater than string2
|
|
|
|
--*/
|
|
|
|
{
|
|
int cc;
|
|
LPSTR AString1 = NULL;
|
|
LPSTR AString2 = NULL;
|
|
|
|
AString1 = NetpAllocAStrFromWStr( string1 );
|
|
if ( AString1 == NULL ) {
|
|
cc = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
AString2 = NetpAllocAStrFromWStr( string2 );
|
|
if ( AString2 == NULL ) {
|
|
cc = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
cc = CompareStringA( 0, // deliberately NOT locale sensitive
|
|
NORM_IGNORECASE | NORM_IGNOREWIDTH | NORM_IGNOREKANATYPE | SORT_STRINGSORT,
|
|
(LPCSTR) AString1, -1,
|
|
(LPCSTR) AString2, -1 );
|
|
|
|
Cleanup:
|
|
|
|
if ( AString1 != NULL ) {
|
|
NetApiBufferFree( AString1 );
|
|
}
|
|
|
|
if ( AString2 != NULL ) {
|
|
NetApiBufferFree( AString2 );
|
|
}
|
|
|
|
switch ( cc ) {
|
|
case ERROR_NOT_ENOUGH_MEMORY:
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
case CSTR_EQUAL:
|
|
return 0;
|
|
case CSTR_LESS_THAN:
|
|
return -1;
|
|
case CSTR_GREATER_THAN:
|
|
return 1;
|
|
case 0:
|
|
NlPrint(( NL_CRITICAL, "Cannot CompareStringW: 0x%lx\n", GetLastError() ));
|
|
default:
|
|
return _NLSCMPERROR;
|
|
}
|
|
}
|
|
|
|
|