2652 lines
70 KiB
C
2652 lines
70 KiB
C
/*++
|
||
|
||
Copyright (c) 1997-1998 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
utils.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the code to process OS Chooser message
|
||
for the BINL server.
|
||
|
||
Author:
|
||
|
||
Adam Barr (adamba) 9-Jul-1997
|
||
Geoff Pease (gpease) 10-Nov-1997
|
||
|
||
Environment:
|
||
|
||
User Mode - Win32
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "binl.h"
|
||
#pragma hdrstop
|
||
|
||
//
|
||
// When all else fails "Error screen".
|
||
//
|
||
CHAR ErrorScreenHeaders[] =
|
||
"<OSCML>"\
|
||
"<META KEY=F3 ACTION=\"REBOOT\">"
|
||
"<META KEY=ENTER ACTION=\"REBOOT\">"
|
||
"<TITLE> Client Installation Wizard Error "; // there is a %08x after this
|
||
CHAR ErrorScreenBody[] =
|
||
" </TITLE>"
|
||
"<FOOTER> Press F3 to reboot</FOOTER>"
|
||
"<BODY LEFT=3 RIGHT=76><BR><BR>"; // the error message is inserted here
|
||
CHAR ErrorScreenTrailer[] =
|
||
"An error occurred on the server. Please notify your administrator.<BR>"
|
||
"%SUBERROR%<BR>"
|
||
"</BODY>"
|
||
"</OSCML>";
|
||
|
||
void
|
||
OscCreateWin32SubError(
|
||
PCLIENT_STATE clientState,
|
||
DWORD Error )
|
||
/*++
|
||
Routine Description:
|
||
|
||
Create a OSC Variable SUBERROR with the actual Win32 error code that
|
||
caused the BINL error.
|
||
|
||
Arguments:
|
||
|
||
clientState - client state to add the variable too.
|
||
|
||
Error - the Win32 error that occurred.
|
||
--*/
|
||
{
|
||
DWORD dwLen;
|
||
PWCHAR ErrorResponse = NULL;
|
||
PWCHAR ErrorMsg = NULL;
|
||
BOOL UsedFallback = FALSE;
|
||
PWCHAR pch;
|
||
DWORD ErrorLength;
|
||
|
||
const WCHAR UnknownErrorMsg[] = L"Unknown Error.";
|
||
const WCHAR ErrorString[] = L"Error: 0x%08x - %s";
|
||
|
||
TraceFunc( "OscCreateWin32SubError( )\n" );
|
||
|
||
// Retrieve the error message from system resources.
|
||
dwLen = FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||
FORMAT_MESSAGE_IGNORE_INSERTS |
|
||
FORMAT_MESSAGE_FROM_HMODULE |
|
||
FORMAT_MESSAGE_FROM_SYSTEM,
|
||
NULL,
|
||
Error,
|
||
0,
|
||
(LPWSTR) &ErrorMsg,
|
||
0,
|
||
NULL );
|
||
if ( dwLen == 0 )
|
||
goto Cleanup;
|
||
|
||
#if DBG
|
||
if ( ErrorMsg )
|
||
DebugMemoryAdd( ErrorMsg, __FILE__, __LINE__, "BINL", LPTR, wcslen(ErrorMsg), "ErrorMsg" );
|
||
#endif
|
||
|
||
// If all else fails, just print an error code out.
|
||
if ( ErrorMsg == NULL ) {
|
||
UsedFallback = TRUE;
|
||
ErrorMsg = (PWCHAR) &UnknownErrorMsg;
|
||
dwLen = wcslen(ErrorMsg);
|
||
}
|
||
|
||
// The + 4 is the extra characters of the "%08x" of the generated error message.
|
||
ErrorLength = dwLen + sizeof( ErrorString ) + 4;
|
||
ErrorResponse = (PWCHAR) BinlAllocateMemory( ErrorLength * sizeof(WCHAR) );
|
||
if ( ErrorResponse == NULL ) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
wsprintf( ErrorResponse, ErrorString, Error, ErrorMsg );
|
||
|
||
// We need to go through the string and elminate any CRs or LFs that
|
||
// FormatMessageA() might have introduced.
|
||
pch = ErrorResponse;
|
||
while ( *pch )
|
||
{
|
||
if ( *pch == '\r' || * pch == '\n' )
|
||
*pch = 32; // change to space
|
||
|
||
pch++;
|
||
}
|
||
|
||
OscAddVariableW( clientState, "SUBERROR", ErrorResponse );
|
||
|
||
Cleanup:
|
||
if ( ErrorResponse )
|
||
BinlFreeMemory( ErrorResponse );
|
||
|
||
if ( ErrorMsg && !UsedFallback )
|
||
BinlFreeMemory( ErrorMsg );
|
||
}
|
||
|
||
void
|
||
OscCreateLDAPSubError(
|
||
PCLIENT_STATE clientState,
|
||
DWORD Error )
|
||
/*++
|
||
Routine Description:
|
||
|
||
Create a OSC Variable SUBERROR with the actual LDAP error code that
|
||
caused the BINL error.
|
||
|
||
Arguments:
|
||
|
||
clientState - client state to add the variable too.
|
||
|
||
Error - the LDAP error that occurred.
|
||
--*/
|
||
{
|
||
DWORD dwLen;
|
||
PWCHAR ErrorResponse = NULL;
|
||
DWORD ErrorLength;
|
||
|
||
const WCHAR LdapErrorMsg[] = L"LDAP Error: 0x%08x";
|
||
|
||
TraceFunc( "OscCreateLDAPSubError( )\n" );
|
||
|
||
// The + 13 is the "0x12345678 - " of the generated error message.
|
||
ErrorLength = wcslen(LdapErrorMsg) + 1 + 13;
|
||
ErrorResponse = (PWCHAR) BinlAllocateMemory( ErrorLength * sizeof(WCHAR) );
|
||
if ( ErrorResponse == NULL ) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
wsprintf( ErrorResponse, LdapErrorMsg, Error );
|
||
|
||
OscAddVariableW( clientState, "SUBERROR", ErrorResponse );
|
||
|
||
Cleanup:
|
||
if ( ErrorResponse )
|
||
BinlFreeMemory( ErrorResponse );
|
||
}
|
||
|
||
//
|
||
// This routine was stolen from private\ntos\rtl\sertl.c\RtlRunEncodeUnicodeString().
|
||
//
|
||
|
||
VOID
|
||
OscGenerateSeed(
|
||
UCHAR Seed[1]
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Generates a one-byte seed for use in run encoding/decoding client
|
||
state variables such as passwords.
|
||
|
||
Arguments:
|
||
|
||
Seed - points to a single byte that holds the generated seed.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
LARGE_INTEGER Time;
|
||
PUCHAR LocalSeed;
|
||
NTSTATUS Status;
|
||
ULONG i;
|
||
|
||
//
|
||
// Use the 2nd byte of current time as the seed.
|
||
// This byte seems to be sufficiently random (by observation).
|
||
//
|
||
|
||
Status = NtQuerySystemTime ( &Time );
|
||
BinlAssert(NT_SUCCESS(Status));
|
||
|
||
LocalSeed = (PUCHAR)((PVOID)&Time);
|
||
|
||
i = 1;
|
||
|
||
(*Seed) = LocalSeed[ i ];
|
||
|
||
//
|
||
// Occasionally, this byte could be zero. That would cause the
|
||
// string to become un-decodable, since 0 is the magic value that
|
||
// causes us to re-gen the seed. This loop makes sure that we
|
||
// never end up with a zero byte (unless time is zero, as well).
|
||
//
|
||
|
||
while ( ((*Seed) == 0) && ( i < sizeof( Time ) ) )
|
||
{
|
||
(*Seed) |= LocalSeed[ i++ ] ;
|
||
}
|
||
|
||
if ( (*Seed) == 0 )
|
||
{
|
||
(*Seed) = 1;
|
||
}
|
||
}
|
||
|
||
DWORD
|
||
OscRunEncode(
|
||
IN PCLIENT_STATE ClientState,
|
||
IN LPSTR Data,
|
||
OUT LPSTR * EncodedData
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Calls RtlRunEncodeUnicodeString for the Data, using the client
|
||
state's random seed. Then convert each byte into a 2-byte
|
||
value so that there are no NULLs in the result.
|
||
|
||
Each byte is encoded into a 2-byte values as follows:
|
||
The first byte has the low 4 bits of the byte in its low 4 bits,
|
||
with 0xf in the high 4 bits
|
||
The second byte has the high 4 bits of the byte in its high 4 bits,
|
||
with 0xf in the low 4 bits
|
||
|
||
Arguments:
|
||
|
||
ClientState - the client state.
|
||
|
||
Data - The data which is to be encoded.
|
||
|
||
EncodedData - An allocated buffer which holds the encoded result.
|
||
|
||
Return Value:
|
||
|
||
The result of the operation.
|
||
|
||
--*/
|
||
{
|
||
STRING String;
|
||
ULONG i;
|
||
LPSTR p;
|
||
|
||
RtlInitAnsiString(&String, Data);
|
||
|
||
*EncodedData = BinlAllocateMemory((String.Length * 2) + 1);
|
||
if (*EncodedData == NULL) {
|
||
return ERROR_NOT_ENOUGH_SERVER_MEMORY;
|
||
}
|
||
|
||
RtlRunEncodeUnicodeString(&ClientState->Seed, (PUNICODE_STRING)&String);
|
||
|
||
for (i = 0, p = *EncodedData; i < String.Length; i++) {
|
||
*(p++) = Data[i] | 0xf0;
|
||
*(p++) = Data[i] | 0x0f;
|
||
}
|
||
*p = '\0';
|
||
|
||
return ERROR_SUCCESS;
|
||
|
||
}
|
||
|
||
DWORD
|
||
OscRunDecode(
|
||
IN PCLIENT_STATE ClientState,
|
||
IN LPSTR EncodedData,
|
||
OUT LPSTR * Data
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Convert the encoded data (see OscRunEncode) into the real bytes,
|
||
then calls RtlRunDecodeUnicodeString on that, using the client
|
||
state's random seed.
|
||
|
||
Arguments:
|
||
|
||
ClientState - the client state.
|
||
|
||
EncodedData - the encoded data from OscRunEncode.
|
||
|
||
Data - An allocated buffer which holds the decoded result.
|
||
|
||
Return Value:
|
||
|
||
The result of the operation.
|
||
|
||
--*/
|
||
{
|
||
STRING String;
|
||
ULONG Count = strlen(EncodedData) / 2;
|
||
ULONG i, j;
|
||
LPSTR p;
|
||
|
||
*Data = BinlAllocateMemory(Count + 1);
|
||
if (*Data == NULL) {
|
||
return ERROR_NOT_ENOUGH_SERVER_MEMORY;
|
||
}
|
||
|
||
for (i = 0, j = 0, p = *Data; i < Count; i++, j+=2) {
|
||
*(p++) = (EncodedData[j] & 0x0f) | (EncodedData[j+1] & 0xf0);
|
||
}
|
||
*p = '\0';
|
||
|
||
//
|
||
// Set up the string ourselves since there may be NULLs in
|
||
// the decoded data.
|
||
//
|
||
|
||
String.Buffer = *Data;
|
||
String.Length = (USHORT)Count;
|
||
String.MaximumLength = (USHORT)(Count+1);
|
||
|
||
RtlRunDecodeUnicodeString(ClientState->Seed, (PUNICODE_STRING)&String);
|
||
|
||
return ERROR_SUCCESS;
|
||
}
|
||
|
||
//
|
||
// This routine was stolen from net\svcdlls\logonsrv\server\ssiauth.c.
|
||
//
|
||
|
||
BOOLEAN
|
||
OscGenerateRandomBits(
|
||
PUCHAR Buffer,
|
||
ULONG BufferLen
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Generates random bits
|
||
|
||
Arguments:
|
||
|
||
pBuffer - Buffer to fill
|
||
|
||
cbBuffer - Number of bytes in buffer
|
||
|
||
Return Value:
|
||
|
||
Status of the operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
BOOL Status = TRUE;
|
||
HCRYPTPROV CryptProvider = 0;
|
||
|
||
Status = CryptAcquireContext( &CryptProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT );
|
||
|
||
if ( Status ) {
|
||
|
||
Status = CryptGenRandom( CryptProvider, BufferLen, ( LPBYTE )Buffer );
|
||
|
||
CryptReleaseContext( CryptProvider, 0 );
|
||
|
||
} else {
|
||
|
||
BinlPrintDbg((DEBUG_ERRORS, "CryptAcquireContext failed with %lu\n", GetLastError() ));
|
||
|
||
}
|
||
|
||
return ( Status != 0);
|
||
}
|
||
|
||
VOID
|
||
OscGeneratePassword(
|
||
OUT PWCHAR Password,
|
||
OUT PULONG PasswordLength
|
||
)
|
||
{
|
||
ULONG i;
|
||
|
||
*PasswordLength = LM20_PWLEN * sizeof(WCHAR);
|
||
|
||
for (i = 0; i < LM20_PWLEN; i++) {
|
||
|
||
if ( Password[i] == L'\0' ) {
|
||
Password[i] = 0x55;
|
||
} else if ((USHORT)Password[i] < 0x20 || (USHORT)Password[i] > 0x7A) {
|
||
Password[i] = Password[i] % (0x7a-0x20) + 0x20;
|
||
}
|
||
}
|
||
Password[LM20_PWLEN] = L'\0';
|
||
}
|
||
|
||
//
|
||
// GenerateErrorScreen( )
|
||
//
|
||
DWORD
|
||
GenerateErrorScreen(
|
||
PCHAR *OutMessage,
|
||
PULONG OutMessageLength,
|
||
DWORD Error,
|
||
PCLIENT_STATE clientState
|
||
)
|
||
{
|
||
DWORD Err;
|
||
DWORD dwLen;
|
||
PCHAR ErrorMsg;
|
||
DWORD ErrorScreenLength = strlen(ErrorScreenHeaders) + strlen(ErrorScreenBody) + strlen(ErrorScreenTrailer);
|
||
PCHAR pch;
|
||
PCHAR RspMessage = NULL;
|
||
ULONG RspMessageLength = 0;
|
||
|
||
const CHAR UnknownErrorMsg[] = "Unknown Error.";
|
||
|
||
TCHAR ErrorMsgFilename[ MAX_PATH ];
|
||
HANDLE hfile;
|
||
|
||
LPSTR Messages[5];
|
||
|
||
Messages[0] = OscFindVariableA( clientState, "USERNAME" );
|
||
Messages[1] = OscFindVariableA( clientState, "USERDOMAIN" );
|
||
Messages[2] = OscFindVariableA( clientState, "MACHINENAME" );
|
||
Messages[3] = OscFindVariableA( clientState, "SUBERROR" );
|
||
Messages[4] = NULL; // paranoid
|
||
|
||
if ( _snwprintf( ErrorMsgFilename,
|
||
sizeof(ErrorMsgFilename) / sizeof(ErrorMsgFilename[0]),
|
||
L"%ws\\OSChooser\\%ws\\%08x.OSC",
|
||
IntelliMirrorPathW,
|
||
OscFindVariableW( clientState, "LANGUAGE" ),
|
||
Error ) != -1 ) {
|
||
|
||
//
|
||
// If we find the file, load it into memory.
|
||
//
|
||
hfile = CreateFile( ErrorMsgFilename, GENERIC_READ,
|
||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
|
||
if ( hfile != INVALID_HANDLE_VALUE )
|
||
{
|
||
DWORD FileSize;
|
||
//
|
||
// Find out how big this screen is, if bigger than 0xFFFFFFFF we won't
|
||
// display it.
|
||
//
|
||
FileSize = GetFileSize( hfile, NULL );
|
||
if ( FileSize != 0xFFFFffff )
|
||
{
|
||
DWORD dwRead = 0;
|
||
|
||
RspMessage = BinlAllocateMemory( FileSize + 3 );
|
||
if ( RspMessage == NULL )
|
||
{
|
||
//
|
||
// Ignore error and fall thru to generate an error screen
|
||
//
|
||
}
|
||
else
|
||
{
|
||
RspMessageLength = 0;
|
||
RspMessage[0] = '\0';
|
||
|
||
while ( dwRead != FileSize )
|
||
{
|
||
BOOL b;
|
||
DWORD dw;
|
||
b = ReadFile( hfile, &RspMessage[dwRead], FileSize - dwRead, &dw, NULL );
|
||
if (!b)
|
||
{
|
||
PWCHAR strings[2];
|
||
strings[0] = ErrorMsgFilename;
|
||
strings[1] = NULL;
|
||
Err = GetLastError( );
|
||
|
||
BinlPrint(( DEBUG_OSC_ERROR, "Error reading screen file: Seek=%u, Size=%u, File=%ws\n",
|
||
dwRead, FileSize - dwRead, ErrorMsgFilename ));
|
||
|
||
BinlReportEventW( EVENT_ERROR_READING_OSC_SCREEN,
|
||
EVENTLOG_ERROR_TYPE,
|
||
1,
|
||
sizeof(Err),
|
||
strings,
|
||
&Err
|
||
);
|
||
break;
|
||
}
|
||
dwRead += dw;
|
||
}
|
||
|
||
RspMessageLength = dwRead;
|
||
RspMessage[dwRead] = '\0'; // paranoid
|
||
|
||
CloseHandle( hfile );
|
||
|
||
Err = ERROR_SUCCESS;
|
||
goto Cleanup;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
BinlPrintDbg((DEBUG_OSC_ERROR, "!!Error 0x%08x - Could not determine file size.\n", GetLastError( )));
|
||
//
|
||
// Ignore error and fall thru to generate an error screen
|
||
//
|
||
}
|
||
|
||
CloseHandle( hfile );
|
||
}
|
||
|
||
}
|
||
|
||
BinlPrintDbg((DEBUG_OSC_ERROR, "no friendly OSC error screen available.\n" ));
|
||
//
|
||
// See if this is a BINL error or a system error and
|
||
// get the text from the error tables.
|
||
//
|
||
dwLen = FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||
FORMAT_MESSAGE_FROM_HMODULE |
|
||
FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
||
GetModuleHandle(L"BINLSVC.DLL"),
|
||
Error,
|
||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
||
(LPSTR) &ErrorMsg,
|
||
0,
|
||
(va_list*) &Messages );
|
||
if ( dwLen == 0 )
|
||
{
|
||
BinlAssert( ErrorMsg == NULL );
|
||
Err = GetLastError( );
|
||
BinlPrintDbg((DEBUG_OSC_ERROR, "!! Error 0x%08x - no BINLSVC specific message available.\n", Err ));
|
||
|
||
dwLen = FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||
FORMAT_MESSAGE_IGNORE_INSERTS |
|
||
FORMAT_MESSAGE_FROM_SYSTEM,
|
||
NULL,
|
||
Error,
|
||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
||
(LPSTR) &ErrorMsg,
|
||
0,
|
||
NULL );
|
||
if ( dwLen == 0 )
|
||
{
|
||
BinlAssert( ErrorMsg == NULL );
|
||
Err = GetLastError( );
|
||
BinlPrintDbg((DEBUG_OSC_ERROR, "!! Error 0x%08x - no SYSTEM specific message available.\n", Err ));
|
||
}
|
||
}
|
||
|
||
#if DBG
|
||
if ( ErrorMsg )
|
||
DebugMemoryAdd( ErrorMsg, __FILE__, __LINE__, "BINL", LPTR, lstrlenA(ErrorMsg), "ErrorMsg" );
|
||
#endif
|
||
|
||
//
|
||
// If all else fails, just print an error code.
|
||
//
|
||
if ( ErrorMsg == NULL ) {
|
||
BinlPrintDbg(( DEBUG_OSC_ERROR, "sending using generic error message.\n" ));
|
||
ErrorMsg = (PCHAR) &UnknownErrorMsg;
|
||
dwLen = strlen(ErrorMsg);
|
||
}
|
||
|
||
#define ERRORITEM "%s%08x%s<BR><BOLD>%s</BOLD><BR><BR>%s"
|
||
|
||
//
|
||
// The + 13 is the "0x12345678 - " of the generated error message.
|
||
//
|
||
RspMessageLength = ErrorScreenLength + strlen(ERRORITEM) + dwLen + 1 + 13;
|
||
RspMessage = (PCHAR) BinlAllocateMemory( RspMessageLength );
|
||
if ( RspMessage == NULL )
|
||
{
|
||
Err = ERROR_NOT_ENOUGH_SERVER_MEMORY;
|
||
goto Cleanup;
|
||
}
|
||
|
||
wsprintfA( RspMessage, ERRORITEM, ErrorScreenHeaders, Error, ErrorScreenBody, ErrorMsg, ErrorScreenTrailer );
|
||
|
||
Err = ERROR_SUCCESS;
|
||
|
||
Cleanup:
|
||
if ( Err == ERROR_SUCCESS )
|
||
{
|
||
// BinlPrint(( DEBUG_OSC, "Generated Error Response:\n%s\n", RspMessage ));
|
||
*OutMessage = RspMessage;
|
||
*OutMessageLength = RspMessageLength;
|
||
|
||
BinlReportEventA( EVENT_ERROR_SERVER_SIDE_ERROR,
|
||
EVENTLOG_ERROR_TYPE,
|
||
4,
|
||
sizeof(Error),
|
||
Messages,
|
||
&Error
|
||
);
|
||
}
|
||
else
|
||
{
|
||
BinlPrintDbg(( DEBUG_OSC_ERROR, "!! Error 0x%08x - Couldn't generate error screen.\n", Err ));
|
||
|
||
BinlReportEventA( EVENT_ERROR_GENERATING_SERVER_SIDE_ERROR,
|
||
EVENTLOG_ERROR_TYPE,
|
||
4,
|
||
sizeof(Err),
|
||
Messages,
|
||
&Err
|
||
);
|
||
|
||
*OutMessage = NULL;
|
||
*OutMessageLength = 0;
|
||
|
||
if ( RspMessage )
|
||
{
|
||
BinlFreeMemory( RspMessage );
|
||
}
|
||
}
|
||
|
||
return Err;
|
||
}
|
||
|
||
//
|
||
// Returns a pointer point to the next 'ch' or NULL character.
|
||
//
|
||
PCHAR
|
||
FindNext(
|
||
PCHAR Start,
|
||
CHAR ch,
|
||
PCHAR End
|
||
)
|
||
{
|
||
TraceFunc("FindNext( )\n");
|
||
|
||
while( Start != End && *Start && *Start !=ch )
|
||
Start++;
|
||
|
||
if ( Start != End && *Start ) {
|
||
return Start;
|
||
} else {
|
||
return NULL;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Finds the screen name.
|
||
//
|
||
PCHAR
|
||
FindScreenName(
|
||
PCHAR Screen
|
||
)
|
||
{
|
||
PCHAR Name;
|
||
TraceFunc("FindScreenName( )\n");
|
||
|
||
Name = strstr( Screen, "NAME" );
|
||
|
||
if ( Name == NULL )
|
||
return NULL;
|
||
|
||
Name += 5; // "Name" plus space
|
||
|
||
return Name;
|
||
}
|
||
|
||
DWORD
|
||
OscImpersonate(
|
||
IN PCLIENT_STATE ClientState
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Makes the current thread impersonate the client. It is assumed
|
||
that the client has already sent up a login screen. If this call
|
||
succeeds, ClientState->AuthenticatedDCLdapHandle is valid.
|
||
|
||
Arguments:
|
||
|
||
ClientState - The client state.
|
||
|
||
Return Value:
|
||
|
||
Windows Error.
|
||
|
||
--*/
|
||
{
|
||
DWORD Error = ERROR_SUCCESS;
|
||
LPSTR pUserName;
|
||
LPSTR pUserDomain;
|
||
LPSTR pUserPassword;
|
||
LPSTR pDecodedPassword = NULL;
|
||
LPSTR tempptr;
|
||
ULONG temp;
|
||
ULONG LdapError = 0;
|
||
SEC_WINNT_AUTH_IDENTITY_A authIdentity;
|
||
BOOL bResult;
|
||
BOOL Impersonating = FALSE;
|
||
LPWSTR pCrossDsDc;
|
||
|
||
TraceFunc( "OscImpersonate( ... )\n" );
|
||
|
||
pCrossDsDc = OscFindVariableW( ClientState, "DCNAME" );
|
||
if (*pCrossDsDc == L'\0') {
|
||
|
||
//
|
||
// Clean up any old client state.
|
||
//
|
||
|
||
if (ClientState->AuthenticatedDCLdapHandle &&
|
||
ClientState->UserToken) {
|
||
|
||
bResult = ImpersonateLoggedOnUser(ClientState->UserToken);
|
||
if (bResult) {
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
if (ClientState->AuthenticatedDCLdapHandle) {
|
||
// Reconnecting again. Use new credentials.
|
||
ldap_unbind(ClientState->AuthenticatedDCLdapHandle);
|
||
ClientState->AuthenticatedDCLdapHandle = NULL;
|
||
}
|
||
if (ClientState->UserToken) {
|
||
CloseHandle(ClientState->UserToken);
|
||
ClientState->UserToken = NULL;
|
||
}
|
||
|
||
//
|
||
// Get the login variables from the client state.
|
||
//
|
||
|
||
pUserName = OscFindVariableA( ClientState, "USERNAME" );
|
||
pUserDomain = OscFindVariableA( ClientState, "USERDOMAIN" );
|
||
pUserPassword = OscFindVariableA( ClientState, "*PASSWORD" );
|
||
|
||
if (pUserName[0] == '\0') {
|
||
OscAddVariableA( ClientState, "SUBERROR", "USERNAME" );
|
||
Error = ERROR_BINL_MISSING_VARIABLE;
|
||
goto ImpersonateFailed;
|
||
}
|
||
|
||
//
|
||
// Decode the password.
|
||
//
|
||
|
||
Error = OscRunDecode(ClientState, pUserPassword, &pDecodedPassword);
|
||
if (Error != ERROR_SUCCESS) {
|
||
goto ImpersonateFailed;
|
||
}
|
||
|
||
|
||
//
|
||
// if the user didn't enter a domain name, use the server's
|
||
//
|
||
|
||
if (pUserDomain == NULL || pUserDomain[0] == '\0') {
|
||
|
||
OscAddVariableW( ClientState, "USERDOMAIN", BinlGlobalOurDomainName );
|
||
|
||
pUserDomain = OscFindVariableA( ClientState, "USERDOMAIN" );
|
||
|
||
}
|
||
|
||
//
|
||
// Do a LogonUser with the credentials, since we
|
||
// need that to change the machine password (even the
|
||
// authenticated LDAP handle won't do that if we don't
|
||
// have 128-bit SSL setup on this machine).
|
||
//
|
||
|
||
bResult = LogonUserA(
|
||
pUserName,
|
||
pUserDomain,
|
||
pDecodedPassword,
|
||
LOGON32_LOGON_NETWORK_CLEARTEXT,
|
||
LOGON32_PROVIDER_DEFAULT,
|
||
&ClientState->UserToken);
|
||
|
||
if (!bResult) {
|
||
Error = GetLastError();
|
||
BinlPrintDbg(( DEBUG_ERRORS, "LogonUser failed %lx\n", Error));
|
||
ClientState->UserToken = NULL; // this may be set even on failure
|
||
goto ImpersonateFailed;
|
||
}
|
||
|
||
//
|
||
// if the user didn't enter a domain name, grab it out of the user token.
|
||
//
|
||
|
||
if (pUserDomain == NULL || pUserDomain[0] == '\0') {
|
||
|
||
PTOKEN_USER userToken;
|
||
DWORD tokenSize = 4096;
|
||
|
||
userToken = (PTOKEN_USER) BinlAllocateMemory( tokenSize );
|
||
|
||
if (userToken != NULL) {
|
||
|
||
DWORD returnLength;
|
||
BOOL bRC;
|
||
|
||
bRC = GetTokenInformation( ClientState->UserToken,
|
||
TokenUser,
|
||
(LPVOID) userToken,
|
||
tokenSize,
|
||
&returnLength
|
||
);
|
||
|
||
if (bRC) {
|
||
|
||
WCHAR uUser[128];
|
||
DWORD cUser = 128;
|
||
WCHAR uDomain[128];
|
||
DWORD cDomain = 128;
|
||
SID_NAME_USE peType;
|
||
|
||
uDomain[0] = L'\0';
|
||
uUser[0] = L'\0';
|
||
|
||
bRC = LookupAccountSidW( NULL, // system name
|
||
userToken->User.Sid,
|
||
uUser, // user name
|
||
&cUser, // user name count
|
||
uDomain, // domain name
|
||
&cDomain, // domain name count
|
||
&peType
|
||
);
|
||
|
||
if (bRC && uDomain[0] != L'\0') {
|
||
|
||
OscAddVariableW( ClientState, "USERDOMAIN", &uDomain[0] );
|
||
}
|
||
}
|
||
|
||
BinlFreeMemory( userToken );
|
||
}
|
||
}
|
||
|
||
//
|
||
// Now impersonate the user.
|
||
//
|
||
|
||
bResult = ImpersonateLoggedOnUser(ClientState->UserToken);
|
||
if (!bResult) {
|
||
BinlPrintDbg(( DEBUG_ERRORS,
|
||
"ImpersonateLoggedOnUser failed %x\n", GetLastError()));
|
||
Error = GetLastError();
|
||
goto ImpersonateFailed;
|
||
}
|
||
|
||
Impersonating = TRUE;
|
||
|
||
//
|
||
// Create authenticated DC connection for use in machine object creation
|
||
// or modification.
|
||
//
|
||
BinlPrintDbg(( DEBUG_OSC,
|
||
"ldap_init %S or %S\n", pCrossDsDc, BinlGlobalDefaultDS ));
|
||
|
||
ClientState->AuthenticatedDCLdapHandle = ldap_init(
|
||
(*pCrossDsDc != L'\0')
|
||
? pCrossDsDc
|
||
: BinlGlobalDefaultDS,
|
||
LDAP_PORT);
|
||
|
||
BinlPrintDbg(( DEBUG_OSC,
|
||
"ldap_init handle %x\n", ClientState->AuthenticatedDCLdapHandle ));
|
||
|
||
|
||
temp = DS_DIRECTORY_SERVICE_REQUIRED | DS_IP_REQUIRED;
|
||
ldap_set_option(ClientState->AuthenticatedDCLdapHandle, LDAP_OPT_GETDSNAME_FLAGS, &temp );
|
||
|
||
temp = LDAP_VERSION3;
|
||
ldap_set_option(ClientState->AuthenticatedDCLdapHandle, LDAP_OPT_VERSION, &temp );
|
||
|
||
//
|
||
// Tell LDAP to keep connections referenced after searches.
|
||
//
|
||
|
||
temp = (ULONG)((ULONG_PTR)LDAP_OPT_ON);
|
||
ldap_set_option(ClientState->AuthenticatedDCLdapHandle, LDAP_OPT_REF_DEREF_CONN_PER_MSG, &temp);
|
||
|
||
LdapError = ldap_connect(ClientState->AuthenticatedDCLdapHandle,0);
|
||
|
||
if (LdapError != LDAP_SUCCESS) {
|
||
BinlPrintDbg(( DEBUG_ERRORS,
|
||
"this ldap_connect() failed %x\n", LdapError));
|
||
goto ImpersonateFailed;
|
||
}
|
||
|
||
//
|
||
// LDAP_AUTH_NEGOTIATE tells it to use the credentials of the user
|
||
// we are impersonating.
|
||
//
|
||
|
||
LdapError = ldap_bind_sA(ClientState->AuthenticatedDCLdapHandle,
|
||
NULL,
|
||
NULL,
|
||
LDAP_AUTH_NEGOTIATE);
|
||
|
||
if (LdapError != LDAP_SUCCESS) {
|
||
BinlPrintDbg(( DEBUG_ERRORS,
|
||
"ldap_bind_s() failed %x\n", LdapError));
|
||
goto ImpersonateFailed;
|
||
}
|
||
|
||
ImpersonateFailed:
|
||
|
||
//
|
||
// If we decoded the password, then erase and free it.
|
||
//
|
||
|
||
if (pDecodedPassword != NULL) {
|
||
RtlZeroMemory(pDecodedPassword, strlen(pDecodedPassword));
|
||
BinlFreeMemory(pDecodedPassword);
|
||
}
|
||
|
||
if (LdapError != LDAP_SUCCESS) {
|
||
Error = LdapMapErrorToWin32(LdapError);
|
||
}
|
||
|
||
if (Error) {
|
||
PWCHAR strings[3];
|
||
strings[0] = OscFindVariableW( ClientState, "USERNAME" );
|
||
strings[1] = OscFindVariableW( ClientState, "USERDOMAIN" );
|
||
strings[2] = NULL;
|
||
|
||
BinlReportEventW( ERROR_BINL_ERR_USER_LOGIN_FAILED,
|
||
EVENTLOG_WARNING_TYPE,
|
||
2,
|
||
sizeof(ULONG),
|
||
strings,
|
||
&Error
|
||
);
|
||
|
||
if (ClientState->AuthenticatedDCLdapHandle) {
|
||
ldap_unbind(ClientState->AuthenticatedDCLdapHandle);
|
||
ClientState->AuthenticatedDCLdapHandle = NULL;
|
||
}
|
||
if (ClientState->UserToken) {
|
||
CloseHandle(ClientState->UserToken);
|
||
ClientState->UserToken = NULL;
|
||
}
|
||
if (Impersonating) {
|
||
RevertToSelf();
|
||
}
|
||
}
|
||
|
||
return Error;
|
||
}
|
||
|
||
DWORD
|
||
OscRevert(
|
||
IN PCLIENT_STATE ClientState
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Stops the current thread impersonating.
|
||
|
||
Arguments:
|
||
|
||
ClientState - The client state.
|
||
|
||
Return Value:
|
||
|
||
Windows Error.
|
||
|
||
--*/
|
||
{
|
||
DWORD Error = ERROR_SUCCESS;
|
||
BOOL bResult;
|
||
|
||
TraceFunc( "OscRevert( ... )\n" );
|
||
|
||
//
|
||
// We are done impersonating for the moment.
|
||
//
|
||
|
||
bResult = RevertToSelf();
|
||
if (!bResult) {
|
||
BinlPrintDbg(( DEBUG_ERRORS,
|
||
"RevertToSelf failed %x\n", GetLastError()));
|
||
Error = GetLastError();
|
||
}
|
||
|
||
// keep the ldap handle around in case we need it again.
|
||
|
||
// if (ClientState->AuthenticatedDCLdapHandle) {
|
||
// ldap_unbind(ClientState->AuthenticatedDCLdapHandle);
|
||
// ClientState->AuthenticatedDCLdapHandle = NULL;
|
||
// }
|
||
// if (ClientState->UserToken) {
|
||
// CloseHandle(ClientState->UserToken);
|
||
// ClientState->UserToken = NULL;
|
||
// }
|
||
|
||
return Error;
|
||
|
||
}
|
||
|
||
//
|
||
// OscGuidToBytes( )
|
||
//
|
||
// Change CHAR Guid to bytes
|
||
//
|
||
DWORD
|
||
OscGuidToBytes(
|
||
LPSTR pszGuid,
|
||
LPBYTE Guid )
|
||
{
|
||
PCHAR psz;
|
||
ULONG len;
|
||
ULONG i;
|
||
|
||
TraceFunc( "OscGuidToBytes( ... )\n" );
|
||
|
||
len = strlen(pszGuid);
|
||
BinlAssert( len == 32 );
|
||
if ( len != 32 )
|
||
return ERROR_BINL_INVALID_GUID;
|
||
|
||
psz = pszGuid;
|
||
i = 0;
|
||
while ( i * 2 < 32 )
|
||
{
|
||
//
|
||
// Upper 4-bits
|
||
//
|
||
CHAR c = *psz;
|
||
psz++;
|
||
Guid[i] = ( c > 59 ? (toupper(c) - 55) << 4 : (c - 48) << 4);
|
||
|
||
//
|
||
// Lower 4-bits
|
||
//
|
||
c = *psz;
|
||
psz++;
|
||
Guid[i] += ( c > 59 ? (toupper(c) - 55) : (c - 48) );
|
||
|
||
//
|
||
// Next byte
|
||
//
|
||
i++;
|
||
}
|
||
|
||
return ERROR_SUCCESS;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
OscSifIsSysPrep(
|
||
LPWSTR pSysPrepSifPath
|
||
)
|
||
{
|
||
DWORD dwErr;
|
||
WCHAR Buffer[256];
|
||
UNICODE_STRING UnicodeString;
|
||
|
||
TraceFunc("OscSifIsSysPrep( )\n");
|
||
|
||
Buffer[0] = UNICODE_NULL;
|
||
GetPrivateProfileString(OSCHOOSER_SIF_SECTIONW,
|
||
L"ImageType",
|
||
Buffer, // default
|
||
Buffer,
|
||
256,
|
||
pSysPrepSifPath
|
||
);
|
||
|
||
RtlInitUnicodeString(&UnicodeString, Buffer);
|
||
RtlUpcaseUnicodeString(&UnicodeString, &UnicodeString, FALSE);
|
||
|
||
if (_wcsicmp(L"SYSPREP", Buffer)) {
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
OscSifIsCmdConsA(
|
||
PCHAR pSifPath
|
||
)
|
||
{
|
||
DWORD dwErr;
|
||
CHAR Buffer[256];
|
||
|
||
TraceFunc("OscSifIsCmdCons( )\n");
|
||
|
||
Buffer[0] = UNICODE_NULL;
|
||
GetPrivateProfileStringA(OSCHOOSER_SIF_SECTIONA,
|
||
"ImageType",
|
||
Buffer, // default
|
||
Buffer,
|
||
256,
|
||
pSifPath
|
||
);
|
||
|
||
if (_stricmp("CMDCONS", Buffer)) {
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
OscSifIsASR(
|
||
PCHAR pSifPath
|
||
)
|
||
{
|
||
DWORD dwErr;
|
||
CHAR Buffer[256];
|
||
|
||
TraceFunc("OscSifIsASR( )\n");
|
||
|
||
Buffer[0] = UNICODE_NULL;
|
||
GetPrivateProfileStringA(OSCHOOSER_SIF_SECTIONA,
|
||
"ImageType",
|
||
Buffer, // default
|
||
Buffer,
|
||
256,
|
||
pSifPath
|
||
);
|
||
|
||
if (_stricmp("ASR", Buffer)) {
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
DWORD
|
||
OscGetSkuType(
|
||
PWSTR PathToTxtSetupSif
|
||
)
|
||
{
|
||
PWSTR SifFile;
|
||
DWORD SkuType = 0;
|
||
|
||
SifFile = BinlAllocateMemory(
|
||
(wcslen(PathToTxtSetupSif) +
|
||
1 +
|
||
wcslen(L"txtsetup.sif") +
|
||
1 ) * sizeof(WCHAR));
|
||
|
||
if (!SifFile) {
|
||
return 0; //default to professional on failure
|
||
}
|
||
|
||
wcscpy(SifFile, PathToTxtSetupSif);
|
||
if (SifFile[wcslen(SifFile)-1] == L'\\') {
|
||
wcscat( SifFile, L"txtsetup.sif" );
|
||
} else {
|
||
wcscat( SifFile, L"\\txtsetup.sif" );
|
||
}
|
||
|
||
SkuType = GetPrivateProfileInt(
|
||
L"SetupData",
|
||
L"ProductType",
|
||
0,
|
||
SifFile );
|
||
|
||
BinlFreeMemory( SifFile );
|
||
|
||
return (SkuType);
|
||
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
OscGetClosestNt(
|
||
IN LPWSTR PathToKernel,
|
||
IN DWORD SkuType,
|
||
IN PCLIENT_STATE ClientState,
|
||
OUT LPWSTR SetupPath,
|
||
OUT PBOOLEAN ExactMatch
|
||
)
|
||
{
|
||
DWORD Error = ERROR_SUCCESS;
|
||
WIN32_FIND_DATA FindData;
|
||
HANDLE hFind = INVALID_HANDLE_VALUE;
|
||
BOOLEAN Impersonated = FALSE;
|
||
WCHAR Path[MAX_PATH];
|
||
ULONGLONG BestVersion = (ULONGLONG)0;
|
||
ULONGLONG ThisVersion;
|
||
ULONGLONG KernelVersion;
|
||
DWORD dwPathLen;
|
||
BOOLEAN ReturnValue = FALSE;
|
||
|
||
TraceFunc("OscGetClosestNt( )\n");
|
||
|
||
Error = ImpersonateSecurityContext(&ClientState->ServerContextHandle);
|
||
if (Error != STATUS_SUCCESS) {
|
||
BinlPrintDbg(( DEBUG_OSC_ERROR, "ImpersonateSecurityContext: 0x%08x\n", Error ));
|
||
goto Cleanup;
|
||
}
|
||
|
||
Impersonated = TRUE;
|
||
|
||
//
|
||
// Get the version info of the kernel passed in
|
||
//
|
||
if (!OscGetNtVersionInfo(&KernelVersion, PathToKernel, ClientState)) {
|
||
BinlPrintDbg(( DEBUG_OSC_ERROR, "OscGetNtVersionInfo failed\n" ));
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Resulting string should be something like:
|
||
// "D:\RemoteInstall\Setup\English\Images\*"
|
||
if ( _snwprintf( Path,
|
||
sizeof(Path) / sizeof(Path[0]),
|
||
L"%ws\\Setup\\%ws\\%ws\\*",
|
||
IntelliMirrorPathW,
|
||
OscFindVariableW(ClientState, "LANGUAGE"),
|
||
REMOTE_INSTALL_IMAGE_DIR_W
|
||
) == -1 ) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
hFind = FindFirstFile(Path, (LPVOID) &FindData);
|
||
if (hFind == INVALID_HANDLE_VALUE) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
dwPathLen = wcslen(Path);
|
||
|
||
//
|
||
// Loop enumerating each subdirectory
|
||
//
|
||
do {
|
||
//
|
||
// Ignore directories "." and ".."
|
||
//
|
||
if (wcscmp(FindData.cFileName, L".") &&
|
||
wcscmp(FindData.cFileName, L"..") &&
|
||
(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
||
DWORD ThisSkuType;
|
||
DWORD dwFileNameLen;
|
||
//
|
||
// Add the sub-directory to the path
|
||
//
|
||
dwFileNameLen = wcslen(FindData.cFileName);
|
||
if (dwPathLen + dwFileNameLen + MAX_ARCHITECTURE_LENGTH + 1 > sizeof(Path)/sizeof(Path[0])) {
|
||
continue; // path too long, skip it
|
||
}
|
||
wcscpy(&Path[dwPathLen - 1], FindData.cFileName );
|
||
|
||
BinlPrintDbg(( DEBUG_OSC, "Found OS Directory: %ws\n", Path ));
|
||
|
||
// Resulting string should be something like:
|
||
// "D:\RemoteInstall\Setup\English\Images\nt50.wks\i386"
|
||
wcscat(Path, L"\\");
|
||
wcscat(Path, OscFindVariableW(ClientState, "MACHINETYPE"));
|
||
|
||
ThisSkuType = OscGetSkuType( Path );
|
||
|
||
#if 0
|
||
//
|
||
// Now look for the kernel. We want to save the best version
|
||
// that is newer or equal to the kernel we are looking for,
|
||
// and older than the previous best version (note that
|
||
// BestVersion is initialized to 0 so we need to check for
|
||
// that also).
|
||
//
|
||
if (OscGetNtVersionInfo(&ThisVersion, Path, ClientState) &&
|
||
(ThisVersion >= KernelVersion) &&
|
||
(ThisSkuType == SkuType) &&
|
||
((BestVersion == (ULONGLONG)0) || (ThisVersion < BestVersion))) {
|
||
BestVersion = ThisVersion;
|
||
wcscpy(SetupPath, Path);
|
||
}
|
||
#else
|
||
if (OscGetNtVersionInfo(&ThisVersion, Path, ClientState)) {
|
||
//
|
||
// if the sku we're looking for is ads and we've found srv,
|
||
// then lie and say it's really
|
||
// ads. This gets around a problem where txtsetup.sif didn't
|
||
// specify the SKU type correctly in 2195.
|
||
//
|
||
if (ThisSkuType == 1 && SkuType == 2) {
|
||
ThisSkuType = 2;
|
||
}
|
||
|
||
if ((ThisVersion >= KernelVersion) &&
|
||
(ThisSkuType == SkuType) &&
|
||
((BestVersion == (ULONGLONG)0) || (ThisVersion < BestVersion))) {
|
||
BestVersion = ThisVersion;
|
||
wcscpy(SetupPath, Path);
|
||
}
|
||
}
|
||
#endif
|
||
}
|
||
|
||
} while (FindNextFile(hFind, (LPVOID) &FindData));
|
||
|
||
if (BestVersion != 0) {
|
||
ReturnValue = TRUE;
|
||
*ExactMatch = (BOOLEAN)(BestVersion == KernelVersion);
|
||
} else {
|
||
ReturnValue = FALSE;
|
||
}
|
||
|
||
Cleanup:
|
||
|
||
if (hFind != INVALID_HANDLE_VALUE) {
|
||
FindClose(hFind);
|
||
}
|
||
|
||
if (Impersonated) {
|
||
Error = RevertSecurityContext(&ClientState->ServerContextHandle);
|
||
if (Error != STATUS_SUCCESS) {
|
||
BinlPrintDbg(( DEBUG_OSC_ERROR, "RevertSecurityContext: 0x%08x\n", Error ));
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
return ReturnValue;
|
||
}
|
||
|
||
BOOLEAN
|
||
OscGetNtVersionInfo(
|
||
PULONGLONG Version,
|
||
PWCHAR SearchDir,
|
||
PCLIENT_STATE ClientState
|
||
)
|
||
{
|
||
DWORD Error = ERROR_SUCCESS;
|
||
DWORD FileVersionInfoSize;
|
||
DWORD VersionHandle;
|
||
ULARGE_INTEGER TmpVersion;
|
||
PVOID VersionInfo;
|
||
VS_FIXEDFILEINFO * FixedFileInfo;
|
||
UINT FixedFileInfoLength;
|
||
WCHAR Path[MAX_PATH];
|
||
BOOLEAN fResult = FALSE;
|
||
|
||
TraceFunc("OscGetNtVersionInfo( )\n");
|
||
|
||
if (!SearchDir) {
|
||
goto e0;
|
||
}
|
||
|
||
// Resulting string should be something like:
|
||
// "D:\RemoteInstall\Setup\English\Images\nt50.wks\i386\ntoskrnl.exe"
|
||
if (wcslen(SearchDir) + sizeof("\\ntoskrnl.exe") + 1> sizeof(Path)/sizeof(Path[0])) {
|
||
goto e0; // path too long, skip it
|
||
}
|
||
wcscpy(Path, SearchDir);
|
||
wcscat(Path, L"\\ntoskrnl.exe");
|
||
|
||
BinlPrintDbg((DEBUG_OSC, "Checking version: %ws\n", Path));
|
||
|
||
FileVersionInfoSize = GetFileVersionInfoSize(Path, &VersionHandle);
|
||
if (FileVersionInfoSize == 0)
|
||
goto e0;
|
||
|
||
VersionInfo = BinlAllocateMemory(FileVersionInfoSize);
|
||
if (VersionInfo == NULL)
|
||
goto e0;
|
||
|
||
if (!GetFileVersionInfo(
|
||
Path,
|
||
VersionHandle,
|
||
FileVersionInfoSize,
|
||
VersionInfo))
|
||
goto e1;
|
||
|
||
if (!VerQueryValue(
|
||
VersionInfo,
|
||
L"\\",
|
||
&FixedFileInfo,
|
||
&FixedFileInfoLength))
|
||
goto e1;
|
||
|
||
TmpVersion.HighPart = FixedFileInfo->dwFileVersionMS;
|
||
TmpVersion.LowPart = FixedFileInfo->dwFileVersionLS;
|
||
*Version = TmpVersion.QuadPart;
|
||
|
||
fResult = TRUE;
|
||
|
||
e1:
|
||
BinlFreeMemory(VersionInfo);
|
||
e0:
|
||
return fResult;
|
||
}
|
||
|
||
//
|
||
// Send a message on our socket. If the message is too long, then it
|
||
// splits it into fragments of MAXIMUM_FRAGMENT_LENGTH bytes.
|
||
//
|
||
|
||
#define MAXIMUM_FRAGMENT_LENGTH 1400
|
||
|
||
DWORD
|
||
SendUdpMessage(
|
||
LPBINL_REQUEST_CONTEXT RequestContext,
|
||
PCLIENT_STATE clientState,
|
||
BOOL bFragment,
|
||
BOOL bResend
|
||
)
|
||
{
|
||
DWORD error;
|
||
FRAGMENT_PACKET FragmentHeader;
|
||
USHORT FragmentNumber;
|
||
USHORT FragmentTotal;
|
||
ULONG MessageLengthWithoutHeader;
|
||
ULONG BytesSent;
|
||
ULONG BytesThisSend;
|
||
UCHAR TempMessage[1500];
|
||
FRAGMENT_PACKET UNALIGNED * SendFragmentPacket =
|
||
(FRAGMENT_PACKET UNALIGNED *)TempMessage;
|
||
|
||
TraceFunc("SendUdpMessage( )\n");
|
||
|
||
//
|
||
// The message starts with a signature, a length, a sequence number (all
|
||
// four bytes), then two ushorts for fragment count and total. If
|
||
// we have to split it we preserve this header in each packet, with
|
||
// fragment count modified for each one.
|
||
//
|
||
|
||
MessageLengthWithoutHeader =
|
||
clientState->LastResponseLength - FRAGMENT_PACKET_DATA_OFFSET;
|
||
|
||
if (!bFragment ||
|
||
((FragmentTotal = (USHORT)((MessageLengthWithoutHeader + MAXIMUM_FRAGMENT_LENGTH - 1) / MAXIMUM_FRAGMENT_LENGTH)) <= 1))
|
||
{
|
||
#ifdef _TRACE_FUNC_
|
||
SendFragmentPacket = (FRAGMENT_PACKET UNALIGNED *)clientState->LastResponse;
|
||
TraceFunc("Sending packet with ");
|
||
BinlPrintDbg(( DEBUG_OSC, " SequenceNumber = %u )\n", SendFragmentPacket->SequenceNumber ));
|
||
#endif
|
||
|
||
error = sendto(
|
||
RequestContext->ActiveEndpoint->Socket,
|
||
clientState->LastResponse,
|
||
clientState->LastResponseLength,
|
||
0,
|
||
&RequestContext->SourceName,
|
||
RequestContext->SourceNameLength
|
||
);
|
||
|
||
} else {
|
||
|
||
FragmentHeader = *((FRAGMENT_PACKET UNALIGNED *)clientState->LastResponse); // struct copy -- save the header
|
||
BytesSent = 0;
|
||
|
||
for (FragmentNumber = 0; FragmentNumber < FragmentTotal; FragmentNumber++) {
|
||
|
||
if (FragmentNumber == (FragmentTotal - 1)) {
|
||
BytesThisSend = MessageLengthWithoutHeader - BytesSent;
|
||
} else {
|
||
BytesThisSend = MAXIMUM_FRAGMENT_LENGTH;
|
||
}
|
||
|
||
memcpy(
|
||
TempMessage + FRAGMENT_PACKET_DATA_OFFSET,
|
||
clientState->LastResponse + FRAGMENT_PACKET_DATA_OFFSET + (FragmentNumber * MAXIMUM_FRAGMENT_LENGTH),
|
||
BytesThisSend);
|
||
|
||
memcpy(SendFragmentPacket, &FragmentHeader, FRAGMENT_PACKET_DATA_OFFSET);
|
||
SendFragmentPacket->Length = BytesThisSend + FRAGMENT_PACKET_EMPTY_LENGTH;
|
||
SendFragmentPacket->FragmentNumber = FragmentNumber + 1;
|
||
SendFragmentPacket->FragmentTotal = FragmentTotal;
|
||
|
||
#ifdef TEST_FAILURE
|
||
if (FailFirstFragment) {
|
||
FailFirstFragment = FALSE;
|
||
BinlPrintDbg((DEBUG_OSC, "NOT sending first fragment, %ld bytes\n", BytesThisSend + FRAGMENT_PACKET_DATA_OFFSET));
|
||
error = ERROR_SUCCESS;
|
||
} else
|
||
#endif
|
||
|
||
//
|
||
// On resends, wait between fragments in case the resend is
|
||
// because the card can't handle quick bursts of packets.
|
||
//
|
||
if (bResend && (FragmentNumber != 0)) {
|
||
Sleep(10); // wait 10 milliseconds
|
||
}
|
||
|
||
error = sendto(
|
||
RequestContext->ActiveEndpoint->Socket,
|
||
TempMessage,
|
||
BytesThisSend + FRAGMENT_PACKET_DATA_OFFSET,
|
||
0,
|
||
&RequestContext->SourceName,
|
||
RequestContext->SourceNameLength
|
||
);
|
||
|
||
if (error == SOCKET_ERROR) {
|
||
break;
|
||
}
|
||
|
||
BytesSent += BytesThisSend;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if ( error == SOCKET_ERROR ) {
|
||
error = WSAGetLastError();
|
||
BinlPrintDbg(( DEBUG_OSC_ERROR, "Sendto() failed, error = %ld\n", error ));
|
||
} else {
|
||
error = ERROR_SUCCESS;
|
||
}
|
||
|
||
return( error );
|
||
}
|
||
|
||
//
|
||
// Verifies the packets signature is authentic
|
||
//
|
||
DWORD
|
||
OscVerifySignature(
|
||
PCLIENT_STATE clientState,
|
||
SIGNED_PACKET UNALIGNED * signedMessage
|
||
)
|
||
{
|
||
SECURITY_STATUS SecStatus;
|
||
SecBuffer SigBuffers[2];
|
||
ULONG MessageLength, SignLength;
|
||
SecBufferDesc SignMessage;
|
||
|
||
TraceFunc("OscVerifySignature( )\n");
|
||
|
||
MessageLength = signedMessage->Length;
|
||
SignLength = signedMessage->SignLength;
|
||
|
||
//
|
||
// Verify the signature
|
||
//
|
||
SigBuffers[0].pvBuffer = signedMessage->Data;
|
||
SigBuffers[0].cbBuffer = MessageLength - SIGNED_PACKET_EMPTY_LENGTH;
|
||
SigBuffers[0].BufferType = SECBUFFER_DATA;
|
||
|
||
SigBuffers[1].pvBuffer = signedMessage->Sign;
|
||
SigBuffers[1].cbBuffer = SignLength;
|
||
SigBuffers[1].BufferType = SECBUFFER_TOKEN;
|
||
|
||
SignMessage.pBuffers = SigBuffers;
|
||
SignMessage.cBuffers = 2;
|
||
SignMessage.ulVersion = 0;
|
||
|
||
#ifndef ONLY_SIGN_MESSAGES
|
||
SecStatus = UnsealMessage(
|
||
&clientState->ServerContextHandle,
|
||
&SignMessage,
|
||
0,
|
||
0 );
|
||
#else
|
||
SecStatus = VerifySignature(
|
||
&clientState->ServerContextHandle,
|
||
&SignMessage,
|
||
0,
|
||
0 );
|
||
#endif
|
||
|
||
if (SecStatus != STATUS_SUCCESS)
|
||
{
|
||
DWORD Error;
|
||
SIGNED_PACKET UNALIGNED * SendSignedMessage;
|
||
|
||
BinlPrintDbg(( DEBUG_OSC_ERROR, "Sending ERR packet from Verify/Unseal!!\n"));
|
||
|
||
clientState->LastResponseLength = SIGNED_PACKET_ERROR_LENGTH;
|
||
Error = OscVerifyLastResponseSize(clientState);
|
||
if (Error != ERROR_SUCCESS)
|
||
return SecStatus; // we can't send anything back
|
||
|
||
SendSignedMessage = (SIGNED_PACKET UNALIGNED *)(clientState->LastResponse);
|
||
|
||
memcpy(SendSignedMessage->Signature, ErrorSignedSignature, 4);
|
||
SendSignedMessage->Length = 4;
|
||
SendSignedMessage->SequenceNumber = clientState->LastSequenceNumber;
|
||
}
|
||
|
||
return SecStatus;
|
||
}
|
||
|
||
//
|
||
//
|
||
//
|
||
DWORD
|
||
OscSendSignedMessage(
|
||
LPBINL_REQUEST_CONTEXT RequestContext,
|
||
PCLIENT_STATE clientState,
|
||
PCHAR Message,
|
||
ULONG MessageLength
|
||
)
|
||
{
|
||
DWORD Error = ERROR_SUCCESS;
|
||
SIGNED_PACKET UNALIGNED * SendSignedMessage;
|
||
SecBuffer SigBuffers[2];
|
||
SecBufferDesc SignMessage;
|
||
SECURITY_STATUS SecStatus;
|
||
|
||
#ifdef _TRACE_FUNC_
|
||
TraceFunc("OscSendSignedMessage( ");
|
||
BinlPrintDbg(( DEBUG_OSC, "SequenceNumber = %u )\n", clientState->LastSequenceNumber ));
|
||
#endif
|
||
|
||
//
|
||
// Make sure we have space for the message
|
||
//
|
||
clientState->LastResponseLength = MessageLength + SIGNED_PACKET_DATA_OFFSET;
|
||
Error = OscVerifyLastResponseSize(clientState);
|
||
if (Error != ERROR_SUCCESS)
|
||
return Error;
|
||
|
||
//
|
||
// copy the message
|
||
//
|
||
SendSignedMessage = (SIGNED_PACKET UNALIGNED *) clientState->LastResponse;
|
||
memcpy(SendSignedMessage->Data, Message, MessageLength);
|
||
|
||
//
|
||
// sign the message
|
||
//
|
||
memcpy(SendSignedMessage->Signature, ResponseSignedSignature, 4);
|
||
SendSignedMessage->Length = MessageLength + SIGNED_PACKET_EMPTY_LENGTH;
|
||
SendSignedMessage->SequenceNumber = clientState->LastSequenceNumber;
|
||
SendSignedMessage->FragmentNumber = 1; // fragment count
|
||
SendSignedMessage->FragmentTotal = 1; // fragment total
|
||
|
||
SendSignedMessage->SignLength = NTLMSSP_MESSAGE_SIGNATURE_SIZE;
|
||
|
||
#if 0
|
||
//
|
||
// Send out an unsealed copy to a different port.
|
||
//
|
||
|
||
{
|
||
USHORT TmpPort;
|
||
PCHAR TmpSignature[4];
|
||
|
||
TmpPort = ((struct sockaddr_in *)&RequestContext->SourceName)->sin_port;
|
||
memcpy(TmpSignature, SendSignedMessage->Signature, 4);
|
||
|
||
((struct sockaddr_in *)&RequestContext->SourceName)->sin_port = 0xabcd;
|
||
memcpy(SendSignedMessage->Signature, "FAKE", 4);
|
||
|
||
Error = SendUdpMessage(RequestContext, clientState, TRUE, FALSE);
|
||
|
||
((struct sockaddr_in *)&RequestContext->SourceName)->sin_port = TmpPort;
|
||
memcpy(SendSignedMessage->Signature, TmpSignature, 4);
|
||
}
|
||
#endif
|
||
|
||
SigBuffers[0].pvBuffer = SendSignedMessage->Data;
|
||
SigBuffers[0].cbBuffer = MessageLength;
|
||
SigBuffers[0].BufferType = SECBUFFER_DATA;
|
||
|
||
SigBuffers[1].pvBuffer = SendSignedMessage->Sign;
|
||
SigBuffers[1].cbBuffer = NTLMSSP_MESSAGE_SIGNATURE_SIZE;
|
||
SigBuffers[1].BufferType = SECBUFFER_TOKEN;
|
||
|
||
SignMessage.pBuffers = SigBuffers;
|
||
SignMessage.cBuffers = 2;
|
||
SignMessage.ulVersion = 0;
|
||
|
||
#ifndef ONLY_SIGN_MESSAGES
|
||
SecStatus = SealMessage(
|
||
&clientState->ServerContextHandle,
|
||
0,
|
||
&SignMessage,
|
||
0 );
|
||
#else
|
||
SecStatus = MakeSignature(
|
||
&clientState->ServerContextHandle,
|
||
0,
|
||
&SignMessage,
|
||
0 );
|
||
#endif
|
||
|
||
//
|
||
// Make sure the signature worked. If not, send error packet.
|
||
//
|
||
if (SecStatus != STATUS_SUCCESS)
|
||
{
|
||
BinlPrintDbg(( DEBUG_OSC_ERROR, "Sending ERR packet from Make/Seal!!\n"));
|
||
|
||
clientState->LastResponseLength = SIGNED_PACKET_ERROR_LENGTH;
|
||
Error = OscVerifyLastResponseSize(clientState);
|
||
if (Error != ERROR_SUCCESS)
|
||
return Error;
|
||
|
||
memcpy(SendSignedMessage->Signature, ErrorSignedSignature, 4);
|
||
SendSignedMessage->Length = 4;
|
||
}
|
||
else
|
||
{
|
||
BinlPrintDbg(( DEBUG_OSC, "Sending RSPS, %d bytes\n", clientState->LastResponseLength));
|
||
}
|
||
|
||
#ifdef TEST_FAILURE
|
||
if (FailFirstResponse)
|
||
{
|
||
BinlPrintDbg(( DEBUG_OSC, "NOT Sending RSP, %d bytes\n", clientState->LastResponseLength));
|
||
FailFirstResponse = FALSE;
|
||
Error = ERROR_SUCCESS;
|
||
} else
|
||
#endif
|
||
|
||
Error = SendUdpMessage(RequestContext, clientState, TRUE, FALSE);
|
||
|
||
if (Error != ERROR_SUCCESS)
|
||
{
|
||
BinlPrintDbg(( DEBUG_OSC_ERROR, "Could not send RSP message %d\n", Error ));
|
||
}
|
||
|
||
return Error;
|
||
}
|
||
|
||
//
|
||
//
|
||
//
|
||
DWORD
|
||
OscSendUnsignedMessage(
|
||
LPBINL_REQUEST_CONTEXT RequestContext,
|
||
PCLIENT_STATE clientState,
|
||
PCHAR Message,
|
||
ULONG MessageLength
|
||
)
|
||
{
|
||
DWORD Error = ERROR_SUCCESS;
|
||
SIGNED_PACKET UNALIGNED * SendSignedMessage;
|
||
SecBuffer SigBuffers[2];
|
||
SecBufferDesc SignMessage;
|
||
SECURITY_STATUS SecStatus;
|
||
|
||
#ifdef _TRACE_FUNC_
|
||
TraceFunc("OscSendUnsignedMessage( ");
|
||
BinlPrintDbg(( DEBUG_OSC, "SequenceNumber = %u )\n", clientState->LastSequenceNumber ));
|
||
#endif
|
||
|
||
//
|
||
// Make sure we have space for the message
|
||
//
|
||
clientState->LastResponseLength = MessageLength + SIGNED_PACKET_DATA_OFFSET;
|
||
Error = OscVerifyLastResponseSize(clientState);
|
||
if (Error != ERROR_SUCCESS)
|
||
return Error;
|
||
|
||
//
|
||
// copy the message
|
||
//
|
||
SendSignedMessage = (SIGNED_PACKET UNALIGNED *) clientState->LastResponse;
|
||
memcpy(SendSignedMessage->Data, Message, MessageLength);
|
||
|
||
//
|
||
// sign the message
|
||
//
|
||
memcpy(SendSignedMessage->Signature, ResponseUnsignedSignature, 4);
|
||
SendSignedMessage->Length = MessageLength + SIGNED_PACKET_EMPTY_LENGTH;
|
||
SendSignedMessage->SequenceNumber = clientState->LastSequenceNumber;
|
||
SendSignedMessage->FragmentNumber = 1; // fragment count
|
||
SendSignedMessage->FragmentTotal = 1; // fragment total
|
||
SendSignedMessage->SignLength = 0;
|
||
|
||
Error = SendUdpMessage(RequestContext, clientState, TRUE, FALSE);
|
||
|
||
if (Error != ERROR_SUCCESS)
|
||
{
|
||
BinlPrintDbg(( DEBUG_OSC_ERROR, "Could not send RSU message %d\n", Error ));
|
||
}
|
||
|
||
return Error;
|
||
}
|
||
|
||
DWORD
|
||
OscSendSetupMessage(
|
||
LPBINL_REQUEST_CONTEXT RequestContext,
|
||
PCLIENT_STATE clientState,
|
||
ULONG RequestType,
|
||
PCHAR Message,
|
||
ULONG MessageLength
|
||
)
|
||
{
|
||
DWORD Error = ERROR_SUCCESS;
|
||
SPUDP_PACKET UNALIGNED * SendMessage;
|
||
|
||
#ifdef _TRACE_FUNC_
|
||
TraceFunc("OscSendSetupMessage( ");
|
||
BinlPrintDbg(( DEBUG_OSC, "SequenceNumber = %u )\n", clientState->LastSequenceNumber ));
|
||
#endif
|
||
|
||
//
|
||
// Make sure we have space for the message
|
||
//
|
||
clientState->LastResponseLength = MessageLength + SPUDP_PACKET_DATA_OFFSET;
|
||
Error = OscVerifyLastResponseSize(clientState);
|
||
if (Error != ERROR_SUCCESS) {
|
||
return Error;
|
||
}
|
||
|
||
//
|
||
// copy the message
|
||
//
|
||
SendMessage = (SPUDP_PACKET UNALIGNED *) clientState->LastResponse;
|
||
memcpy(SendMessage->Data, Message, MessageLength);
|
||
|
||
//
|
||
// fill in the message stuff
|
||
//
|
||
memcpy(SendMessage->Signature, SetupResponseSignature, 4);
|
||
SendMessage->Length = MessageLength + SPUDP_PACKET_EMPTY_LENGTH;
|
||
SendMessage->Status = STATUS_SUCCESS;
|
||
SendMessage->SequenceNumber = clientState->LastSequenceNumber;
|
||
SendMessage->RequestType = RequestType;
|
||
SendMessage->FragmentNumber = 1; // fragment count
|
||
SendMessage->FragmentTotal = 1; // fragment total
|
||
|
||
Error = SendUdpMessage(RequestContext, clientState, TRUE, FALSE);
|
||
|
||
if (Error != ERROR_SUCCESS) {
|
||
BinlPrintDbg(( DEBUG_OSC_ERROR, "Could not send SPR message %d\n", Error ));
|
||
}
|
||
|
||
return Error;
|
||
}
|
||
|
||
#ifdef SET_ACLS_ON_CLIENT_DIRS
|
||
//
|
||
//
|
||
//
|
||
DWORD
|
||
OscSetClientDirectoryPermissions(
|
||
PCLIENT_STATE clientState )
|
||
{
|
||
DWORD Err = ERROR_SUCCESS;
|
||
WCHAR DirPath[ MAX_PATH ];
|
||
WCHAR Domain[ 80 ];
|
||
DWORD dwDomainSize = 80;
|
||
PSECURITY_DESCRIPTOR pSD;
|
||
PACL pDACL;
|
||
PSID pSID;
|
||
BOOL bOwnerDefault;
|
||
DWORD dwLengthRequired;
|
||
SID_NAME_USE snu;
|
||
PWCHAR pMachineName = OscFindVariableW( clientState, "MACHINENAME" );
|
||
|
||
if ( _snwprintf ( DirPath,
|
||
sizeof(DirPath) / sizeof(DirPath[0]),
|
||
L"%ws\\REMINST\\Clients\\%ws",
|
||
OscFindVariableW( clientState, "SERVERNAME" ),
|
||
pMachineName ) == -1 ) {
|
||
Err = ERROR_BAD_PATHNAME;
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Figure out how big the machine account's SID is
|
||
//
|
||
LookupAccountName( NULL,
|
||
pMachineName,
|
||
pSID,
|
||
&dwLengthRequired,
|
||
Domain,
|
||
&dwDomainSize,
|
||
&snu );
|
||
|
||
//
|
||
// make space
|
||
//
|
||
pSID = (PSID) BinlAllocateMemory( dwLengthRequired );
|
||
if ( pSID == NULL )
|
||
goto OutOfMemory;
|
||
|
||
//
|
||
// get the machine account's SID
|
||
//
|
||
if (!LookupAccountName( NULL, pMachineName, pSID, &dwLengthRequired, Domain, &dwDomainSize, &snu ) )
|
||
goto Error;
|
||
|
||
dwLengthRequired += sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid ( pSID );
|
||
pDACL = (PACL) BinlAllocateMemory( dwLengthRequired );
|
||
if ( pDACL == NULL )
|
||
goto OutOfMemory;
|
||
|
||
pSD = ( PSECURITY_DESCRIPTOR) BinlAllocateMemory( SECURITY_DESCRIPTOR_MIN_LENGTH + dwLengthRequired );
|
||
if ( pSD == NULL )
|
||
goto OutOfMemory;
|
||
|
||
if ( !InitializeSecurityDescriptor ( pSD, SECURITY_DESCRIPTOR_REVISION) )
|
||
goto Error;
|
||
|
||
if ( !InitializeAcl( pDACL, dwLengthRequired, ACL_REVISION ) )
|
||
goto Error;
|
||
|
||
if ( !AddAccessAllowedAce( pDACL, ACL_REVISION, FILE_ALL_ACCESS, pSID ) )
|
||
goto Error;
|
||
|
||
if ( !IsValidAcl( pDACL ) )
|
||
goto Error;
|
||
|
||
if ( !SetSecurityDescriptorDacl( pSD, TRUE, pDACL, FALSE ) )
|
||
goto Error;
|
||
|
||
if ( !SetSecurityDescriptorOwner( pSD, pSID, FALSE ) )
|
||
goto Error;
|
||
|
||
if ( ! IsValidSecurityDescriptor ( pSD ) )
|
||
goto Error;
|
||
|
||
if ( !SetFileSecurity( DirPath,
|
||
OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
|
||
pSD ) )
|
||
goto Error;
|
||
|
||
goto Cleanup;
|
||
|
||
OutOfMemory:
|
||
Err = ERROR_NOT_ENOUGH_SERVER_MEMORY;
|
||
goto Cleanup;
|
||
|
||
Error:
|
||
Err = GetLastError( );
|
||
|
||
Cleanup:
|
||
if ( pSID )
|
||
BinlFreeMemory( pSID );
|
||
|
||
if ( pSD )
|
||
BinlFreeMemory( pSD );
|
||
|
||
return Err;
|
||
}
|
||
#endif // SET_ACLS_ON_CLIENT_DIRS
|
||
|
||
#if 0
|
||
VOID
|
||
OscGetFlipServerList(
|
||
PUCHAR FlipServerList,
|
||
PULONG FlipServerListLength
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function gets the flip server list using the GPT of the
|
||
currently impersonated user.
|
||
|
||
Arguments:
|
||
|
||
FlipServerList - The location to store the flip server list, which
|
||
is a series of 4-byte IP addresses.
|
||
|
||
FlipServerListLength - Returns the length of the flip server list
|
||
if any are stored.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
LPWSTR GptPath;
|
||
WCHAR NetbootPath[MAX_PATH];
|
||
WCHAR TempServerList[128];
|
||
ULONG TempServerIp[4];
|
||
LPWSTR CurDirLoc, CurDirEnd;
|
||
LPWSTR CurSrvLoc, CurSrvEnd;
|
||
PUCHAR CurFlipLoc;
|
||
ULONG FlipServerCount;
|
||
|
||
TraceFunc("OscGetFlipServerList( )\n");
|
||
|
||
TempServerList[0] = L'\0';
|
||
|
||
//
|
||
// Read the GPT path.
|
||
//
|
||
|
||
GptPath = GetGPTPath(NULL, NULL);
|
||
|
||
//
|
||
// Scan the GPT path for a netboot.ini file.
|
||
//
|
||
|
||
CurDirLoc = GptPath;
|
||
|
||
while (*CurDirLoc != L'\0') {
|
||
|
||
CurDirEnd = wcschr(CurDirLoc, L';');
|
||
if (CurDirEnd == NULL) {
|
||
wsprintf(NetbootPath, L"%wsnetboot.ini", CurDirLoc);
|
||
CurDirLoc += wcslen(CurDirLoc); // points to final '\0'
|
||
} else {
|
||
*CurDirEnd = L'\0'; // HACK since %*ws does not seem to work
|
||
wsprintf(NetbootPath, L"%wsnetboot.ini", CurDirLoc);
|
||
*CurDirEnd = L';';
|
||
CurDirLoc = CurDirEnd + 1; // move past the ';'
|
||
}
|
||
|
||
//
|
||
// Check that the file exists.
|
||
//
|
||
|
||
if (GetFileAttributes(NetbootPath) == (DWORD)-1) {
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// If the file exists, assume it is the right one -- if
|
||
// it doesn't have the right section and key, don't try to
|
||
// look in the next path location.
|
||
//
|
||
|
||
GetPrivateProfileString(
|
||
L"BINL Server",
|
||
L"NewAccountServers",
|
||
L"", // default value is empty string
|
||
TempServerList,
|
||
sizeof(TempServerList),
|
||
NetbootPath
|
||
);
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
//
|
||
// At this point the server list is in TempServerList, which
|
||
// may be of length 0. Parse through it for IP addresses and
|
||
// put them in FlipServerList.
|
||
//
|
||
|
||
BinlPrintDbg(( DEBUG_OSC, "TempServerList is <%ws>\n", TempServerList ));
|
||
|
||
CurSrvLoc = TempServerList;
|
||
CurFlipLoc = FlipServerList;
|
||
|
||
while (*CurSrvLoc != L'\0') {
|
||
|
||
CurSrvEnd = wcschr(CurSrvLoc, L',');
|
||
if (CurSrvEnd != NULL) {
|
||
*CurSrvEnd = L'\0';
|
||
}
|
||
|
||
swscanf(CurSrvLoc, L"%ld.%ld.%ld.%ld", &TempServerIp[0], &TempServerIp[1], &TempServerIp[2], &TempServerIp[3]);
|
||
|
||
CurFlipLoc[0] = (UCHAR)TempServerIp[0];
|
||
CurFlipLoc[1] = (UCHAR)TempServerIp[1];
|
||
CurFlipLoc[2] = (UCHAR)TempServerIp[2];
|
||
CurFlipLoc[3] = (UCHAR)TempServerIp[3];
|
||
|
||
#if 0
|
||
BinlPrintDbg(( DEBUG_OSC, "FOUND IP address %d.%d.%d.%d\n",
|
||
CurFlipLoc[0],
|
||
CurFlipLoc[1],
|
||
CurFlipLoc[2],
|
||
CurFlipLoc[3]));
|
||
#endif
|
||
|
||
CurFlipLoc += 4;
|
||
*FlipServerListLength += 4;
|
||
|
||
//
|
||
// Only allow MAX_FLIP_SERVER_COUNT servers.
|
||
//
|
||
|
||
if (*FlipServerListLength == (MAX_FLIP_SERVER_COUNT*4)) {
|
||
break;
|
||
}
|
||
|
||
if (CurSrvEnd != NULL) {
|
||
CurSrvLoc = CurSrvEnd + 1;
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Randomize the list in FlipServerList.
|
||
//
|
||
|
||
FlipServerCount = (*FlipServerListLength) / 4;
|
||
|
||
if (FlipServerCount > 1) {
|
||
|
||
ULONG RandomSeed;
|
||
ULONG i, j;
|
||
UCHAR TempBuffer[4];
|
||
|
||
//
|
||
// For each element except the last, swap it with a random
|
||
// element.
|
||
//
|
||
|
||
RandomSeed = GetTickCount();
|
||
|
||
for (i = 0; i < FlipServerCount-1; i++) {
|
||
|
||
//
|
||
// Pick a random element j between the ith and the end.
|
||
//
|
||
|
||
j = i + (RtlRandom(&RandomSeed) % (FlipServerCount - i));
|
||
|
||
//
|
||
// Swap ith and jth element, unless i == j.
|
||
//
|
||
|
||
if (i != j) {
|
||
memcpy(TempBuffer, &FlipServerList[i*4], 4);
|
||
memcpy(&FlipServerList[i*4], &FlipServerList[j*4], 4);
|
||
memcpy(&FlipServerList[j*4], TempBuffer, 4);
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
#endif // FlipServer
|
||
|
||
#ifdef REMOTE_BOOT
|
||
//
|
||
// Copy any initial files specified in SIF.
|
||
//
|
||
DWORD
|
||
OscCopyTemplateFiles(
|
||
LPWSTR SourcePath,
|
||
LPWSTR ImagePath,
|
||
LPWSTR TemplateFile
|
||
)
|
||
{
|
||
#define MAX_FILES_SIZE 2048
|
||
WCHAR Files[ MAX_FILES_SIZE ];
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
LPWSTR pFilename;
|
||
WCHAR SrcFilepath[ MAX_PATH ];
|
||
WCHAR DstFilepath[ MAX_PATH ];
|
||
|
||
TraceFunc("OscCopyTemplateFiles( )\n");
|
||
|
||
dwErr = GetPrivateProfileSection( L"OSChooserFiles",
|
||
Files,
|
||
MAX_FILES_SIZE,
|
||
TemplateFile );
|
||
BinlAssert( dwErr != MAX_FILES_SIZE - 2 );
|
||
#undef MAX_FILES_SIZE
|
||
|
||
pFilename = Files;
|
||
while ( *pFilename )
|
||
{
|
||
BOOL b;
|
||
LPWSTR psz = pFilename;
|
||
while ( *psz && *psz !=L',' )
|
||
psz++;
|
||
|
||
if ( *psz == L',' )
|
||
{
|
||
*psz = L'\0';
|
||
psz++;
|
||
}
|
||
else
|
||
{
|
||
psz = pFilename;
|
||
}
|
||
|
||
wsprintf( SrcFilepath, L"%ws\\%ws", SourcePath, psz );
|
||
wsprintf( DstFilepath, L"%ws\\%ws", ImagePath, pFilename );
|
||
|
||
BinlPrintDbg((DEBUG_OSC, "Copying %ws to %ws...\n", SrcFilepath, DstFilepath));
|
||
|
||
b = CopyFile( SrcFilepath, DstFilepath, TRUE );
|
||
if ( !b ) {
|
||
dwErr = GetLastError( );
|
||
goto Error;
|
||
}
|
||
|
||
// find the end of the string
|
||
while ( *psz )
|
||
psz++;
|
||
|
||
pFilename = ++psz; // skip null
|
||
}
|
||
|
||
Error:
|
||
return dwErr;
|
||
}
|
||
#endif // REMOTE_BOOT
|
||
|
||
#if DBG && defined(REMOTE_BOOT)
|
||
//
|
||
// Create MAC Address file -
|
||
// This might be turned into a DESKTOP.INI file(?). -gpease
|
||
//
|
||
DWORD
|
||
OscCreateNullFile(
|
||
LPWSTR Image,
|
||
LPWSTR MAC
|
||
)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
WCHAR Path[ MAX_PATH ];
|
||
HANDLE hFile = INVALID_HANDLE_VALUE;
|
||
|
||
TraceFunc("OscCreateNullFile( )\n");
|
||
|
||
wsprintf( Path, L"%ws\\%ws", Image, MAC );
|
||
|
||
//
|
||
// Create NULL length file
|
||
//
|
||
hFile = CreateFile( Path,
|
||
GENERIC_WRITE,
|
||
FILE_SHARE_READ,
|
||
NULL, // security attribs
|
||
CREATE_ALWAYS,
|
||
FILE_ATTRIBUTE_NORMAL, // maybe FILE_ATTRIBUTE_HIDDEN
|
||
NULL ); // template
|
||
if (hFile != INVALID_HANDLE_VALUE) {
|
||
CloseHandle( hFile );
|
||
}
|
||
|
||
return dwErr;
|
||
}
|
||
#endif
|
||
|
||
DWORD
|
||
OscConstructSecret(
|
||
PCLIENT_STATE clientState,
|
||
PWCHAR UnicodePassword,
|
||
ULONG UnicodePasswordLength,
|
||
PCREATE_DATA CreateData
|
||
)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
UINT i;
|
||
WCHAR DomainBuffer[64];
|
||
DWORD SidLength, DomainLength;
|
||
SID_NAME_USE NameUse;
|
||
BOOL b;
|
||
PCHAR pBootFile;
|
||
PCHAR pSifFile;
|
||
#if defined(REMOTE_BOOT)
|
||
PCHAR pNetBIOSName;
|
||
PCHAR pUserDomain;
|
||
#endif
|
||
|
||
TraceFunc( "OscConstructSecret( )\n" );
|
||
|
||
RtlZeroMemory(CreateData, sizeof(CREATE_DATA));
|
||
|
||
//
|
||
// Copy the machine data into the response packet
|
||
//
|
||
// The following fields aren't necessary unless we're supporting remote boot.
|
||
// UCHAR Sid[28];
|
||
// UCHAR Domain[32];
|
||
// UCHAR Name[32];
|
||
// UCHAR Password[32];
|
||
// ULONG UnicodePasswordLength; // in bytes
|
||
// WCHAR UnicodePassword[32];
|
||
// UCHAR Installation[32];
|
||
// UCHAR MachineType[6]; // 'i386\0' or 'Alpha\0'
|
||
//
|
||
|
||
pBootFile = OscFindVariableA( clientState, "BOOTFILE" );
|
||
if ( pBootFile[0] == L'\0' ) {
|
||
OscAddVariableA( clientState, "SUBERROR", "BOOTFILE" );
|
||
return ERROR_BINL_MISSING_VARIABLE;
|
||
}
|
||
|
||
pSifFile = OscFindVariableA( clientState, "SIFFILE" );
|
||
if ( pSifFile[0] == L'\0' ) {
|
||
OscAddVariableA( clientState, "SUBERROR", "SIFFILE" );
|
||
return ERROR_BINL_MISSING_VARIABLE;
|
||
}
|
||
|
||
memcpy( CreateData->Id, "ACCT", 4);
|
||
CreateData->VersionNumber = OSC_CREATE_DATA_VERSION;
|
||
strcpy( CreateData->NextBootfile, pBootFile );
|
||
strcpy( CreateData->SifFile, pSifFile );
|
||
|
||
#if defined(REMOTE_BOOT)
|
||
pNetBIOSName = OscFindVariableA( clientState, "NETBIOSNAME");
|
||
if ( pNetBIOSName[0] == L'\0' ) {
|
||
OscAddVariableA( clientState, "SUBERROR", "NETBIOSNAME" );
|
||
return ERROR_BINL_MISSING_VARIABLE;
|
||
}
|
||
|
||
pUserDomain = OscFindVariableA( clientState, "USERDOMAIN" );
|
||
if ( pUserDomain[0] == L'\0' ) {
|
||
OscAddVariableA( clientState, "SUBERROR", "USERDOMAIN" );
|
||
return ERROR_BINL_MISSING_VARIABLE;
|
||
}
|
||
|
||
strcpy( CreateData->Name, OscFindVariableA( clientState, pNetBIOSName ) );
|
||
CreateData->UnicodePasswordLength = UnicodePasswordLength;
|
||
memcpy( CreateData->UnicodePassword, UnicodePassword, CreateData->UnicodePasswordLength );
|
||
strcpy( CreateData->Domain, OscFindVariableA( clientState, pUserDomain ) );
|
||
|
||
//
|
||
// We send the password down in Unicode also which is
|
||
// just the machine name.
|
||
// NOTE: We probably need to worry about
|
||
// the code page of the client, for the moment just do
|
||
// the simplest conversion. We may also want to get
|
||
// the machine name/password in Unicode and only convert
|
||
// it to ANSI right here. We'll punt this for the moment,
|
||
// at least the on-the-wire format will be correct.
|
||
//
|
||
//
|
||
// This isn't used right now, we only care about the Unicode password.
|
||
//
|
||
memset( CreateData->Password, '\0', sizeof(CreateData->Password) );
|
||
|
||
//
|
||
// Get the SID from the system.
|
||
//
|
||
SidLength = sizeof(CreateData->Sid);
|
||
DomainLength = sizeof(DomainBuffer) / sizeof(WCHAR);
|
||
|
||
b = LookupAccountName(
|
||
NULL,
|
||
OscFindVariableW( clientState, "NETBIOSNAME" ),
|
||
CreateData->Sid,
|
||
&SidLength,
|
||
DomainBuffer,
|
||
&DomainLength,
|
||
&NameUse);
|
||
|
||
if (!b) {
|
||
DWORD dwErr = GetLastError( );
|
||
BinlPrintDbg(( DEBUG_OSC_ERROR, "!! Error 0x%08x - Account lookup failed.\n", dwErr ));
|
||
OscCreateWin32SubError( clientState, dwErr );
|
||
return ERROR_BINL_FAILED_TO_INITIALIZE_CLIENT;;
|
||
}
|
||
|
||
// This should be the NETBIOS domain name.
|
||
wcstombs( CreateData->Domain, DomainBuffer, DomainLength + 1 );
|
||
|
||
//
|
||
// Sanity check
|
||
//
|
||
BinlAssertMsg( CreateData->Name[0], "No machine name" );
|
||
// BinlAssertMsg( CreateData->Password[0], "No machine password" );
|
||
BinlAssertMsg( CreateData->UnicodePasswordLength, "Password length is ZERO" );
|
||
BinlAssertMsg( CreateData->UnicodePassword[0], "No UNICODE machine password" );
|
||
BinlAssertMsg( CreateData->Domain[0], "No machine domain" );
|
||
|
||
#endif
|
||
BinlAssertMsg( CreateData->NextBootfile[0], "No boot file" );
|
||
return dwErr;
|
||
}
|
||
|
||
DWORD
|
||
GetOurServerInfo (
|
||
VOID
|
||
)
|
||
//
|
||
// This routine gets several global names that we need to handle client
|
||
// requests. We store them in globals because they change very infrequently
|
||
// and they're relatively expense to retrieve.
|
||
//
|
||
{
|
||
PWCHAR fqdn = NULL;
|
||
DWORD uSize;
|
||
DWORD dnsError = ERROR_SUCCESS;
|
||
DWORD fqdnError = ERROR_SUCCESS;
|
||
DWORD netbiosServerError = ERROR_SUCCESS;
|
||
DWORD netbiosDomainError = ERROR_SUCCESS;
|
||
PWCHAR ourDNSName = NULL;
|
||
PWCHAR tmp;
|
||
PWCHAR pDomain;
|
||
WCHAR ServerName[32] = { 0 };
|
||
DWORD ServerSize = sizeof(ServerName) / sizeof(WCHAR);
|
||
ULONG Error;
|
||
|
||
// first grab the netbios name of our server
|
||
|
||
if ( !GetComputerNameEx( ComputerNameNetBIOS, ServerName, &ServerSize ) ) {
|
||
netbiosServerError = GetLastError();
|
||
BinlPrintDbg(( DEBUG_OSC_ERROR, "!! Error 0x%08x - GetComputerNameEx failed.\n", netbiosServerError ));
|
||
} else {
|
||
|
||
tmp = BinlAllocateMemory( ( lstrlenW( ServerName ) + 1 ) * sizeof(WCHAR) );
|
||
|
||
if (tmp == NULL) {
|
||
|
||
netbiosServerError = ERROR_NOT_ENOUGH_SERVER_MEMORY;
|
||
|
||
} else {
|
||
|
||
lstrcpyW( tmp, ServerName );
|
||
|
||
EnterCriticalSection( &gcsParameters );
|
||
|
||
if (BinlGlobalOurServerName) {
|
||
BinlFreeMemory( BinlGlobalOurServerName );
|
||
}
|
||
|
||
BinlGlobalOurServerName = tmp;
|
||
|
||
LeaveCriticalSection( &gcsParameters );
|
||
}
|
||
}
|
||
|
||
// Next grab the fully qualified domain name of our server
|
||
uSize = 0;
|
||
if ( !GetComputerObjectName( NameFullyQualifiedDN, NULL, &uSize ) ) {
|
||
fqdnError = GetLastError( );
|
||
if ( fqdnError != ERROR_MORE_DATA ) {
|
||
|
||
BinlPrint((DEBUG_OSC_ERROR, "!! Error 0x%08x - GetComputerObjectName failed.\n", fqdnError ));
|
||
goto GetDNS;
|
||
}
|
||
fqdnError = ERROR_SUCCESS;
|
||
}
|
||
fqdn = BinlAllocateMemory( uSize * sizeof(WCHAR) );
|
||
if ( fqdn ) {
|
||
if ( !GetComputerObjectName( NameFullyQualifiedDN, fqdn, &uSize ) ) {
|
||
|
||
fqdnError = GetLastError( );
|
||
BinlPrint((DEBUG_OSC_ERROR, "!! Error 0x%08x - GetComputerObjectName failed.\n", fqdnError ));
|
||
|
||
} else {
|
||
|
||
EnterCriticalSection( &gcsParameters );
|
||
|
||
tmp = BinlGlobalOurFQDNName;
|
||
BinlGlobalOurFQDNName = fqdn;
|
||
|
||
fqdn = tmp; // we'll free it below
|
||
|
||
// next setup the netbios domain name
|
||
|
||
pDomain = StrStrIW( BinlGlobalOurFQDNName, L"DC=" );
|
||
if ( pDomain ) {
|
||
|
||
PDS_NAME_RESULTW pResults;
|
||
|
||
BinlPrintDbg(( DEBUG_OSC, "Converting %ws to a NetBIOS domain name...\n", pDomain ));
|
||
|
||
netbiosDomainError = DsCrackNames( INVALID_HANDLE_VALUE,
|
||
DS_NAME_FLAG_SYNTACTICAL_ONLY,
|
||
DS_FQDN_1779_NAME,
|
||
DS_CANONICAL_NAME,
|
||
1,
|
||
&pDomain,
|
||
&pResults );
|
||
if (netbiosDomainError != ERROR_SUCCESS) {
|
||
|
||
BinlPrint(( DEBUG_ERRORS, "GetOurServerInfo error in DsCrackNames %u\n", netbiosDomainError ));
|
||
}
|
||
|
||
if ( netbiosDomainError == ERROR_SUCCESS ) {
|
||
if ( pResults->cItems == 1
|
||
&& pResults->rItems[0].status == DS_NAME_NO_ERROR
|
||
&& pResults->rItems[0].pName ) { // paranoid
|
||
|
||
pResults->rItems[0].pName[wcslen(pResults->rItems[0].pName)-1] = L'\0';
|
||
|
||
tmp = BinlAllocateMemory( ( lstrlenW( pResults->rItems[0].pName ) + 1 ) * sizeof(WCHAR) );
|
||
|
||
if (tmp == NULL) {
|
||
|
||
netbiosDomainError = ERROR_NOT_ENOUGH_SERVER_MEMORY;
|
||
|
||
} else {
|
||
|
||
lstrcpyW( tmp, pResults->rItems[0].pName );
|
||
|
||
if (BinlGlobalOurDomainName) {
|
||
BinlFreeMemory( BinlGlobalOurDomainName );
|
||
}
|
||
BinlGlobalOurDomainName = tmp;
|
||
}
|
||
}
|
||
DsFreeNameResult( pResults );
|
||
}
|
||
}
|
||
LeaveCriticalSection( &gcsParameters );
|
||
}
|
||
} else {
|
||
|
||
fqdnError = ERROR_NOT_ENOUGH_SERVER_MEMORY;
|
||
}
|
||
|
||
GetDNS:
|
||
// Retrieve the FQDNS name of the server
|
||
uSize = 0;
|
||
if ( !GetComputerNameEx( ComputerNameDnsFullyQualified, NULL, &uSize ) ) {
|
||
dnsError = GetLastError( );
|
||
if ( dnsError != ERROR_MORE_DATA ) {
|
||
BinlPrint((DEBUG_OSC_ERROR, "!! Error 0x%08x - GetComputerNameEx failed.\n", dnsError ));
|
||
goto returnError;
|
||
}
|
||
dnsError = ERROR_SUCCESS;
|
||
}
|
||
ourDNSName = (PWCHAR) BinlAllocateMemory( uSize * sizeof(WCHAR) );
|
||
if ( ourDNSName ) {
|
||
if ( !GetComputerNameEx( ComputerNameDnsFullyQualified, ourDNSName, &uSize ) ) {
|
||
|
||
dnsError = GetLastError( );
|
||
BinlPrint((DEBUG_OSC_ERROR, "!! Error 0x%08x - GetComputerNameEx failed.\n", dnsError ));
|
||
|
||
} else {
|
||
|
||
EnterCriticalSection( &gcsParameters );
|
||
|
||
tmp = BinlGlobalOurDnsName;
|
||
BinlGlobalOurDnsName = ourDNSName;
|
||
|
||
LeaveCriticalSection( &gcsParameters );
|
||
|
||
ourDNSName = tmp; // we'll free it below
|
||
}
|
||
} else {
|
||
dnsError = ERROR_NOT_ENOUGH_SERVER_MEMORY;
|
||
}
|
||
|
||
returnError:
|
||
|
||
if (ourDNSName) {
|
||
BinlFreeMemory( ourDNSName );
|
||
}
|
||
if (fqdn) {
|
||
BinlFreeMemory( fqdn );
|
||
}
|
||
if (fqdnError != ERROR_SUCCESS) {
|
||
Error = fqdnError;
|
||
} else if (dnsError != ERROR_SUCCESS) {
|
||
Error = dnsError;
|
||
} else if (netbiosServerError != ERROR_SUCCESS) {
|
||
Error = netbiosServerError;
|
||
} else {
|
||
Error = netbiosDomainError;
|
||
}
|
||
return Error;
|
||
}
|
||
|
||
DWORD
|
||
GetDomainNetBIOSName(
|
||
IN PCWSTR DomainNameInAnyFormat,
|
||
OUT PWSTR *NetBIOSName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Retrieves the netbios name for a domain given an input name. The input
|
||
name may be in DNS form or netbios form, it doesn't really matter.
|
||
|
||
Arguments:
|
||
|
||
DomainNameInAnyFormat - string representing the name of the domain to query
|
||
|
||
NetBIOSName - receives string that represents the domain netbios name.
|
||
The string must be freed via BinlFreeMemory.
|
||
|
||
Return Value:
|
||
|
||
win32 error code indicating outcome.
|
||
|
||
--*/
|
||
{
|
||
PDOMAIN_CONTROLLER_INFO DomainControllerInfo = NULL;
|
||
PDSROLE_PRIMARY_DOMAIN_INFO_BASIC DomainInfo = NULL;
|
||
DWORD Error;
|
||
|
||
Error = DsGetDcName(
|
||
NULL,
|
||
DomainNameInAnyFormat,
|
||
NULL,
|
||
NULL,
|
||
DS_RETURN_FLAT_NAME,
|
||
&DomainControllerInfo );
|
||
|
||
if (Error != ERROR_SUCCESS) {
|
||
BinlPrintDbg((
|
||
DEBUG_ERRORS,
|
||
"DsGetDcName (%ws) failed, ec = %d.\r\n",
|
||
DomainNameInAnyFormat,
|
||
Error ));
|
||
goto exit;
|
||
}
|
||
|
||
Error = DsRoleGetPrimaryDomainInformation(
|
||
DomainControllerInfo->DomainControllerName,
|
||
DsRolePrimaryDomainInfoBasic,
|
||
(PBYTE *) &DomainInfo);
|
||
|
||
if (Error != ERROR_SUCCESS) {
|
||
BinlPrintDbg((
|
||
DEBUG_ERRORS,
|
||
"DsRoleGetPrimaryDomainInformation (%ws) failed, ec = %d.\r\n",
|
||
DomainControllerInfo->DomainControllerName,
|
||
Error ));
|
||
goto exit;
|
||
}
|
||
|
||
*NetBIOSName = BinlAllocateMemory(
|
||
(wcslen(DomainInfo->DomainNameFlat)+1) * sizeof(WCHAR) );
|
||
|
||
if (*NetBIOSName) {
|
||
wcscpy( *NetBIOSName, DomainInfo->DomainNameFlat );
|
||
} else {
|
||
BinlPrintDbg((
|
||
DEBUG_ERRORS,
|
||
"GetDomainNetBIOSName: failed to allocate memory (%d bytes) .\r\n",
|
||
(wcslen(DomainInfo->DomainNameFlat)+1) * sizeof(WCHAR) ));
|
||
Error = ERROR_NOT_ENOUGH_SERVER_MEMORY;
|
||
}
|
||
|
||
exit:
|
||
if (DomainInfo) {
|
||
DsRoleFreeMemory( DomainInfo );
|
||
}
|
||
|
||
if (DomainControllerInfo) {
|
||
NetApiBufferFree( DomainControllerInfo );
|
||
}
|
||
|
||
return(Error);
|
||
|
||
}
|