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);
|
|||
|
|
|||
|
}
|