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

552 lines
12 KiB

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
secret.c
Abstract:
This module contains the code to read and write secrets from disk.
Author:
Adam Barr (adamba) 13-June-1997
Revision History:
Adam Barr (adamba) 29-December-1997
Modified from private\ntos\boot\lib\blsecret.c.
--*/
#include <rdrssp.h>
#include <rc4.h>
#include <wcstr.h>
#if defined(REMOTE_BOOT)
#if 0
VOID
RdrpDumpSector(
PUCHAR Sector
)
{
int i, j;
PUCHAR SectorChar = (PUCHAR)Sector;
for (i = 0; i < 512; i+= 16) {
for (j = 0; j < 16; j++) {
DbgPrint("%2.2x ", SectorChar[i + j]);
}
DbgPrint(" ");
for (j = 0; j < 16; j++) {
if ((SectorChar[i+j] >= ' ') && (SectorChar[i+j] < '~')) {
DbgPrint("%c", SectorChar[i+j]);
} else {
DbgPrint(".");
}
}
DbgPrint("\n");
}
}
#endif
NTSTATUS
RdrOpenRawDisk(
PHANDLE Handle
)
/*++
Routine Description:
This routine opens the raw disk for read/write.
Arguments:
Handle - returns the Handle if successful, for use in subsequent calls.
Return Value:
The status return from the ZwOpenFile.
--*/
{
NTSTATUS status;
OBJECT_ATTRIBUTES objectAttributes;
UNICODE_STRING physicalDriveString;
IO_STATUS_BLOCK ioStatus;
RtlInitUnicodeString(&physicalDriveString, L"\\Device\\Harddisk0\\Partition0");
InitializeObjectAttributes(
&objectAttributes,
&physicalDriveString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
status = ZwOpenFile(
Handle,
FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE,
&objectAttributes,
&ioStatus,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT);
if ((!NT_SUCCESS(status)) || (!NT_SUCCESS(ioStatus.Status))) {
KdPrint(("RdrOpenRawDisk: status on ZwOpenFile: %x, %x\n", status, ioStatus.Status));
if (NT_SUCCESS(status)) {
status = ioStatus.Status;
}
}
return status;
}
NTSTATUS
RdrCloseRawDisk(
HANDLE Handle
)
/*++
Routine Description:
This routine closes the raw disk.
Arguments:
Handle - The Handle returned by RdrOpenRawDisk.
Return Value:
The status return from the ZwClose.
--*/
{
return ZwClose(Handle);
}
NTSTATUS
RdrCheckForFreeSectors (
HANDLE Handle
)
/*++
Routine Description:
This routine makes sure that the MBR looks correct and that there
is nothing installed (OnTrack or EZ-Drive need to detect
NT fault-tolerance also) that would prevent us from using the third
sector for storing the password secret.
Arguments:
Handle - The Handle returned by RdrOpenRawDisk.
Return Value:
ESUCCESS if the disk is OK, or an error.
--*/
{
NTSTATUS status;
USHORT Sector[256];
ULONG BytesRead;
PPARTITION_DESCRIPTOR Partition;
LARGE_INTEGER SeekPosition;
IO_STATUS_BLOCK ioStatus;
SeekPosition.QuadPart = 0;
//
// Read the MBR at the start of the disk.
//
status = ZwReadFile(
Handle,
NULL,
NULL,
NULL,
&ioStatus,
Sector,
512,
&SeekPosition,
NULL);
if ((!NT_SUCCESS(status)) || (!NT_SUCCESS(ioStatus.Status))) {
KdPrint(("RdrCheckForFreeSectors: status on ZwReadFile: %x, %x\n", status, ioStatus.Status));
if (NT_SUCCESS(status)) {
status = ioStatus.Status;
}
return status;
}
#if 0
RdrpDumpSector((PUCHAR)Sector);
#endif
//
// Make sure the signature is OK, and that the type of partition
// 0 is not 0x54 (OnTrack) or 0x55 (EZ-Drive).
//
if (Sector[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) {
KdPrint(("RdrCheckForFreeSectors: Boot record signature %x not found (%x found)\n",
BOOT_RECORD_SIGNATURE,
Sector[BOOT_SIGNATURE_OFFSET] ));
return STATUS_INVALID_PARAMETER;
}
Partition = (PPARTITION_DESCRIPTOR)&Sector[PARTITION_TABLE_OFFSET];
if ((Partition->PartitionType == 0x54) ||
(Partition->PartitionType == 0x55)) {
KdPrint(("RdrCheckForFreeSectors: First partition has type %x, exiting\n", Partition->PartitionType));
return STATUS_INVALID_PARAMETER;
}
KdPrint(("RdrCheckForFreeSectors: Partition type is %d\n", Partition->PartitionType));
return STATUS_SUCCESS;
}
NTSTATUS
RdrReadSecret(
HANDLE Handle,
PRI_SECRET Secret
)
/*++
Routine Description:
This routine reads the secret from the disk, if present.
Arguments:
Handle - The Handle returned by RdrOpenRawDisk.
Return Value:
ESUCCESS if the secret is OK, an error otherwise.
--*/
{
NTSTATUS status;
ULONG BytesRead;
LARGE_INTEGER SeekPosition;
IO_STATUS_BLOCK ioStatus;
UCHAR Sector[512];
//
// Seek to the third sector.
// DEADISSUE 08/08/2000 -- this is in an #ifdef REMOTE_BOOT block,
// which is dead code, left here in case it is ever resuurected:
// I am pretty sure we can assume that the first disk has 512-byte sectors.
//
SeekPosition.QuadPart = 2 * 512;
//
// Read a full sector. The secret is at the beginning.
//
status = ZwReadFile(
Handle,
NULL,
NULL,
NULL,
&ioStatus,
Sector,
512,
&SeekPosition,
NULL);
if ((!NT_SUCCESS(status)) || (!NT_SUCCESS(ioStatus.Status))) {
KdPrint(("RdrReadSecret: status on ZwReadFile: %x, %x\n", status, ioStatus.Status));
if (NT_SUCCESS(status)) {
status = ioStatus.Status;
}
return status;
}
RtlMoveMemory(Secret, Sector, sizeof(RI_SECRET));
if (memcmp(Secret->Signature, RI_SECRET_SIGNATURE, 4) != 0) {
KdPrint(("RdrReadSecret: No signature found\n"));
return STATUS_INVALID_PARAMETER;
}
return STATUS_SUCCESS;
}
NTSTATUS
RdrWriteSecret(
HANDLE Handle,
PRI_SECRET Secret
)
/*++
Routine Description:
This routine writes the secret to the disk.
Arguments:
Handle - The Handle returned by RdrOpenRawDisk.
Return Value:
ESUCCESS if the secret is written OK, an error otherwise.
--*/
{
NTSTATUS status;
ULONG BytesWritten;
LARGE_INTEGER SeekPosition;
IO_STATUS_BLOCK ioStatus;
UCHAR Sector[512];
//
// Seek to the third sector.
//
SeekPosition.QuadPart = 2 * 512;
//
// Copy the secret to a full sector since the raw disk requires
// reads/writes in sector multiples.
//
RtlZeroMemory(Sector, sizeof(Sector));
RtlMoveMemory(Sector, Secret, sizeof(RI_SECRET));
//
// Write a secret-sized chunk.
//
status = ZwWriteFile(
Handle,
NULL,
NULL,
NULL,
&ioStatus,
Sector,
512,
&SeekPosition,
NULL);
if ((!NT_SUCCESS(status)) || (!NT_SUCCESS(ioStatus.Status))) {
KdPrint(("RdrWriteSecret: status on ZwWriteFile: %x, %x\n", status, ioStatus.Status));
if (NT_SUCCESS(status)) {
status = ioStatus.Status;
}
return status;
}
return STATUS_SUCCESS;
}
VOID
RdrInitializeSecret(
IN PUCHAR Domain,
IN PUCHAR User,
IN PUCHAR LmOwfPassword1,
IN PUCHAR NtOwfPassword1,
IN PUCHAR LmOwfPassword2 OPTIONAL,
IN PUCHAR NtOwfPassword2 OPTIONAL,
IN PUCHAR Sid,
IN OUT PRI_SECRET Secret
)
{
int Length;
int i;
struct RC4_KEYSTRUCT Key;
memset(Secret, 0, sizeof(RI_SECRET));
memcpy(Secret->Signature, RI_SECRET_SIGNATURE, 4);
Secret->Version = 1;
Length = strlen(Domain);
memcpy(Secret->Domain, Domain, Length);
Length = strlen(User);
memcpy(Secret->User, User, Length);
memcpy(Secret->Sid, Sid, RI_SECRET_SID_SIZE);
//
// Encrypt the passwords using the user name.
//
#ifdef RDR_USE_LM_PASSWORD
memcpy(Secret->LmEncryptedPassword1, LmOwfPassword1, LM_OWF_PASSWORD_SIZE);
rc4_key(&Key, strlen(User), User);
rc4(&Key, LM_OWF_PASSWORD_SIZE, Secret->LmEncryptedPassword1);
if (LmOwfPassword2 != NULL) {
memcpy(Secret->LmEncryptedPassword2, LmOwfPassword2, LM_OWF_PASSWORD_SIZE);
rc4_key(&Key, strlen(User), User);
rc4(&Key, LM_OWF_PASSWORD_SIZE, Secret->LmEncryptedPassword2);
}
#endif
memcpy(Secret->NtEncryptedPassword1, NtOwfPassword1, NT_OWF_PASSWORD_SIZE);
rc4_key(&Key, strlen(User), User);
rc4(&Key, NT_OWF_PASSWORD_SIZE, Secret->NtEncryptedPassword1);
if (NtOwfPassword2 != NULL) {
memcpy(Secret->NtEncryptedPassword2, NtOwfPassword2, NT_OWF_PASSWORD_SIZE);
rc4_key(&Key, strlen(User), User);
rc4(&Key, NT_OWF_PASSWORD_SIZE, Secret->NtEncryptedPassword2);
}
}
#endif // defined(REMOTE_BOOT)
VOID
RdrParseSecret(
IN OUT PUCHAR Domain,
IN OUT PUCHAR User,
IN OUT PUCHAR LmOwfPassword1,
IN OUT PUCHAR NtOwfPassword1,
#if defined(REMOTE_BOOT)
IN OUT PUCHAR LmOwfPassword2,
IN OUT PUCHAR NtOwfPassword2,
#endif // defined(REMOTE_BOOT)
IN OUT PUCHAR Sid,
IN PRI_SECRET Secret
)
{
struct RC4_KEYSTRUCT Key;
memcpy(Domain, Secret->Domain, RI_SECRET_DOMAIN_SIZE);
Domain[RI_SECRET_DOMAIN_SIZE] = '\0';
memcpy(User, Secret->User, RI_SECRET_USER_SIZE);
User[RI_SECRET_USER_SIZE] = '\0';
memcpy(Sid, Secret->Sid, RI_SECRET_SID_SIZE);
//
// Decrypt the passwords using the user name.
//
#ifdef RDR_USE_LM_PASSWORD
memcpy(LmOwfPassword1, Secret->LmEncryptedPassword1, LM_OWF_PASSWORD_SIZE);
rc4_key(&Key, strlen(User), User);
rc4(&Key, LM_OWF_PASSWORD_SIZE, LmOwfPassword1);
#if defined(REMOTE_BOOT)
memcpy(LmOwfPassword2, Secret->LmEncryptedPassword2, LM_OWF_PASSWORD_SIZE);
rc4_key(&Key, strlen(User), User);
rc4(&Key, LM_OWF_PASSWORD_SIZE, LmOwfPassword2);
#endif // defined(REMOTE_BOOT)
#else
memset(LmOwfPassword1, 0, LM_OWF_PASSWORD_SIZE);
#if defined(REMOTE_BOOT)
memset(LmOwfPassword2, 0, LM_OWF_PASSWORD_SIZE);
#endif // defined(REMOTE_BOOT)
#endif
memcpy(NtOwfPassword1, Secret->NtEncryptedPassword1, NT_OWF_PASSWORD_SIZE);
rc4_key(&Key, strlen(User), User);
rc4(&Key, NT_OWF_PASSWORD_SIZE, NtOwfPassword1);
#if defined(REMOTE_BOOT)
memcpy(NtOwfPassword2, Secret->NtEncryptedPassword2, NT_OWF_PASSWORD_SIZE);
rc4_key(&Key, strlen(User), User);
rc4(&Key, NT_OWF_PASSWORD_SIZE, NtOwfPassword2);
#endif // defined(REMOTE_BOOT)
}
#if defined(REMOTE_BOOT)
VOID
RdrOwfPassword(
IN PUNICODE_STRING Password,
IN OUT PUCHAR LmOwfPassword,
IN OUT PUCHAR NtOwfPassword
)
{
char TmpText[CLEAR_BLOCK_LENGTH*2];
char TmpChar;
int Length;
int i;
#ifdef RDR_USE_LM_PASSWORD
Length = Password.Length / sizeof(WCHAR);
//
// Convert the password to an upper-case ANSI buffer.
//
if (Length == 0) {
TmpText[0] = '\0';
} else {
for (i = 0; i <= Length; i++) {
wctomb(&TmpChar, Password.Buffer[i]);
TmpText[i] = toupper(TmpChar);
}
}
RtlCalculateLmOwfPassword((PLM_PASSWORD)TmpText, (PLM_OWF_PASSWORD)LmOwfPassword);
#else
memset(LmOwfPassword, 0, LM_OWF_PASSWORD_SIZE);
#endif
RtlCalculateNtOwfPassword(Password, (PNT_OWF_PASSWORD)NtOwfPassword);
RtlSecureZeroMemory(TmpText, sizeof(TmpText));
}
#endif // defined(REMOTE_BOOT)