windows-nt/Source/XPSP1/NT/net/dhcp/server/binl/utils.c

2652 lines
70 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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);
}