windows-nt/Source/XPSP1/NT/base/boot/oschoice/oschoice.c

2851 lines
71 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
osloader.c
Abstract:
This module contains the code that implements the OS chooser.
Author:
Adam Barr (adamba) 15-May-1997
Revision History:
--*/
#ifdef i386
#include "bldrx86.h"
#endif
#if defined(_IA64_)
#include "bldria64.h"
#endif
#include "netboot.h" // for network functionality
#include "netfs.h" // for network functionality
#include "stdio.h"
#include "msg.h"
#include <pxe_cmn.h>
#include <pxe_api.h>
#include <tftp_api.h>
#include "parse.h"
#include "stdlib.h"
#include "parseini.h"
#include "haldtect.h"
#ifdef EFI
#define BINL_PORT 0x0FAB // 4011 (decimal) in little-endian
#else
#define BINL_PORT 0xAB0F // 4011 (decimal) in big-endian
#endif
#if defined(_WIN64) && defined(_M_IA64)
#pragma section(".base", long, read, write)
__declspec(allocate(".base"))
extern
PVOID __ImageBase;
#else
extern
PVOID __ImageBase;
#endif
VOID
BlpClearScreen(
VOID
);
BOOLEAN
BlDetectHal(
VOID
);
VOID
BlMainLoop(
);
UCHAR OsLoaderVersion[] = "OS Chooser V5.0\r\n";
WCHAR OsLoaderVersionW[] = L"OS Chooser V5.0\r\n";
UCHAR OsLoaderName[] = "oschoice.exe";
const CHAR rghex[] = "0123456789ABCDEF";
typedef BOOLEAN BOOL;
BOOLEAN isOSCHOICE=TRUE;
ULONG RemoteHost;
USHORT RemotePort;
USHORT LocalPort;
CHAR DomainName[256];
CHAR UserName[256];
CHAR Password[128];
CHAR AdministratorPassword[OSC_ADMIN_PASSWORD_LEN+1];
CHAR AdministratorPasswordConfirm[OSC_ADMIN_PASSWORD_LEN+1];
WCHAR UnicodePassword[128];
CHAR LmOwfPassword[LM_OWF_PASSWORD_SIZE];
CHAR NtOwfPassword[NT_OWF_PASSWORD_SIZE];
BOOLEAN AllowFlip = TRUE; // can we be flipped to another server
BOOLEAN LoggedIn = FALSE; // have we successfully logged in
UCHAR NextBootfile[128];
UCHAR SifFile[128];
BOOLEAN DoSoftReboot = FALSE;
BOOLEAN BlUsePae;
//
// the following globals are for detecting the hal
//
UCHAR HalType[8+1+3+1];
UCHAR HalDescription[128];
PVOID InfFile;
PVOID WinntSifHandle;
PCHAR WinntSifFile;
ULONG WinntSifFileLength;
BOOLEAN DisableACPI = FALSE;
#if 0 && DBG
#define _TRACE_FUNC_
#endif
#ifdef _TRACE_FUNC_
#define TraceFunc( _func) { \
CHAR FileLine[80]; \
sprintf( FileLine, "%s(%u)", __FILE__, __LINE__ ); \
DPRINT( OSC, ( "%-55s: %s", FileLine, _func )); \
}
#else
#define TraceFunc( _func )
#endif
//
// This removes macro redefinitions which appear because we define __RPC_DOS__,
// but rpc.h defines __RPC_WIN32__
//
#pragma warning(disable:4005)
//
// As of 12/17/98, SECURITY_DOS is *not* defined - adamba
//
#if defined(SECURITY_DOS)
//
// These appear because we defined SECURITY_DOS
//
#define __far
#define __pascal
#define __loadds
#endif
#include <security.h>
#include <rpc.h>
#include <spseal.h>
#if defined(SECURITY_DOS)
//
// PSECURITY_STRING is not supposed to be used when SECURITY_DOS is
// defined -- it should be a WCHAR*. Unfortunately ntlmsp.h breaks
// this rule and even uses the SECURITY_STRING structure, which there
// is really no equivalent for in 16-bit mode.
//
typedef SEC_WCHAR * SECURITY_STRING; // more-or-less the intention where it is used
typedef SEC_WCHAR * PSECURITY_STRING;
#endif
#include <ntlmsp.h>
//
// Packet structure definitions.
//
#include "oscpkt.h"
#if DBG
VOID
DumpBuffer(
PVOID Buffer,
ULONG BufferSize
)
/*++
Routine Description:
Dumps the buffer content on to the debugger output.
Arguments:
Buffer: buffer pointer.
BufferSize: size of the buffer.
Return Value:
none
--*/
{
#define NUM_CHARS 16
ULONG i, limit;
CHAR TextBuffer[NUM_CHARS + 1];
PUCHAR BufferPtr = Buffer;
KdPrint(("------------------------------------\n"));
//
// Hex dump of the bytes
//
limit = ((BufferSize - 1) / NUM_CHARS + 1) * NUM_CHARS;
for (i = 0; i < limit; i++) {
if (i < BufferSize) {
KdPrint(("%02x ", (UCHAR)BufferPtr[i]));
if (BufferPtr[i] < 31 ) {
TextBuffer[i % NUM_CHARS] = '.';
} else if (BufferPtr[i] == '\0') {
TextBuffer[i % NUM_CHARS] = ' ';
} else {
TextBuffer[i % NUM_CHARS] = (CHAR) BufferPtr[i];
}
} else {
KdPrint((" "));
TextBuffer[i % NUM_CHARS] = ' ';
}
if ((i + 1) % NUM_CHARS == 0) {
TextBuffer[NUM_CHARS] = 0;
KdPrint((" %s\n", TextBuffer));
}
}
KdPrint(("------------------------------------\n"));
}
VOID
PrintTime(
LPSTR Comment,
TimeStamp ConvertTime
)
/*++
Routine Description:
Print the specified time
Arguments:
Comment - Comment to print in front of the time
Time - Local time to print
Return Value:
None
--*/
{
KdPrint(( "%s", Comment ));
//
// If the time is infinite,
// just say so.
//
if ( ConvertTime.LowPart == 0x7FFFFFFF ) {
KdPrint(( "Infinite\n" ));
//
// Otherwise print it more clearly
//
} else {
KdPrint(("%lx %lx\n", ConvertTime.HighPart, ConvertTime.LowPart));
}
}
#endif // DBG
//
// Define transfer entry of loaded image.
//
typedef
VOID
(*PTRANSFER_ROUTINE) (
PLOADER_PARAMETER_BLOCK LoaderBlock
);
BOOLEAN
BlGetDriveSignature(
IN PCHAR Name,
OUT PULONG Signature
);
PVOID
BlLoadDataFile(
IN ULONG DeviceId,
IN PCHAR LoadDevice,
IN PCHAR SystemPath,
IN PUNICODE_STRING Filename,
IN MEMORY_TYPE MemoryType,
OUT PULONG FileSize
);
#if defined(REMOTE_BOOT)
BOOLEAN
BlIsDiskless(
VOID
);
#endif // defined(REMOTE_BOOT)
//
// Define local static data.
//
PCHAR ArcStatusCodeMessages[] = {
"operation was success",
"E2BIG",
"EACCES",
"EAGAIN",
"EBADF",
"EBUSY",
"EFAULT",
"EINVAL",
"EIO",
"EISDIR",
"EMFILE",
"EMLINK",
"ENAMETOOLONG",
"ENODEV",
"ENOENT",
"ENOEXEC",
"ENOMEM",
"ENOSPC",
"ENOTDIR",
"ENOTTY",
"ENXIO",
"EROFS",
};
//
// Diagnostic load messages
//
VOID
BlFatalError(
IN ULONG ClassMessage,
IN ULONG DetailMessage,
IN ULONG ActionMessage
);
VOID
BlBadFileMessage(
IN PCHAR BadFileName
);
VOID
BlpSetInverseMode(
IN BOOLEAN InverseOn
);
VOID
BlpSendEscape(
PCHAR Escape
);
ULONG
BlGetUserResponse(
IN ULONG XLocation,
IN ULONG YLocation,
IN BOOLEAN Hidden,
IN ULONG MaximumLength,
OUT PCHAR Response
);
ULONG
BlGetKeyWithBlink(
IN ULONG XLocation,
IN ULONG YLocation
);
ULONG
BlDoLogin ( );
VOID
BlDoLogoff(
VOID
);
//
// Define external static data.
//
BOOLEAN BlConsoleInitialized = FALSE;
ULONG BlConsoleOutDeviceId = 0;
ULONG BlConsoleInDeviceId = 0;
ULONG BlDcacheFillSize = 32;
extern BOOLEAN BlOutputDots;
ULONGLONG NetRebootParameter = (ULONGLONG)0;
UCHAR NetRebootFile[128];
BOOLEAN BlRebootSystem = FALSE;
ULONG BlVirtualBias = 0;
CHAR KernelFileName[8+1+3+1]="ntoskrnl.exe";
CHAR HalFileName[8+1+3+1]="hal.dll";
//
// Globals used during login. Mostly because it would be too many
// parameters to pass to BlDoLogin().
//
#define OUTGOING_MESSAGE_LENGTH 1024
#define INCOMING_MESSAGE_LENGTH 8192
#define TEMP_INCOMING_MESSAGE_LENGTH 1500
#define RECEIVE_TIMEOUT 5
#define RECEIVE_RETRIES 24
CHAR OutgoingMessageBuffer[OUTGOING_MESSAGE_LENGTH];
SIGNED_PACKET UNALIGNED * OutgoingSignedMessage;
CHAR IncomingMessageBuffer[INCOMING_MESSAGE_LENGTH];
SIGNED_PACKET UNALIGNED * IncomingSignedMessage;
CHAR TempIncomingMessage[TEMP_INCOMING_MESSAGE_LENGTH]; // used for reassembly
CredHandle CredentialHandle;
BOOLEAN CredentialHandleValid = FALSE;
CtxtHandle ClientContextHandle;
BOOLEAN ClientContextHandleValid = FALSE;
PSecPkgInfoA PackageInfo = NULL;
ARC_STATUS
BlInitStdio (
IN ULONG Argc,
IN PCHAR Argv[]
)
{
PCHAR ConsoleOutDevice;
PCHAR ConsoleInDevice;
ULONG Status;
if (BlConsoleInitialized) {
return ESUCCESS;
}
//
// Get the name of the console output device and open the device for
// write access.
//
ConsoleOutDevice = BlGetArgumentValue(Argc, Argv, "consoleout");
if (ConsoleOutDevice == NULL) {
return ENODEV;
}
Status = ArcOpen(ConsoleOutDevice, ArcOpenWriteOnly, &BlConsoleOutDeviceId);
if (Status != ESUCCESS) {
return Status;
}
//
// Get the name of the console input device and open the device for
// read access.
//
ConsoleInDevice = BlGetArgumentValue(Argc, Argv, "consolein");
if (ConsoleInDevice == NULL) {
return ENODEV;
}
Status = ArcOpen(ConsoleInDevice, ArcOpenReadOnly, &BlConsoleInDeviceId);
if (Status != ESUCCESS) {
return Status;
}
BlConsoleInitialized = TRUE;
return ESUCCESS;
}
extern BOOLEAN NetBoot;
NTSTATUS
UdpSendAndReceive(
IN PVOID SendBuffer,
IN ULONG SendBufferLength,
IN ULONG SendRemoteHost,
IN USHORT SendRemotePort,
IN ULONG SendRetryCount,
IN PVOID ReceiveBuffer,
IN ULONG ReceiveBufferLength,
OUT PULONG ReceiveRemoteHost,
OUT PUSHORT ReceiveRemotePort,
IN ULONG ReceiveTimeout,
IN ULONG ReceiveSignatureCount,
IN PCHAR ReceiveSignatures[],
IN ULONG ReceiveSequenceNumber
)
{
ULONG i, j;
ULONG length;
SIGNED_PACKET UNALIGNED * ReceiveHeader =
(SIGNED_PACKET UNALIGNED *)ReceiveBuffer;
#ifdef _TRACE_FUNC_
TraceFunc("UdpSendAndReceive( ");
DPRINT( OSC, ("ReceiveSequenceNumber=%u )\n", ReceiveSequenceNumber) );
#endif
//
// Try sending the packet SendRetryCount times, until we receive
// a response with the right signature, waiting ReceiveTimeout
// each time.
//
for (i = 0; i < SendRetryCount; i++) {
length = UdpSend(
SendBuffer,
SendBufferLength,
SendRemoteHost,
SendRemotePort);
if ( length != SendBufferLength ) {
DPRINT( ERROR, ("UdpSend only sent %d bytes, not %d\n", length, SendBufferLength) );
return STATUS_UNEXPECTED_NETWORK_ERROR;
}
ReReceive:
//
// NULL out the first 12 bytes in case we get shorter data.
//
memset(ReceiveBuffer, 0x0, 12);
length = UdpReceive(
ReceiveBuffer,
ReceiveBufferLength,
ReceiveRemoteHost,
ReceiveRemotePort,
ReceiveTimeout);
if ( length == 0 ) {
DPRINT( ERROR, ("UdpReceive timed out\n") );
continue;
}
//
// Make sure the signature is one of the ones we expect.
//
for (j = 0; j < ReceiveSignatureCount; j++) {
if (memcmp(ReceiveBuffer, ReceiveSignatures[j], 4) == 0) {
//
// Now make sure that the sequence number is correct,
// if asked to check (0 means don't check).
//
if ((ReceiveSequenceNumber == 0) ||
(ReceiveSequenceNumber == ReceiveHeader->SequenceNumber)) {
return STATUS_SUCCESS;
} else {
DPRINT( ERROR, ("UdpReceive expected seq %d, got %d\n",
ReceiveSequenceNumber, ReceiveHeader->SequenceNumber) );
}
}
}
DPRINT( ERROR, ("UdpReceive got wrong signature\n") );
//
// Don't UdpSend again just because we got a bad signature. Still need
// to respect the original ReceiveTimeout however!
//
goto ReReceive;
}
//
// We timed out.
//
return STATUS_IO_TIMEOUT;
}
//
// This routine signs and sends a message, waits for a response, and
// then verifies the signature on the response.
//
// It returns a positive number on success, 0 on a timeout, -1 if
// the server did not recognize the client, and -2 on other errors
// (which should be fixable by having the client re-login and
// re-transmit the request).
//
// NOTE: The data is sent as a UDP datagram. This requires a UDP header
// which the SendBuffer is assumed to have room for. In addition, we
// use 32 bytes for the "REQS", the total length, the sequence number,
// the sign length, and the sign itself (which is 16 bytes).
//
// For similar reasons, ReceiveBuffer is assumed to have 32 bytes of
// room at the beginning.
//
// Return values:
//
// 0 - nothing was received
// -1 - a timeout occurred
// -2 - unexpected network error, such as a sign/seal error
// -3 - receive buffer overflow
// positive number - the number of data bytes received
//
#define SIGN_HEADER_SIZE SIGNED_PACKET_DATA_OFFSET
ULONG CorruptionCounter = 1;
ULONG
SignSendAndReceive(
IN PVOID SendBuffer,
IN ULONG SendBufferLength,
IN ULONG SendRemoteHost,
IN USHORT SendRemotePort,
IN ULONG SendRetryCount,
IN ULONG SendSequenceNumber,
CtxtHandle ClientContextHandle,
IN PVOID ReceiveBuffer,
IN ULONG ReceiveBufferLength,
OUT PULONG ReceiveRemoteHost,
OUT PUSHORT ReceiveRemotePort,
IN ULONG ReceiveTimeout
)
{
SECURITY_STATUS SecStatus;
ULONG Status;
ULONG length;
SecBufferDesc SignMessage;
SecBuffer SigBuffers[2];
SIGNED_PACKET UNALIGNED * SendHeader =
(SIGNED_PACKET UNALIGNED *)((PCHAR)SendBuffer - SIGN_HEADER_SIZE);
SIGNED_PACKET UNALIGNED * ReceiveHeader =
(SIGNED_PACKET UNALIGNED *)((PCHAR)ReceiveBuffer - SIGN_HEADER_SIZE);
PCHAR ResultSigs[3];
USHORT FragmentNumber;
USHORT FragmentTotal;
FRAGMENT_PACKET UNALIGNED * TempFragment = (FRAGMENT_PACKET UNALIGNED *)TempIncomingMessage;
ULONG ResendCount = 0;
ULONG ReceivedDataBytes;
TraceFunc("SignSendAndReceive( )\n");
if ( LoggedIn )
{
SigBuffers[1].pvBuffer = SendHeader->Sign;
SigBuffers[1].cbBuffer = NTLMSSP_MESSAGE_SIGNATURE_SIZE;
SigBuffers[1].BufferType = SECBUFFER_TOKEN;
SigBuffers[0].pvBuffer = SendBuffer;
SigBuffers[0].cbBuffer = SendBufferLength;
SigBuffers[0].BufferType = SECBUFFER_DATA;
SignMessage.pBuffers = SigBuffers;
SignMessage.cBuffers = 2;
SignMessage.ulVersion = 0;
//
// Sign/seal a message
//
#ifndef ONLY_SIGN_MESSAGES
SecStatus = SealMessage(
&ClientContextHandle,
0,
&SignMessage,
0 );
if ( SecStatus != SEC_E_OK ) {
DPRINT( OSC, ("SealMessage: %lx\n", SecStatus) );
return (ULONG)-2;
}
#else
SecStatus = MakeSignature(
&ClientContextHandle,
0,
&SignMessage,
0 );
if ( SecStatus != SEC_E_OK ) {
DPRINT( OSC, ("MakeSignature: %lx\n", SecStatus) );
return (ULONG)-2;
}
#endif
#if 0
//
// Corrupt every fifth message.
//
if ((CorruptionCounter % 5) == 0) {
DPRINT( ERROR, ("INTENTIONALLY CORRUPTING A PACKET\n") );
((PCHAR)SendBuffer)[0] = '\0';
}
++CorruptionCounter;
#endif
memcpy(SendHeader->Signature, RequestSignedSignature, 4);
SendHeader->SignLength = NTLMSSP_MESSAGE_SIGNATURE_SIZE;
ResultSigs[0] = ResponseSignedSignature;
}
else
{
memcpy(SendHeader->Signature, RequestUnsignedSignature, 4);
SendHeader->SignLength = 0;
ResultSigs[0] = ResponseUnsignedSignature;
}
ResultSigs[1] = ErrorSignedSignature;
ResultSigs[2] = UnrecognizedClientSignature;
//
// Fill in our header before the SendBuffer. The sign has already been
// written in because we set up SigBuffers to point to the right place.
//
SendHeader->Length = SendBufferLength + SIGNED_PACKET_EMPTY_LENGTH;
SendHeader->SequenceNumber = SendSequenceNumber;
SendHeader->FragmentNumber = 1;
SendHeader->FragmentTotal = 1;
//
// Do an exchange with the server.
//
ReSend:
Status = UdpSendAndReceive(
SendHeader,
SendBufferLength + SIGN_HEADER_SIZE,
SendRemoteHost,
SendRemotePort,
SendRetryCount,
ReceiveHeader,
INCOMING_MESSAGE_LENGTH,
ReceiveRemoteHost,
ReceiveRemotePort,
ReceiveTimeout,
3, // signature count
ResultSigs, // signatures we look for
SendSequenceNumber); // response should have the same one
if (!NT_SUCCESS(Status)) {
if (Status == STATUS_IO_TIMEOUT) {
return (ULONG)-1;
} else {
return (ULONG)-2;
}
}
//
// Was it an error?
//
if (memcmp(ReceiveHeader->Signature, ErrorSignedSignature, 4) == 0) {
DPRINT( ERROR, ("SignSendAndReceive: got ERR response\n") );
return (ULONG)-2;
}
//
// Was the client not recognized by the server?
//
if (memcmp(ReceiveHeader->Signature, UnrecognizedClientSignature, 4) == 0) {
DPRINT( ERROR, ("SignSendAndReceive: got UNR response\n") );
return (ULONG)-1;
}
if (ReceiveHeader->Length < (ULONG)SIGNED_PACKET_EMPTY_LENGTH) {
DPRINT( ERROR, ("SignSendAndReceive: response is only %d bytes!\n", ReceiveHeader->Length) );
++ResendCount;
if (ResendCount > SendRetryCount) {
return (ULONG)-2;
}
goto ReSend;
}
//
// If there are fragments, then try to receive the rest of them.
//
if (ReceiveHeader->FragmentTotal != 1) {
//
// Make sure this is fragment 1 -- otherwise the first one
// was probably dropped and we should re-request it.
//
if (ReceiveHeader->FragmentNumber != 1) {
DPRINT( ERROR, ("UdpReceive got non-first fragment\n") );
++ResendCount;
if (ResendCount > SendRetryCount) {
return (ULONG)-1;
}
goto ReSend; // redoes the whole exchange.
}
FragmentTotal = ReceiveHeader->FragmentTotal;
ReceivedDataBytes = ReceiveHeader->Length - SIGNED_PACKET_EMPTY_LENGTH;
for (FragmentNumber = 1; FragmentNumber < FragmentTotal; FragmentNumber ++) {
ReReceive:
//
// NULL out the start of the receive buffer.
//
memset(TempFragment, 0x0, sizeof(FRAGMENT_PACKET));
length = UdpReceive(
TempFragment,
TEMP_INCOMING_MESSAGE_LENGTH,
ReceiveRemoteHost,
ReceiveRemotePort,
ReceiveTimeout);
if ( length == 0 ) {
DPRINT( ERROR, ("UdpReceive timed out\n") );
++ResendCount;
if (ResendCount > SendRetryCount) {
return (ULONG)-1;
}
goto ReSend; // redoes the whole exchange.
}
//
// Make sure the signature is one of the ones we expect -- only
// worry about the ResultSignature because we won't get an
// error response on any fragment besides the first.
//
// Also make sure that the
// sequence number is correct, if asked to check (0 means don't
// check). If it's not, then go back and wait for another packet.
//
if ((TempFragment->Length < (ULONG)FRAGMENT_PACKET_EMPTY_LENGTH) ||
(memcmp(TempFragment->Signature, ResultSigs[0], 4) != 0) ||
((SendSequenceNumber != 0) &&
(SendSequenceNumber != TempFragment->SequenceNumber))) {
DPRINT( ERROR, ("UdpReceive got wrong signature or sequence number\n") );
goto ReReceive;
}
//
// Check that the fragment number is also correct.
//
if (TempFragment->FragmentNumber != FragmentNumber+1) {
DPRINT( ERROR, ("UdpReceive got wrong fragment number\n") );
goto ReReceive;
}
//
// Make sure that this fragment won't overflow the buffer.
//
if (ReceivedDataBytes + (TempFragment->Length - FRAGMENT_PACKET_EMPTY_LENGTH) >
ReceiveBufferLength) {
return (ULONG)-3;
}
//
// This is the correct fragment, so copy it over and loop
// to the next fragment.
//
memcpy(
&ReceiveHeader->Data[ReceivedDataBytes],
TempFragment->Data,
TempFragment->Length - FRAGMENT_PACKET_EMPTY_LENGTH);
ReceivedDataBytes += TempFragment->Length - FRAGMENT_PACKET_EMPTY_LENGTH;
}
//
// When we are done getting everything, modify the length in the
// incoming packet to match the total length (currently it will
// just have the length of the first fragment.
//
ReceiveHeader->Length = ReceivedDataBytes + SIGNED_PACKET_EMPTY_LENGTH;
DPRINT( OSC, ("Got packet with %d fragments, total length %d\n",
FragmentTotal, ReceiveHeader->Length) );
}
//
// Make sure the sign is the length we expect!!
//
if (LoggedIn == TRUE &&
ReceiveHeader->SignLength != NTLMSSP_MESSAGE_SIGNATURE_SIZE)
{
DPRINT( ERROR, ("SignSendAndReceive: signature length is %d bytes!\n", ReceiveHeader->SignLength) );
++ResendCount;
if (ResendCount > SendRetryCount) {
return (ULONG)-2;
}
goto ReSend;
}
else if ( LoggedIn == FALSE &&
ReceiveHeader->SignLength != 0 )
{
DPRINT( ERROR, ("SignSendAndReceive: signature length is not 0 bytes (=%u)!\n", ReceiveHeader->SignLength) );
++ResendCount;
if (ResendCount > SendRetryCount) {
return (ULONG)-2;
}
goto ReSend;
}
if ( LoggedIn )
{
SigBuffers[1].pvBuffer = ReceiveHeader->Sign;
SigBuffers[1].cbBuffer = NTLMSSP_MESSAGE_SIGNATURE_SIZE;
SigBuffers[1].BufferType = SECBUFFER_TOKEN;
SigBuffers[0].pvBuffer = ReceiveBuffer;
SigBuffers[0].cbBuffer = ReceiveHeader->Length - SIGNED_PACKET_EMPTY_LENGTH;
SigBuffers[0].BufferType = SECBUFFER_DATA;
SignMessage.pBuffers = SigBuffers;
SignMessage.cBuffers = 2;
SignMessage.ulVersion = 0;
#ifndef ONLY_SIGN_MESSAGES
SecStatus = UnsealMessage(
&ClientContextHandle,
&SignMessage,
0,
0 );
if ( SecStatus != SEC_E_OK ) {
DPRINT( ERROR, ("UnsealMessage: %lx\n", SecStatus) );
return (ULONG)-2;
}
#else
SecStatus = VerifySignature(
&ClientContextHandle,
&SignMessage,
0,
0 );
if ( SecStatus != SEC_E_OK ) {
DPRINT( ERROR, ("VerifySignature: %lx\n", SecStatus) );
return (ULONG)-2;
}
#endif
}
//
// Sucess, so return.
//
return (ReceiveHeader->Length - SIGNED_PACKET_EMPTY_LENGTH);
}
#if defined(REMOTE_BOOT)
//
// write secret based on the CREATE_DATA structure
//
VOID
BlWriteSecretFromCreateData(
PCREATE_DATA CreateData
)
{
ULONG FileId;
RI_SECRET Secret;
ARC_STATUS ArcStatus;
UNICODE_STRING TmpNtPassword;
CHAR TmpLmOwfPassword[LM_OWF_PASSWORD_SIZE];
CHAR TmpNtOwfPassword[NT_OWF_PASSWORD_SIZE];
TraceFunc("BlWriteSecretFromCreateData( )\n");
//
// Write the secret. This is the secret for the machine account
// created by BINL, not for the user that logged on.
//
if (BlOpenRawDisk(&FileId) == ESUCCESS) {
if (BlCheckForFreeSectors(FileId) == ESUCCESS) {
TmpNtPassword.Length = (USHORT)CreateData->UnicodePasswordLength;
TmpNtPassword.MaximumLength = sizeof(CreateData->UnicodePassword);
TmpNtPassword.Buffer = CreateData->UnicodePassword;
BlOwfPassword(
CreateData->Password,
&TmpNtPassword,
TmpLmOwfPassword,
TmpNtOwfPassword);
BlInitializeSecret(
CreateData->Domain,
CreateData->Name,
TmpLmOwfPassword,
TmpNtOwfPassword,
NULL, // no password 2
NULL, // no password 2
CreateData->Sid,
&Secret);
//
// Copy the cleartext UnicodePassword into the reserved
// section. The reserved section has the length followed
// by the data (up to 32 WCHARs).
//
(*(ULONG UNALIGNED *)(Secret.Reserved)) = CreateData->UnicodePasswordLength;
RtlCopyMemory(
Secret.Reserved + sizeof(ULONG),
CreateData->UnicodePassword,
CreateData->UnicodePasswordLength);
ArcStatus = BlWriteSecret(FileId, &Secret);
if (ArcStatus != ESUCCESS) {
DPRINT( ERROR, ("BlWriteSecret: status is %d\n", ArcStatus) );
}
}
BlCloseRawDisk(FileId);
}
}
#endif // defined(REMOTE_BOOT)
//
// Retrieve next screen
//
BOOL
BlRetrieveScreen(
ULONG *SequenceNumber,
PCHAR OutMessage,
PCHAR InMessage
)
{
ARC_STATUS Status;
ULONG OutMessageLength = strlen( OutMessage );
ULONG InMessageLength;
PCREATE_DATA CreateData;
TraceFunc("BlRetrieveScreen( )\n");
// make sure we don't over flow the output buffer
if ( OutMessageLength > 1023 ) {
OutMessageLength = 1023;
OutMessage[OutMessageLength] = '\0';
}
++(*SequenceNumber);
if ( *SequenceNumber > 0x2000 )
{
*SequenceNumber = 1;
}
if (!LoggedIn)
{
#ifdef _TRACE_FUNC_
TraceFunc( "Sending RQU ");
DPRINT( OSC, ("(%u)...\n", *SequenceNumber) );
#endif
memcpy( OutgoingSignedMessage->Data, OutMessage, OutMessageLength );
Status = SignSendAndReceive(
OutgoingSignedMessage->Data,
OutMessageLength,
NetServerIpAddress,
BINL_PORT,
RECEIVE_RETRIES,
*SequenceNumber,
ClientContextHandle,
IncomingSignedMessage->Data,
INCOMING_MESSAGE_LENGTH - SIGN_HEADER_SIZE,
&RemoteHost,
&RemotePort,
RECEIVE_TIMEOUT);
}
else
{
#ifdef _TRACE_FUNC_
TraceFunc( "Sending Seal/Signed REQS " );
DPRINT( OSC, ("(%u)...\n", *SequenceNumber) );
#endif
while (TRUE)
{
memcpy( OutgoingSignedMessage->Data, OutMessage, OutMessageLength );
Status = SignSendAndReceive(
OutgoingSignedMessage->Data,
OutMessageLength,
NetServerIpAddress,
BINL_PORT,
RECEIVE_RETRIES,
*SequenceNumber,
ClientContextHandle,
IncomingSignedMessage->Data,
INCOMING_MESSAGE_LENGTH - SIGN_HEADER_SIZE,
&RemoteHost,
&RemotePort,
RECEIVE_TIMEOUT);
if ((Status == 0) || (Status == (ULONG)-2))
{
DPRINT( OSC, ("Attempting to re-login\n") );
//
// We assume that the server has dropped the current login
// and don't bother calling BlDoLogoff();
//
LoggedIn = FALSE;
Status = BlDoLogin( );
*SequenceNumber = 1;
if (Status == STATUS_SUCCESS)
{
DPRINT( ERROR, ("Successfully re-logged in\n") );
memcpy(OutgoingSignedMessage->Data, OutMessage, OutMessageLength);
LoggedIn = TRUE;
continue;
}
else
{
DPRINT( ERROR, ("ERROR - could not re-login, %x\n", Status) );
//DbgBreakPoint();
//
// Call ourselves again, but request the LoginErr screen which
// is 00004e28.
//
strcpy( OutMessage, "00004e28\n" );
return BlRetrieveScreen( SequenceNumber, OutMessage, InMessage );
}
}
else if (Status == (ULONG)-1)
{
DPRINT( ERROR, ("Unrecognized, requested TIMEOUT screen\n") );
//
// We assume that the server has dropped the current login
//
LoggedIn = FALSE;
//
// Increase the sequence number for the new screen request,
// don't worry about wrapping since the session will die soon.
//
++(*SequenceNumber);
//
// Call ourselves again, but request the TIMEOUT screen.
//
strcpy( OutMessage, "00004E2A\n" );
return BlRetrieveScreen( SequenceNumber, OutMessage, InMessage );
}
else if (Status == (ULONG)-3)
{
DPRINT( ERROR, ("Unrecognized, requested TOO LONG screen\n") );
//
// This screen is a fatal error, so don't worry about
// staying logged in.
//
LoggedIn = FALSE;
//
// Increase the sequence number for the new screen request,
// don't worry about wrapping since the session will die soon.
//
++(*SequenceNumber);
//
// Call ourselves again, but request the TIMEOUT screen.
//
strcpy( OutMessage, "00004E53\n" );
return BlRetrieveScreen( SequenceNumber, OutMessage, InMessage );
}
else
{
break;
}
}
}
//
// NULL-terminate it.
//
IncomingSignedMessage->Data[IncomingSignedMessage->Length - SIGNED_PACKET_EMPTY_LENGTH] = '\0';
strcpy( InMessage, IncomingSignedMessage->Data );
InMessageLength = strlen(InMessage);
// DumpBuffer( InMessage, strlen(InMessage) );
//
// If we got an just an ACCT response, with no screen data, that means a
// restart is happening.
//
if (memcmp(InMessage, "ACCT", 4) == 0)
{
CreateData = (PCREATE_DATA) IncomingSignedMessage->Data;
#if defined(REMOTE_BOOT)
//
// If doing remote BOOT (as opposed to install) enable this.
//
BlWriteSecretFromCreateData( CreateData );
#endif // defined(REMOTE_BOOT)
DPRINT( OSC, ("Trying to reboot to <%s>\n", CreateData->NextBootfile) );
strcpy(NextBootfile, CreateData->NextBootfile);
strcpy(SifFile, CreateData->SifFile);
DoSoftReboot = TRUE;
return FALSE; // exit message loop
}
//
// If we got a screen with an ACCT response after the screen data,
// should write the secret and do a soft reboot. In this situation
// InMessageLength will only include the screen data itself, but
// IncomingSignedMessage->Length will include the whole thing.
//
if ((IncomingSignedMessage->Length - SIGNED_PACKET_EMPTY_LENGTH) ==
(InMessageLength + 1 + sizeof(CREATE_DATA))) {
CreateData = (PCREATE_DATA) (InMessage + InMessageLength + 1);
if (memcmp(CreateData->Id, "ACCT", 4) == 0) {
#if defined(REMOTE_BOOT)
//
// If doing remote BOOT (as opposed to install) enable this.
//
BlWriteSecretFromCreateData( CreateData );
#endif // defined(REMOTE_BOOT)
DPRINT( OSC, ("INSTALL packet setting up reboot to <%s>\n", CreateData->NextBootfile) );
strcpy(NextBootfile, CreateData->NextBootfile);
strcpy(SifFile, CreateData->SifFile);
DoSoftReboot = TRUE;
//
// Don't return FALSE, because we still want to show the INSTALL
// screen. NextBootFile/SifFile/DoSoftReboot won't be modified by
// that so we will do a proper soft reboot when the time comes.
//
}
}
// Special-case server tells us to LAUNCH a file
if (memcmp(InMessage, "LAUNCH", 6) == 0) {
CreateData = (PCREATE_DATA) (IncomingSignedMessage->Data + 7);
DPRINT( OSC, ("Trying to launch <%s>\n", CreateData->NextBootfile) );
strcpy(NextBootfile, CreateData->NextBootfile);
strcpy(SifFile, CreateData->SifFile);
if (CreateData->RebootParameter == OSC_REBOOT_COMMAND_CONSOLE_ONLY) {
NetRebootParameter = NET_REBOOT_COMMAND_CONSOLE_ONLY;
} else if (CreateData->RebootParameter == OSC_REBOOT_ASR) {
NetRebootParameter = NET_REBOOT_ASR;
}
DoSoftReboot = TRUE;
return FALSE; // exit message loop
}
// Special-case REBOOT - server told us to reboot.
if (memcmp(InMessage, "REBOOT", 6) == 0)
{
return FALSE; // exit message loop
}
#if defined(REMOTE_BOOT)
// Special-case GETCREATE - should reboot after we get this
if (memcmp(InMessage, "GETCREATE", 9) == 0) {
CreateData = (PCREATE_DATA) (IncomingSignedMessage->Data + 10);
BlWriteSecretFromCreateData( CreateData );
//
// We were soft rebooted to, and it told us where to go back to
// in NetRebootFile.
//
NetRebootParameter = NET_REBOOT_SECRET_VALID;
strcpy(NextBootfile, NetRebootFile);
SifFile[0] = '\0';
DoSoftReboot = TRUE;
return FALSE; // exit message loop
}
// Special-case REPLDONE - write the secret, then do normal processing.
// The secret is sent as binary data immediately after the screen.
//
// This check for "NAME REPLDONE" is obsolete now that we use OSCML.
//
if (memcmp(InMessage, "NAME REPLDONE", 13) == 0) {
CreateData = (PCREATE_DATA) (InMessage + strlen(InMessage) + 1);
BlWriteSecretFromCreateData( CreateData );
//
// Set this so the user won't be sent back to us to logon for
// te disk having changed.
//
NetRebootParameter = NET_REBOOT_SECRET_VALID;
strcpy(NextBootfile, CreateData->NextBootfile);
SifFile[0] = '\0';
DoSoftReboot = TRUE;
}
#endif // defined(REMOTE_BOOT)
return TRUE; // stay in message loop
}
ARC_STATUS
BlOsLoader (
IN ULONG Argc,
IN PCHAR Argv[],
IN PCHAR Envp[]
)
/*++
Routine Description:
This is the main routine that controls the loading of the NT operating
system on an ARC compliant system. It opens the system partition,
the boot partition, the console input device, and the console output
device. The NT operating system and all its DLLs are loaded and bound
together. Control is then transfered to the loaded system.
Arguments:
Argc - Supplies the number of arguments that were provided on the
command that invoked this program.
Argv - Supplies a pointer to a vector of pointers to null terminated
argument strings.
Envp - Supplies a pointer to a vector of pointers to null terminated
environment variables.
Return Value:
EBADF is returned if the specified OS image cannot be loaded.
--*/
{
CHAR OutputBuffer[256];
ULONG Count;
ARC_STATUS Status;
SECURITY_STATUS SecStatus; // NOTE: This is a SHORT, so not an NTSTATUS failure on error
ULONG PackageCount;
PVOID LoaderBase;
//
// Initialize the OS loader console input and output.
//
Status = BlInitStdio(Argc, Argv);
if (Status != ESUCCESS) {
return Status;
}
//
// Initialize the boot debugger for platforms that directly load the
// OS Loader.
//
// N.B. This must occur after the console input and output have been
// initialized so debug messages can be printed on the console
// output device.
//
#if defined(_ALPHA_) || defined(ARCI386) || defined(_IA64_)
//
// If the program memory descriptor was found, then compute the base
// address of the OS Loader for use by the debugger.
//
LoaderBase = &__ImageBase;
BlPrint(TEXT("about to init debugger...\r\n"));
//
// Initialize traps and the boot debugger.
//
#if defined(ENABLE_LOADER_DEBUG)
#if defined(_ALPHA_)
BdInitializeTraps();
#endif
BdInitDebugger("oschoice.exe", LoaderBase, ENABLE_LOADER_DEBUG);
#else
BdInitDebugger("oschoice.exe", LoaderBase, NULL);
#endif
#endif
BlPrint(TEXT("back from initializing debugger...\r\n"));
#if DBG
// NetDebugFlag |= 0x147;
#endif
TraceFunc("BlOsLoader( )\n");
//
// Announce OS Loader.
//
BlpClearScreen();
#if 1
#ifdef UNICODE
BlPrint(OsLoaderVersionW);
#else
BlPrint(OsLoaderVersion);
#endif
#else
strcpy(&OutputBuffer[0], OsLoaderVersion);
ArcWrite(BlConsoleOutDeviceId,
&OutputBuffer[0],
strlen(&OutputBuffer[0]),
&Count);
#endif
//
// Initialize the memory descriptor list, the OS loader heap, and the
// OS loader parameter block.
//
#if 0
//
// bugbug: we already do this in SuMain()
//
BlPrint(TEXT("about to BlMemoryInitialize...\r\n"));
Status = BlMemoryInitialize();
if (Status != ESUCCESS) {
BlFatalError(LOAD_HW_MEM_CLASS,
DIAG_BL_MEMORY_INIT,
LOAD_HW_MEM_ACT);
goto LoadFailed;
}
#endif
//
// Initialize the network.
//
NetGetRebootParameters(&NetRebootParameter, NetRebootFile, NULL, NULL, NULL, NULL, NULL, TRUE);
DPRINT( OSC, ("Initializing the network\n") );
Status = NetInitialize();
if (Status != ESUCCESS) {
return Status;
}
#ifndef EFI
//
// Get ourselves a UDP port.
//
LocalPort = UdpAssignUnicastPort();
DPRINT( OSC, ("Using port %x\n", LocalPort) );
#endif
//
// Initialize the security package.
//
DPRINT( OSC, ("Initializing security package\n") );
SecStatus = EnumerateSecurityPackagesA( &PackageCount, &PackageInfo );
if (SecStatus == SEC_E_OK) {
DPRINT( OSC, ("NTLMSSP: PackageCount: %ld\n", PackageCount) );
DPRINT( OSC, ("Name: %s Comment: %s\n", PackageInfo->Name, PackageInfo->Comment) );
DPRINT( OSC, ("Cap: %ld Version: %ld RPCid: %ld MaxToken: %ld\n\n",
PackageInfo->fCapabilities,
PackageInfo->wVersion,
PackageInfo->wRPCID,
PackageInfo->cbMaxToken) );
} else {
DPRINT( ERROR, ("NTLMSSP: Enumerate failed, %d\n", SecStatus) );
}
//
// Get info about the security packages.
//
SecStatus = QuerySecurityPackageInfoA( NTLMSP_NAME_A, &PackageInfo );
if ( SecStatus != SEC_E_OK ) {
DPRINT( ERROR, ("QuerySecurityPackageInfo failed %d", SecStatus) );
return SecStatus;
}
//
// Detect the Hal type
//
if (!BlDetectHal()) {
//
// just fall through if it fails, it's not the end of the world
//
HalType[0] = '\0';
HalDescription[0] = '\0';
DPRINT( ERROR, ("BlDetectHal failed.\n") );
}
//
// Process screens, loggons, etc... we come back after a "REBOOT"
// was indicated.
//
BlMainLoop( );
//
// Inform boot debugger that the boot phase is complete.
//
// N.B. This is x86 only for now.
//
#if defined(_X86_)
DbgUnLoadImageSymbols(NULL, (PVOID)-1, 0);
#endif
#ifdef EFI
BlEfiSetAttribute( DEFATT );
#else
BlpSendEscape(";0;37;40m");
#endif
BlpSetInverseMode( FALSE );
BlpClearScreen();
BlPrint(TEXT("Waiting for reboot...\n"));
#ifndef EFI
HW_CURSOR(1,0);
#endif
if (DoSoftReboot) {
Status = NetSoftReboot(
NextBootfile,
NetRebootParameter,
NULL, // reboot file
SifFile,
UserName,
DomainName,
Password,
AdministratorPassword); // this only returns on an error
} else {
DPRINT( OSC, ("calling ArcRestart()\n") );
ArcRestart();
}
BlPrint(TEXT("Reboot failed... Press ALT+CTL+DEL to reboot.\n"));
//LoadFailed:
return Status;
}
//
//
//
ARC_STATUS
BlProcessLogin(
PCHAR OutgoingMessage )
{
//
// If this is the login screen, remember some of the inputs
// ourselves.
//
ARC_STATUS Status;
UNICODE_STRING TmpNtPassword;
PCHAR AtSign;
int i;
TraceFunc("BlProcessLogin( )\n");
//
// We could be trying to log another person in so log off the
// current user.
//
if ( LoggedIn == TRUE )
{
BlDoLogoff();
LoggedIn = FALSE;
}
DPRINT( OSC, ("Login info: Domain <%s>, User <%s>, Password<%s>\n", DomainName, UserName, "*") );
//
// Do a quick conversion of the password to Unicode.
//
TmpNtPassword.Length = strlen(Password) * sizeof(WCHAR);
TmpNtPassword.MaximumLength = sizeof(UnicodePassword);
TmpNtPassword.Buffer = UnicodePassword;
for (i = 0; i < sizeof(Password); i++) {
UnicodePassword[i] = (WCHAR)(Password[i]);
}
BlOwfPassword(Password, &TmpNtPassword, LmOwfPassword, NtOwfPassword);
Status = BlDoLogin( );
DPRINT( OSC, ("Login returned: %x\n", Status) );
return Status;
}
//
//
//
VOID
BlMainLoop(
)
{
ULONG SequenceNumber;
int len;
PUCHAR psz;
PUCHAR pch;
UCHAR OutgoingMessage[1024];
PUCHAR IncomingMessage;
TraceFunc("BlMainLoop( )\n");
//
// These all point into our single outgoing and incoming buffers.
//
OutgoingSignedMessage = (SIGNED_PACKET UNALIGNED *)OutgoingMessageBuffer;
IncomingSignedMessage = (SIGNED_PACKET UNALIGNED *)IncomingMessageBuffer;
DomainName[0] = '\0';
UserName[0] = '\0';
Password[0] = '\0';
SequenceNumber = 0;
//
// Ask the server for the initial screen
//
#if defined(REMOTE_BOOT)
if (NetRebootParameter == NET_REBOOT_WRITE_SECRET_ONLY) {
strcpy( OutgoingMessage, "LOGIN\n" ); // first screen is logon.
} else
#endif // defined(REMOTE_BOOT)
{
strcpy( OutgoingMessage, "\n" ); // first screen name is <blank>.
}
IncomingMessage = IncomingSignedMessage->Data;
SpecialAction = ACTION_NOP;
while ( SpecialAction != ACTION_REBOOT )
{
CHAR LastKey;
//
// Retrieve next screen
//
#if 0
IF_DEBUG(OSC) {
DPRINT( OSC, ("Dumping OutgoingingMessage buffer:\r\n" ) );
DumpBuffer( (PVOID)OutgoingMessage, 256 );
}
#endif
if (!BlRetrieveScreen( &SequenceNumber, OutgoingMessage, IncomingMessage ) )
break;
//
// Process the screen and get user input
//
LastKey = BlProcessScreen( IncomingMessage, OutgoingMessage );
DPRINT( OSC, ("LastKey = 0x%02x\nAction = %u\nResults:\n%s<EOM>\n",
LastKey, SpecialAction, OutgoingMessage) );
switch ( SpecialAction )
{
case ACTION_LOGIN:
DPRINT( OSC, ("[SpecialAction] Logging in\n") );
if ( STATUS_SUCCESS == BlProcessLogin( OutgoingMessage ) )
{
#if defined(REMOTE_BOOT)
//
// If we are only logging on for machine replacement, then request
// the GETCREATE screen -- we will reboot once we get the
// response.
//
if (NetRebootParameter == NET_REBOOT_WRITE_SECRET_ONLY) {
//
// Find the current screen name (probably "CHOICE") and
// replace it with "GETCREATE").
//
ULONG OriginalLen = strlen(OutgoingMessage) + 1; // include the '\0'
ULONG CurrentScreenLen = (strchr(OutgoingMessage, '\n') - OutgoingMessage);
ULONG GetCreateLen = strlen("GETCREATE");
if (CurrentScreenLen != GetCreateLen) {
memmove(OutgoingMessage + GetCreateLen,
OutgoingMessage + CurrentScreenLen,
OriginalLen - CurrentScreenLen);
}
memcpy(OutgoingMessage, "GETCREATE", GetCreateLen);
}
#endif // defined(REMOTE_BOOT)
DPRINT( OSC, ("Validate Results are still the same:\n%s<EOM>\n",
OutgoingMessage) );
LoggedIn = TRUE;
SequenceNumber = 0;
//
// If the welcome screen was processed, then add some extra
// outgoing predetermined variables.
//
// Add NIC address
//
// Convert NIC address 0x00a0c968041c to a string
//
//
// Make sure the outgoing has a \n after the screen name
//
if ( OutgoingMessage[ strlen(OutgoingMessage) - 1 ] != '\n' )
{
strcat( OutgoingMessage, "\n" );
}
strcat( OutgoingMessage, "MAC=" );
len = 6;
psz = &OutgoingMessage[ strlen( OutgoingMessage ) ];
pch = (PCHAR) NetLocalHardwareAddress;
while (len--) {
UCHAR c = *(pch++);
*(psz++) = rghex [(c >> 4) & 0x0F] ;
*(psz++) = rghex [c & 0x0F];
}
*psz = '\0'; // terminate
//
// Add the Guid
//
pch = NULL;
len = 0;
GetGuid(&pch, &len);
if ((len != 0) && (pch!=NULL)) {
strcat( OutgoingMessage, "\nGUID=" );
psz = &OutgoingMessage[ strlen( OutgoingMessage ) ];
while (len--) {
UCHAR c = *(pch++);
*(psz++) = rghex [(c >> 4) & 0x0F] ;
*(psz++) = rghex [c & 0x0F];
}
*psz = '\0'; // terminate
}
//
// if we detected the HAL, specify it here
//
if (HalType[0] != '\0') {
strcat( OutgoingMessage, "\nHALTYPE=" );
strcat( OutgoingMessage, HalType );
if (HalDescription[0] != '\0') {
strcat( OutgoingMessage, "\nHALTYPEDESCRIPTION=" );
strcat( OutgoingMessage, HalDescription );
}
}
//
// Add the machine type
//
#if defined(_ALPHA_)
strcat( OutgoingMessage, "\nMACHINETYPE=Alpha\n" ); // add machinetype
#else
#if defined(_IA64_)
strcat( OutgoingMessage, "\nMACHINETYPE=ia64\n" ); // add machinetype
#else // INTEL
strcat( OutgoingMessage, "\nMACHINETYPE=i386\n" ); // add machinetype
#endif // _IA64_
#endif
#if defined(REMOTE_BOOT)
//
// If we are diskless, tell BINL.
//
if (BlIsDiskless()) {
strcat( OutgoingMessage, "DISKLESS=1\n" );
}
#endif // defined(REMOTE_BOOT)
//
// Tell BINL to verify the domain, because otherwise
// the SSPI package on the server will allow the login
// to succeed with an invalid domain. BINL will delete
// this variable from the client state on the server
// once it does the domain check.
//
strcat( OutgoingMessage, "CHECKDOMAIN=1\n" );
}
else
{
//
// Goto the Login Error Screen which is
// 00004e28.
//
strcpy( OutgoingMessage, "00004e28\n" );
LoggedIn = FALSE;
}
break;
}
}
//
// If we logged on successfully, then log off.
//
if (LoggedIn)
{
BlDoLogoff();
}
}
//
//
//
ULONG
BlDoLogin ( )
{
ARC_STATUS Status;
SECURITY_STATUS SecStatus;
SecBufferDesc NegotiateDesc;
SecBuffer NegotiateBuffer;
SecBufferDesc ChallengeDesc;
SecBuffer ChallengeBuffer;
SecBufferDesc AuthenticateDesc;
SecBuffer AuthenticateBuffer;
ULONG ContextAttributes;
SEC_WINNT_AUTH_IDENTITY_A AuthIdentity;
TimeStamp Lifetime;
PCHAR ResultSigs[2];
UCHAR FlipServerList[MAX_FLIP_SERVER_COUNT * 4];
ULONG FlipServerCount;
ULONG CurFlipServer;
UCHAR OwfPasswords[LM_OWF_PASSWORD_SIZE + NT_OWF_PASSWORD_SIZE];
PLOGIN_PACKET OutgoingLoginMessage;
PLOGIN_PACKET IncomingLoginMessage;
OutgoingLoginMessage = (LOGIN_PACKET *) OutgoingMessageBuffer;
IncomingLoginMessage = (LOGIN_PACKET *) IncomingMessageBuffer;
TraceFunc("BlDoLogin( )\n");
//
// Delete both contexts if needed.
//
if (ClientContextHandleValid) {
SecStatus = DeleteSecurityContext( &ClientContextHandle );
ClientContextHandleValid = FALSE;
}
if (CredentialHandleValid) {
SecStatus = FreeCredentialsHandle( &CredentialHandle );
CredentialHandleValid = FALSE;
}
//
// Acquire a credential handle for the client side. The password
// we supply is the LM OWF password and the NT OWF password
// concatenated together.
//
memcpy( OwfPasswords, LmOwfPassword, LM_OWF_PASSWORD_SIZE );
memcpy( OwfPasswords+LM_OWF_PASSWORD_SIZE, NtOwfPassword, NT_OWF_PASSWORD_SIZE );
RtlZeroMemory( &AuthIdentity, sizeof(AuthIdentity) );
AuthIdentity.Domain = DomainName;
AuthIdentity.User = UserName;
AuthIdentity.Password = OwfPasswords;
#if 0
IF_DEBUG(OSC) {
DPRINT( OSC, ("Dumping OwfPasswords:\r\n") );
DumpBuffer( AuthIdentity.Password, LM_OWF_PASSWORD_SIZE+NT_OWF_PASSWORD_SIZE );
}
#endif
DPRINT( OSC, ("About to AcquireCredentialsHandle\n") );
SecStatus = AcquireCredentialsHandleA(
NULL, // New principal
NTLMSP_NAME_A, // Package Name
SECPKG_CRED_OUTBOUND | SECPKG_CRED_OWF_PASSWORD,
NULL,
&AuthIdentity,
NULL,
NULL,
&CredentialHandle,
&Lifetime );
if ( SecStatus != SEC_E_OK ) {
DPRINT( ERROR, ("AcquireCredentialsHandle failed: %s ", SecStatus) );
return SecStatus;
}
DPRINT( OSC, ("CredentialHandle: 0x%lx 0x%lx ",
CredentialHandle.dwLower, CredentialHandle.dwUpper) );
CredentialHandleValid = TRUE;
//
// Get the NegotiateMessage (ClientSide)
//
NegotiateDesc.ulVersion = 0;
NegotiateDesc.cBuffers = 1;
NegotiateDesc.pBuffers = &NegotiateBuffer;
NegotiateBuffer.cbBuffer = PackageInfo->cbMaxToken;
NegotiateBuffer.BufferType = SECBUFFER_TOKEN;
NegotiateBuffer.pvBuffer = OutgoingLoginMessage->Data;
SecStatus = InitializeSecurityContextA(
&CredentialHandle,
NULL, // No Client context yet
NULL, // No target name needed
ISC_REQ_SEQUENCE_DETECT,
0, // Reserved 1
SECURITY_NATIVE_DREP,
NULL, // No initial input token
0, // Reserved 2
&ClientContextHandle,
&NegotiateDesc,
&ContextAttributes,
&Lifetime );
if ( (SecStatus != SEC_E_OK) && (SecStatus != SEC_I_CONTINUE_NEEDED) ) {
DPRINT( ERROR, ("InitializeSecurityContext (negotiate): %d" , SecStatus) );
return SecStatus;
}
ClientContextHandleValid = TRUE;
#if 0
IF_DEBUG(OSC) {
KdPrint(( "\n\nNegotiate Message:\n" ));
KdPrint(( "ClientContextHandle: 0x%lx 0x%lx Attributes: 0x%lx ",
ClientContextHandle.dwLower, ClientContextHandle.dwUpper,
ContextAttributes ));
PrintTime( "Lifetime: ", Lifetime );
DumpBuffer( NegotiateBuffer.pvBuffer, NegotiateBuffer.cbBuffer );
}
#endif
//
// Send the negotiate buffer to the server and wait for a response.
//
memcpy(OutgoingLoginMessage->Signature, NegotiateSignature, 4);
OutgoingLoginMessage->Length = NegotiateBuffer.cbBuffer;
TraceFunc("");
DPRINT( OSC, ("Sending NEG...\n") );
ResultSigs[0] = ChallengeSignature;
ResultSigs[1] = NegativeAckSignature;
#if 0
IF_DEBUG(OSC) {
KdPrint(( "\n\nNegotiate Message Outgoing Packet:\n" ));
DumpBuffer( OutgoingLoginMessage, NegotiateBuffer.cbBuffer + LOGIN_PACKET_DATA_OFFSET );
}
#endif
Status = UdpSendAndReceive(
OutgoingLoginMessage,
NegotiateBuffer.cbBuffer + LOGIN_PACKET_DATA_OFFSET,
NetServerIpAddress,
BINL_PORT,
5, // retry count
IncomingLoginMessage,
INCOMING_MESSAGE_LENGTH,
&RemoteHost,
&RemotePort,
2, // receive timeout
2, // number of signatures
ResultSigs, // signature we are looking for
0); // sequence number (0 means don't check)
if ( !NT_SUCCESS(Status) ) {
DPRINT( ERROR, ("UdpSendAndReceive status is %x\n", Status) );
return Status;
}
//
// If the response was a NAK, then fail immediately.
//
if (memcmp(IncomingLoginMessage->Signature, NegativeAckSignature, 4) == 0) {
DPRINT( ERROR, ("Received NAK from server\n") );
return STATUS_LOGON_FAILURE;
}
#if 0
IF_DEBUG(OSC) {
KdPrint(( "\n\nNegotiate Message Incoming Packet: %d %d %d %d\n",
IncomingLoginMessage->Data,
IncomingLoginMessage->Length,
IncomingLoginMessage->Signature,
IncomingLoginMessage->Status ));
DumpBuffer( IncomingLoginMessage->Data, IncomingLoginMessage->Length );
}
#endif
//
// Get the AuthenticateMessage (ClientSide)
//
AuthenticateDesc.ulVersion = 0;
AuthenticateDesc.cBuffers = 1;
AuthenticateDesc.pBuffers = &AuthenticateBuffer;
AuthenticateBuffer.cbBuffer = PackageInfo->cbMaxToken;
AuthenticateBuffer.BufferType = SECBUFFER_TOKEN;
AuthenticateBuffer.pvBuffer = OutgoingLoginMessage->Data;
ChallengeDesc.ulVersion = 0;
ChallengeDesc.cBuffers = 1;
ChallengeDesc.pBuffers = &ChallengeBuffer;
ChallengeBuffer.cbBuffer = IncomingLoginMessage->Length;
ChallengeBuffer.BufferType = SECBUFFER_TOKEN | SECBUFFER_READONLY;
ChallengeBuffer.pvBuffer = IncomingLoginMessage->Data;
DPRINT( OSC, ("About to call InitializeSecurityContext\n") );
SecStatus = InitializeSecurityContextA(
NULL,
&ClientContextHandle,
NULL, // No target name needed
0,
0, // Reserved 1
SECURITY_NATIVE_DREP,
&ChallengeDesc,
0, // Reserved 2
&ClientContextHandle,
&AuthenticateDesc,
&ContextAttributes,
&Lifetime );
if ( (SecStatus != SEC_E_OK) ) {
DPRINT( OSC, ("InitializeSecurityContext (Authenticate): %d\n", SecStatus) );
return SecStatus;
}
//
// Send the authenticate buffer to the server and wait for the response.
//
if (AllowFlip) {
memcpy(OutgoingLoginMessage->Signature, AuthenticateSignature, 4);
} else {
memcpy(OutgoingLoginMessage->Signature, AuthenticateFlippedSignature, 4);
}
OutgoingLoginMessage->Length = AuthenticateBuffer.cbBuffer;
TraceFunc("");
DPRINT( OSC, ("Sending AUTH...\n") );
#if 0
IF_DEBUG(OSC) {
KdPrint(( "\n\nAuth Message Outgoing Packet:\n" ));
DumpBuffer( OutgoingLoginMessage, AuthenticateBuffer.cbBuffer + LOGIN_PACKET_DATA_OFFSET );
}
#endif
ResultSigs[0] = ResultSignature;
Status = UdpSendAndReceive(
OutgoingLoginMessage,
AuthenticateBuffer.cbBuffer + LOGIN_PACKET_DATA_OFFSET,
NetServerIpAddress,
BINL_PORT,
10, // retry count
IncomingLoginMessage,
INCOMING_MESSAGE_LENGTH,
&RemoteHost,
&RemotePort,
5, // receive timeout
1, // number of signatures we are looking for
ResultSigs, // signatures we look for
0); // sequence number (0 means don't check)
if ( !NT_SUCCESS(Status) ) {
DPRINT( ERROR, ("UdpSendAndReceive status is %x\n", Status) );
return Status;
}
#if 0
IF_DEBUG(OSC) {
KdPrint(( "\n\nAuthenticateBuffer Message Incoming Packet: %d %d %d %d\n",
IncomingLoginMessage->Data,
IncomingLoginMessage->Length,
IncomingLoginMessage->Signature,
IncomingLoginMessage->Status ));
DumpBuffer( IncomingLoginMessage->Data, IncomingLoginMessage->Length );
}
#endif
if (memcmp(IncomingLoginMessage->Signature, ResultSignature, 4) == 0) {
//
// Login has completed/failed, check status.
//
if ( IncomingLoginMessage->Status == STATUS_SUCCESS) {
TraceFunc("Login successful\n");
//
// If we are allowed to be flipped, then check if there is a
// flip list in the response, and if so try to log in to each one
// until we succeed at one.
//
if (AllowFlip) {
AllowFlip = FALSE; // once we have been flipped, don't do it again
if (IncomingLoginMessage->Length > 4) {
FlipServerCount = (IncomingLoginMessage->Length - 4) / 4;
if (FlipServerCount > MAX_FLIP_SERVER_COUNT) {
FlipServerCount = MAX_FLIP_SERVER_COUNT;
}
memcpy(
FlipServerList,
(PUCHAR)(&IncomingLoginMessage->Status) + sizeof(ULONG),
FlipServerCount * 4
);
//
// If the first server in the list is our current server,
// then don't flip.
//
if (*(ULONG *)FlipServerList == NetServerIpAddress) {
DPRINT( OSC, ("Not flipping, first server is the same\n") );
return STATUS_SUCCESS;
}
DPRINT( OSC, ("Trying %d flip servers\n", FlipServerCount) );
for (CurFlipServer = 0; CurFlipServer < FlipServerCount; ++CurFlipServer) {
//
// Logoff the previous server connection.
//
BlDoLogoff();
//
// Now connect to the new server.
//
NetServerIpAddress = *(ULONG *)(&FlipServerList[CurFlipServer*4]);
DPRINT( OSC, ("Trying to flip to server %lx\n", NetServerIpAddress) );
//
// We will only recurse once because *AllowFlip is now FALSE.
//
Status = BlDoLogin( );
DPRINT( OSC, ("Flip server login returned %lx\n", Status) );
if (Status == STATUS_SUCCESS) {
return Status;
}
}
//
// We have tried each flip server in turn and failed!
//
TraceFunc("ERROR - We have tried each flip server in turn and failed!\n");
return STATUS_NO_LOGON_SERVERS;
}
}
} else {
DPRINT( ERROR, ("ERROR - could not login, %x\n", IncomingLoginMessage->Status) );
}
return IncomingLoginMessage->Status;
} else {
//
// Shouldn't get this because we check signatures!!
//
DPRINT( ERROR, ("Got wrong message, expecting success or failure\n") );
return STATUS_UNEXPECTED_NETWORK_ERROR;
}
}
VOID
BlDoLogoff (
VOID
)
{
ARC_STATUS Status;
TraceFunc("BlDoLogoff( )\n");
//
// Send a logoff message to the server -- for the moment this is
// just sent once and not acked, since if it is lost the server
// will eventually timeout.
//
memcpy(OutgoingSignedMessage->Signature, LogoffSignature, 4);
OutgoingSignedMessage->Length = 0;
Status = UdpSend(
OutgoingSignedMessage,
SIGNED_PACKET_DATA_OFFSET,
NetServerIpAddress,
BINL_PORT);
if ( !NT_SUCCESS(Status) ) {
DPRINT( ERROR, ("UdpSend status is %x\n", Status) );
}
}
VOID
BlOutputLoadMessage (
IN PCHAR DeviceName,
IN PCHAR FileName,
IN PTCHAR FileDescription OPTIONAL
)
/*++
Routine Description:
This routine outputs a loading message to the console output device.
Arguments:
DeviceName - Supplies a pointer to a zero terminated device name.
FileName - Supplies a pointer to a zero terminated file name.
FileDescription - Friendly name of the file in question.
Return Value:
None.
--*/
{
ULONG Count;
CHAR OutputBuffer[256];
PTCHAR pOutputBuffer;
#ifdef UNICODE
WCHAR OutputBufferW[256];
UNICODE_STRING uString;
ANSI_STRING aString;
pOutputBuffer = OutputBufferW;
#else
pOutputBuffer = OutputBuffer;
#endif
UNREFERENCED_PARAMETER( FileDescription );
//
// Construct and output loading file message.
//
if (!BlOutputDots) {
strcpy(&OutputBuffer[0], " ");
strcat(&OutputBuffer[0], DeviceName);
strcat(&OutputBuffer[0], FileName);
strcat(&OutputBuffer[0], "\r\n");
} else {
strcpy(&OutputBuffer[0],".");
}
#if 0
BlLog((LOG_LOGFILE,OutputBuffer));
#endif
#ifdef UNICODE
RtlInitAnsiString( &aString, OutputBuffer);
uString.MaximumLength = sizeof(OutputBufferW);
uString.Buffer = OutputBufferW;
RtlAnsiStringToUnicodeString( &uString, &aString, FALSE );
#endif
ArcWrite(BlConsoleOutDeviceId,
pOutputBuffer,
_tcslen(pOutputBuffer),
&Count);
return;
}
BOOLEAN
BlGetDriveSignature(
IN PCHAR Name,
OUT PULONG Signature
)
/*++
Routine Description:
This routine gets the NTFT disk signature for a specified partition or
path.
Arguments:
Name - Supplies the arcname of the partition or drive.
Signature - Returns the NTFT disk signature for the drive.
Return Value:
TRUE - success, Signature will be filled in.
FALSE - failed, Signature will not be filled in.
--*/
{
UCHAR SectorBuffer[512+256];
CHAR DiskName[256];
ULONG DiskId;
PCHAR p;
ARC_STATUS Status;
ULONG Count;
LARGE_INTEGER SeekValue;
//
// Generate the arcname ("...partition(0)") for the raw disk device
// where the boot partition is, so we can read the MBR.
//
strcpy(DiskName, Name);
p=DiskName;
while (*p != '\0') {
if (_strnicmp(p, "partition(",10) == 0) {
break;
}
++p;
}
if (*p != '\0') {
strcpy(p,"partition(0)");
}
Status = ArcOpen(DiskName,ArcOpenReadOnly, &DiskId);
if (Status!=ESUCCESS) {
return(FALSE);
}
//
// Read the first sector of the physical drive
//
SeekValue.QuadPart = 0;
Status = ArcSeek(DiskId, &SeekValue, SeekAbsolute);
if (Status==ESUCCESS) {
Status = ArcRead(DiskId,
ALIGN_BUFFER(SectorBuffer),
512,
&Count);
}
ArcClose(DiskId);
if (Status!=ESUCCESS) {
return(FALSE);
}
//
// copy NTFT signature.
//
*Signature = ((PULONG)SectorBuffer)[PARTITION_TABLE_OFFSET/2-1];
return(TRUE);
}
#ifndef EFI
VOID
BlBadFileMessage(
IN PCHAR BadFileName
)
/*++
Routine Description:
This function displays the error message for a missing or incorrect
critical file.
Arguments:
BadFileName - Supplies the name of the file that is missing or
corrupt.
Return Value:
None.
--*/
{
ULONG Count;
PCHAR Text;
ArcWrite(BlConsoleOutDeviceId,
"\r\n",
strlen("\r\n"),
&Count);
Text = BlFindMessage(LOAD_SW_MIS_FILE_CLASS);
if (Text != NULL) {
ArcWrite(BlConsoleOutDeviceId,
Text,
strlen(Text),
&Count);
}
ArcWrite(BlConsoleOutDeviceId,
BadFileName,
strlen(BadFileName),
&Count);
ArcWrite(BlConsoleOutDeviceId,
"\r\n\r\n",
strlen("\r\n\r\n"),
&Count);
Text = BlFindMessage(LOAD_SW_FILE_REST_ACT);
if (Text != NULL) {
ArcWrite(BlConsoleOutDeviceId,
Text,
strlen(Text),
&Count);
}
}
VOID
BlFatalError(
IN ULONG ClassMessage,
IN ULONG DetailMessage,
IN ULONG ActionMessage
)
/*++
Routine Description:
This function looks up messages to display at a error condition.
It attempts to locate the string in the resource section of the
osloader. If that fails, it prints a numerical error code.
The only time it should print a numerical error code is if the
resource section could not be located. This will only happen
on ARC machines where boot fails before the osloader.exe file
can be opened.
Arguments:
ClassMessage - General message that describes the class of
problem.
DetailMessage - Detailed description of what caused problem
ActionMessage - Message that describes a course of action
for user to take.
Return Value:
none
--*/
{
PCHAR Text;
CHAR Buffer[40];
ULONG Count;
ArcWrite(BlConsoleOutDeviceId,
"\r\n",
strlen("\r\n"),
&Count);
//
// Remove any remains from the last known good message.
//
BlClearToEndOfScreen();
Text = BlFindMessage(ClassMessage);
if (Text == NULL) {
sprintf(Buffer,"%08lx\r\n",ClassMessage);
Text = Buffer;
}
ArcWrite(BlConsoleOutDeviceId,
Text,
strlen(Text),
&Count);
Text = BlFindMessage(DetailMessage);
if (Text == NULL) {
sprintf(Buffer,"%08lx\r\n",DetailMessage);
Text = Buffer;
}
ArcWrite(BlConsoleOutDeviceId,
Text,
strlen(Text),
&Count);
Text = BlFindMessage(ActionMessage);
if (Text == NULL) {
sprintf(Buffer,"%08lx\r\n",ActionMessage);
Text = Buffer;
}
ArcWrite(BlConsoleOutDeviceId,
Text,
strlen(Text),
&Count);
return;
}
#endif
#if defined(REMOTE_BOOT)
BOOLEAN
BlIsDiskless(
VOID
)
/*++
Routine Description:
This function returns TRUE if a machine is diskless.
Arguments:
None.
Return Value:
TRUE if the machine is diskless, FALSE otherwise.
--*/
{
ULONG FileId;
if (BlOpenRawDisk(&FileId) == ESUCCESS) {
BlCloseRawDisk(FileId);
return FALSE;
} else {
return TRUE;
}
}
#endif // defined(REMOTE_BOOT)
BOOLEAN
BlDetectHal(
VOID
)
/*++
Routine Description:
This function tries to determine the Hal type for this system.
It fills in the global "HalType" with the type.
Arguments:
None.
Return Value:
TRUE if the function successfully detects the hal type.
--*/
{
BOOLEAN Status = FALSE;
PSTR MachineName,HalName;
CHAR FileName[128];
ARC_STATUS AStatus;
ULONG DontCare;
//
// detecting the hal requires that you open up a copy of winnt.sif
//
strcpy(FileName, NetBootPath);
strcat(FileName, "winnt.sif" );
AStatus = SlInitIniFile( NULL,
NET_DEVICE_ID,
FileName,
&InfFile,
&WinntSifFile,
&WinntSifFileLength,
&DontCare );
//
// if it opens successfully, then search for the HAL.
//
if (AStatus == ESUCCESS) {
//
// do the search for the HAL.
//
MachineName = SlDetectHal();
if (MachineName) {
//
// OK, got the hal type, now look in the SIF file for the actual
// hal name.
//
HalName = SlGetIniValue(
InfFile,
"Hal",
MachineName,
NULL);
if (HalName) {
strcpy(HalType, HalName );
//
// also get the hal description, which is a "pretty print" version
// of the hal name
//
HalName = SlGetIniValue(
InfFile,
"Computer",
MachineName,
NULL );
if (HalName) {
strcpy(HalDescription, HalName);
Status = TRUE;
}
}
}
SpFreeINFBuffer( InfFile );
}
return(Status);
}
//
// note well: We stub out these setup functions in oschoice.exe, which are
// needed so that the hal detection routines can run properly. None of these
// routines should actually be called.
//
VOID
SlErrorBox(
IN ULONG MessageId,
IN ULONG Line,
IN PCHAR File
)
{
NOTHING;
}
VOID
SlFatalError(
IN ULONG MessageId,
...
)
{
//while(1) {
NOTHING;
//};
}
VOID
SlFriendlyError(
IN ULONG uStatus,
IN PCHAR pchBadFile,
IN ULONG uLine,
IN PCHAR pchCodeFile
)
{
NOTHING;
}
VOID
SlNoMemError(
IN ULONG Line,
IN PCHAR File
)
{
SlFatalError(0,Line,File);
}
VOID
SlBadInfLineError(
IN ULONG Line,
IN PCHAR INFFile
)
{
SlFatalError(0,Line,INFFile);
}
#define SL_KEY_F3 0x03000000
ULONG
SlGetChar(
VOID
)
{
return(SL_KEY_F3);
}
VOID
SlPrint(
IN PTCHAR FormatString,
...
)
{
NOTHING;
}