Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2478 lines
68 KiB

/*++
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>";
#define RANDOM_SEED (98725757)
static PCWSTR gUsableChars = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
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 )/sizeof(ErrorString[0])) + 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;
DWORD UsableCount = 0;
DWORD Seed = 0;
WCHAR GeneratedCharacter;
BOOLEAN Proceed = FALSE;
//
// Set return password length and initialize
// the generated password.
//
*PasswordLength = LM20_PWLEN * sizeof(WCHAR);
memset( Password, 0, *PasswordLength );
//
// Initialize for random password generation.
//
UsableCount = lstrlen(gUsableChars);
Seed = RANDOM_SEED ^ GetCurrentTime();
srand( Seed );
//
// Ensure we have at least one period in the password.
//
Password[rand() % LM20_PWLEN] = L'.';
//
// Ensure there's at least one digit in the password.
//
do {
i = rand() % LM20_PWLEN;
} while ( Password[i] != 0 );
Password[i] = (rand() % 10) + 0x30;
//
// Now fill in the rest of the password.
//
for (i = 0; i < LM20_PWLEN; i++) {
if ( Password[i] == 0 ) {
Password[i] = gUsableChars[rand() % UsableCount];
}
}
}
//
// 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.";
WCHAR 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 ) > 0 ) {
ErrorMsgFilename[MAX_PATH-1] = L'\0'; // throw in terminating null just to be safe
//
// 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, strlen(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;
Error = ldap_set_option(ClientState->AuthenticatedDCLdapHandle, LDAP_OPT_GETDSNAME_FLAGS, &temp );
if (Error != ERROR_SUCCESS) {
BinlPrintDbg(( DEBUG_ERRORS, "OscImpersonate: Error %x when setting ldap options\n" ));
goto ImpersonateFailed;
}
temp = LDAP_VERSION3;
Error = ldap_set_option(ClientState->AuthenticatedDCLdapHandle, LDAP_OPT_VERSION, &temp );
if (Error != ERROR_SUCCESS) {
BinlPrintDbg(( DEBUG_ERRORS, "OscImpersonate: Error %x when setting ldap options\n" ));
goto ImpersonateFailed;
}
//
// Tell LDAP to keep connections referenced after searches.
//
temp = (ULONG)((ULONG_PTR)LDAP_OPT_ON);
Error = ldap_set_option(ClientState->AuthenticatedDCLdapHandle, LDAP_OPT_REF_DEREF_CONN_PER_MSG, &temp);
if (Error != ERROR_SUCCESS) {
BinlPrintDbg(( DEBUG_ERRORS, "OscImpersonate: Error %x when setting ldap options\n" ));
goto ImpersonateFailed;
}
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) {
RtlSecureZeroMemory(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] = '\0';
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] = '\0';
GetPrivateProfileStringA(OSCHOOSER_SIF_SECTIONA,
"ImageType",
Buffer, // default
Buffer,
256,
pSifPath
);
if (_stricmp("ASR", Buffer)) {
return FALSE;
}
return TRUE;
}
BOOLEAN
OscSifIsWinPE(
PCHAR pSifPath
)
{
DWORD dwErr;
CHAR Buffer[256];
TraceFunc("OscSifIsWinPE( )\n");
Buffer[0] = '\0';
GetPrivateProfileStringA(OSCHOOSER_SIF_SECTIONA,
"ImageType",
Buffer, // default
Buffer,
256,
pSifPath
);
if (_stricmp("WinPE", Buffer)) {
return FALSE;
}
return TRUE;
}
BOOLEAN
OscSifIsWinPEW(
PWCHAR pSifPath
)
{
DWORD dwErr;
WCHAR Buffer[256];
TraceFunc("OscSifIsWinPE( )\n");
Buffer[0] = UNICODE_NULL;
GetPrivateProfileString(OSCHOOSER_SIF_SECTIONW,
L"ImageType",
Buffer, // default
Buffer,
256,
pSifPath
);
if (_wcsicmp(L"WinPE", Buffer)) {
return FALSE;
}
return TRUE;
}
DWORD
OscGetSkuType(
PWSTR PathToTxtSetupSif
)
{
PWSTR SifFile;
DWORD SkuType = 0;
SifFile = BinlAllocateMemory(
(wcslen(PathToTxtSetupSif) +
sizeof(L"\\txtsetup.sif")/sizeof(WCHAR) ) * 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,
IN DWORD SetupPathSize,
OUT PBOOLEAN ExactMatch
)
{
DWORD Error = ERROR_SUCCESS;
WIN32_FIND_DATA FindData,TemplateData;
HANDLE hFind = INVALID_HANDLE_VALUE,hTemplate = INVALID_HANDLE_VALUE;
BOOLEAN Impersonated = FALSE;
WCHAR Path[MAX_PATH],TemplatesPath[MAX_PATH];
PWSTR p;
ULONGLONG BestVersion = (ULONGLONG)0;
ULONGLONG ThisVersion;
ULONGLONG KernelVersion;
DWORD dwPathLen;
BOOLEAN ReturnValue = FALSE;
BOOLEAN FoundWinPE;
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
) < 0 ) {
goto Cleanup;
}
Path[MAX_PATH-1] = L'\0'; // throw in terminating null just to be safe
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;
DWORD dwTemplatesPathLen;
//
// 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"
p = OscFindVariableW(ClientState, "MACHINETYPE");
if (!p) {
continue;
}
if (wcslen(Path) + (sizeof(L"\\")/sizeof(WCHAR)) + wcslen(p) > sizeof(Path)/sizeof(Path[0])) {
continue;
}
wcscat(Path, L"\\");
wcscat(Path, p);
//
// get a path to the templates folder and make sure we dont' have
// a winpe image. if we do then we're in trouble because we can't
// treat that as a normal image.
//
FoundWinPE = FALSE;
if (0 > _snwprintf(
TemplatesPath,
MAX_PATH,
L"%ws\\templates\\*.sif",
Path)) {
continue;
}
TemplatesPath[MAX_PATH-1] = L'\0'; // throw in terminating null just to be safe
dwTemplatesPathLen = wcslen(TemplatesPath);
p = wcsrchr(TemplatesPath,L'*');
BinlAssert( p != NULL );
dwTemplatesPathLen = (p - TemplatesPath)/sizeof(WCHAR);
hTemplate = FindFirstFile(TemplatesPath, (LPVOID) &TemplateData);
if (hTemplate != INVALID_HANDLE_VALUE) {
do {
if (wcscmp(TemplateData.cFileName, L".") &&
wcscmp(TemplateData.cFileName, L"..") &&
(TemplateData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
// make sure there is enough room.
if (dwTemplatesPathLen + wcslen(TemplateData.cFileName) + 1 > sizeof(TemplatesPath)/sizeof(WCHAR)) {
continue;
}
wcscpy(&TemplatesPath[dwTemplatesPathLen],TemplateData.cFileName);
if (OscSifIsWinPEW(TemplatesPath)) {
BinlPrintDbg(( DEBUG_OSC, "OS Directory %ws is really a WinPE image, skipping it.\n", Path ));
FoundWinPE = TRUE;
break;
}
}
} while (FindNextFile(hTemplate, (LPVOID) &TemplateData));
FindClose(hTemplate);
hTemplate = INVALID_HANDLE_VALUE;
}
if (FoundWinPE) {
continue;
}
ThisSkuType = OscGetSkuType( Path );
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))) {
if (SetupPathSize >= wcslen(Path)) {
wcscpy(SetupPath, Path);
BestVersion = ThisVersion;
}
}
}
}
} 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 (0 > _snwprintf(
Path,
MAX_PATH,
L"%ws\\ntoskrnl.exe",
SearchDir)) {
goto e0; // path too long, skip it
}
Path[MAX_PATH-1] = L'\0'; // throw in terminating null just to be safe
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;
//
// We need to whack the low 16 bits of the .LowPart so that
// we ignore the service pack value. For example, WindowsXP has a
// version number of 5.1.2600.0. XP-ServicePack1 has a version
// number of 5.1.2600.1038. We'd like those to match, so just whack
// the servicepack number portion.
//
TmpVersion.LowPart &= 0xFFFF0000;
*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 ( !pMachineName || _snwprintf (
DirPath,
sizeof(DirPath) / sizeof(DirPath[0]),
L"%ws\\REMINST\\Clients\\%ws",
OscFindVariableW( clientState, "SERVERNAME" ),
pMachineName ) < 0 ) {
Err = ERROR_BAD_PATHNAME;
goto Cleanup;
}
DirPath[MAX_PATH-1] = L'\0'; // throw in terminating null just to be safe
//
// 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
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;
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;
strncpy( CreateData->NextBootfile, pBootFile, 128 );
CreateData->NextBootfile[128-1]='\0';
strncpy( CreateData->SifFile, pSifFile, 128 );
CreateData->SifFile[128-1]='\0';
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 = BinlStrDup( ServerName );
if (tmp == NULL) {
netbiosServerError = ERROR_NOT_ENOUGH_SERVER_MEMORY;
} else {
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 = BinlStrDup( pResults->rItems[0].pName );
if (tmp == NULL) {
netbiosDomainError = ERROR_NOT_ENOUGH_SERVER_MEMORY;
} else {
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_DNS_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 = BinlStrDup( DomainInfo->DomainNameFlat );
if (!*NetBIOSName) {
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);
}