/*++ 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 #include #include #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)