2851 lines
71 KiB
C
2851 lines
71 KiB
C
|
/*++
|
|||
|
|
|||
|
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;
|
|||
|
}
|