You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2425 lines
63 KiB
2425 lines
63 KiB
/*++
|
|
|
|
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.2\r\n";
|
|
WCHAR OsLoaderVersionW[] = L"OS Chooser V5.2\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 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"
|
|
|
|
|
|
VOID
|
|
BlpSetInverseMode(
|
|
IN BOOLEAN InverseOn
|
|
);
|
|
|
|
VOID
|
|
BlpSendEscape(
|
|
PCHAR Escape
|
|
);
|
|
|
|
ULONG
|
|
BlDoLogin(
|
|
VOID
|
|
);
|
|
|
|
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
|
|
|
|
PCHAR OutgoingMessageBuffer = NULL;
|
|
SIGNED_PACKET UNALIGNED * OutgoingSignedMessage;
|
|
|
|
PCHAR IncomingMessageBuffer = NULL;
|
|
SIGNED_PACKET UNALIGNED * IncomingSignedMessage;
|
|
|
|
PCHAR TempIncomingMessage = NULL;
|
|
|
|
CredHandle CredentialHandle;
|
|
BOOLEAN CredentialHandleValid = FALSE;
|
|
CtxtHandle ClientContextHandle;
|
|
BOOLEAN ClientContextHandleValid = FALSE;
|
|
PSecPkgInfoA PackageInfo = NULL;
|
|
|
|
|
|
|
|
|
|
#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
|
|
|
|
ARC_STATUS
|
|
BlInitStdio (
|
|
IN ULONG Argc,
|
|
IN PCHAR Argv[]
|
|
)
|
|
{
|
|
PCHAR ConsoleOutDevice;
|
|
PCHAR ConsoleInDevice;
|
|
ULONG Status;
|
|
|
|
if (BlConsoleInitialized) {
|
|
return ESUCCESS;
|
|
}
|
|
|
|
|
|
//
|
|
// Allocate some memory for our UDP reads/writes. These *must*
|
|
// be virtual addresses, so we need to allocate them rather than
|
|
// just using static arrays because if we have lots of memory
|
|
// (greater than >9Gig) on a machine and oschoice gets loaded high, we
|
|
// may end up with a bogus address when we convert these addresses to
|
|
// physical addresses just before we UdpWrite/UdpRead.
|
|
//
|
|
OutgoingMessageBuffer = BlAllocateHeap(OUTGOING_MESSAGE_LENGTH);
|
|
IncomingMessageBuffer = BlAllocateHeap(INCOMING_MESSAGE_LENGTH);
|
|
TempIncomingMessage = BlAllocateHeap(TEMP_INCOMING_MESSAGE_LENGTH);
|
|
|
|
|
|
//
|
|
// 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);
|
|
|
|
}
|
|
|
|
//
|
|
// 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;
|
|
|
|
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) {
|
|
|
|
|
|
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
|
|
}
|
|
|
|
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;
|
|
|
|
|
|
#ifdef EFI
|
|
//
|
|
// set the efi watchdog timer to 20 minutes. the boot manager sets it to 5, but
|
|
// the loader could take longer than this, especially if installing over the
|
|
// network
|
|
//
|
|
SetEFIWatchDog(EFI_WATCHDOG_TIMEOUT);
|
|
#endif
|
|
|
|
//
|
|
// 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 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...\r\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
|
|
//
|
|
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 ) )
|
|
{
|
|
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
|
|
//
|
|
// 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 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.
|
|
//
|
|
memcpy(OutgoingLoginMessage->Signature, AuthenticateSignature, 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");
|
|
|
|
} 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
FILETIME GlobalFileTime = { 0 };
|
|
TIME_FIELDS ArcTimeForUTCTime = { 0 };
|
|
|
|
NTSTATUS
|
|
SetFileTimeFromTimeString(
|
|
IN PSTR TimeString,
|
|
OUT PFILETIME FileTime,
|
|
OUT TIME_FIELDS *ArcTime
|
|
)
|
|
{
|
|
TIME_FIELDS *pArcTime;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PSTR p,q;
|
|
|
|
if (!TimeString) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto exit;
|
|
}
|
|
|
|
q = p = TimeString;
|
|
//
|
|
// go until we either run out of space or hit a semi-colon. The
|
|
// semi-colon delimits the two fields of the filetime string.
|
|
//
|
|
while(*q != '\0' && *q != ';') {
|
|
q++;
|
|
}
|
|
|
|
//
|
|
// make sure we didn't have a bad input
|
|
//
|
|
if (*q == '\0') {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto exit;
|
|
}
|
|
|
|
*q = '\0';
|
|
q += 1;
|
|
|
|
//
|
|
// convert from string into binary format.
|
|
//
|
|
FileTime->dwHighDateTime = atoi(p);
|
|
FileTime->dwLowDateTime = atoi(q);
|
|
|
|
//
|
|
// now save off the arc time that we did the conversion so that
|
|
// we can calculate a delta later on.
|
|
//
|
|
pArcTime = ArcGetTime();
|
|
RtlCopyMemory(ArcTime,pArcTime,sizeof(TIME_FIELDS));
|
|
|
|
exit:
|
|
return(Status);
|
|
}
|
|
|
|
#if 0
|
|
|
|
NTSTATUS
|
|
GetFileTimeFromTimeFields(
|
|
IN PTIME_FIELDS TimeFields,
|
|
OUT FILETIME *Time
|
|
)
|
|
{
|
|
if (!TimeFields) {
|
|
return(STATUS_UNSUCCESSFUL);
|
|
}
|
|
|
|
return(RtlTimeFieldsToTime(TimeFields,(LARGE_INTEGER *)Time) == TRUE
|
|
? STATUS_SUCCESS
|
|
: STATUS_UNSUCCESSFUL );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
NTSTATUS
|
|
BlGetSystemTimeAsFileTime(
|
|
FILETIME *pSystemTimeAsFileTime
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return the current UTC system time in file time format.
|
|
|
|
This routine requires that a network agent has let us know what the
|
|
UTC time of the system currently is. If not, we will try to use the
|
|
less accurate system bios time.
|
|
|
|
Arguments:
|
|
|
|
pSystemTimeAsFileTime - receives the current time.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS code indicating outcome.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
LARGE_INTEGER OriginalTime,CurrentTime,Delta,LIFileTime;
|
|
|
|
#if 0
|
|
//
|
|
// check if we've gotten the system time from the network. if not, then
|
|
// we will try to use the time from the bios.
|
|
//
|
|
if (GlobalFileTime.dwLowDateTime == 0 && GlobalFileTime.dwHighDateTime == 0) {
|
|
Status = GetFileTimeFromTimeFields(ArcGetTime(),pSystemTimeAsFileTime);
|
|
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// Get the delta time from when we got the original time.
|
|
//
|
|
if (RtlTimeFieldsToTime(&ArcTimeForUTCTime,&OriginalTime) &&
|
|
RtlTimeFieldsToTime(ArcGetTime(), &CurrentTime)) {
|
|
Delta.QuadPart = CurrentTime.QuadPart - OriginalTime.QuadPart;
|
|
|
|
//
|
|
// Add that delta into the current time.
|
|
// do this math in large integer format cause it handles
|
|
// overflow from one DWORD to the next.
|
|
//
|
|
RtlCopyMemory(&LIFileTime,&GlobalFileTime,sizeof(FILETIME));
|
|
|
|
LIFileTime.QuadPart += Delta.QuadPart;
|
|
|
|
RtlCopyMemory(&GlobalFileTime,&LIFileTime,sizeof(FILETIME));
|
|
}
|
|
#endif
|
|
RtlCopyMemory(pSystemTimeAsFileTime,&GlobalFileTime,sizeof(FILETIME));
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
#ifndef EFI
|
|
|
|
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
|
|
//
|
|
strncpy(FileName, NetBootPath, sizeof(FileName));
|
|
FileName[sizeof(FileName)-1] = '\0';
|
|
|
|
strncat(FileName, "winnt.sif", sizeof(FileName) - strlen(FileName) );
|
|
FileName[sizeof(FileName)-1] = '\0';
|
|
|
|
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);
|
|
}
|
|
#else
|
|
|
|
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.
|
|
|
|
NOTE WELL: EFI machines are always "ACPI" machines so there is
|
|
only one hal type.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the function successfully detects the hal type.
|
|
|
|
--*/
|
|
{
|
|
strcpy(HalType, "hal.dll" );
|
|
strcpy(HalDescription,"ACPI PC");
|
|
return(TRUE);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// 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;
|
|
}
|