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.
 
 
 
 
 
 

917 lines
25 KiB

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
efs.c
Abstract:
This module contains the code that implements the EFS
file system filter driver.
Author:
Robert Gu (robertg) 29-Oct-1996
Environment:
Kernel mode
Revision History:
--*/
#include "efs.h"
#include "efsrtl.h"
#define BUFFER_SIZE 1024
#define BUFFER_REG_VAL L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\NTFS\\EFS\\Parameters"
#define MAX_ALLOC_BUFFER L"MaximumBlob"
#define EFS_KERNEL_CACHE_PERIOD L"EFSKCACHEPERIOD"
//
// Global storage for this file system filter driver.
//
EFS_DATA EfsData;
WORK_QUEUE_ITEM EfsShutdownCleanupWorkItem;
//
// $EFS stream name
//
WCHAR AttrName[5] = L"$EFS";
#if DBG
ULONG EFSDebug = 0;
#endif
ENCRYPTION_CALL_BACK EFSCallBackTable = {
ENCRYPTION_CURRENT_INTERFACE_VERSION,
ENCRYPTION_ALL_STREAMS,
EfsOpenFile,
NULL,
EFSFilePostCreate,
EfsFileControl,
EfsFileControl,
EFSFsControl,
EfsRead,
EfsWrite,
EfsFreeContext
};
VOID
EfspShutdownCleanup(
IN PVOID Parameter
);
//
// Assign text sections for each routine.
//
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, EfspShutdownCleanup)
#pragma alloc_text(PAGE, EfsInitialization)
#pragma alloc_text(PAGE, EfsGetSessionKey)
#pragma alloc_text(PAGE, GetKeyBlobLength)
#pragma alloc_text(PAGE, GetKeyBlobBuffer)
#pragma alloc_text(PAGE, SetKeyTable)
#pragma alloc_text(PAGE, EfsInitFips)
#endif
VOID
EfspShutdownCleanup(
IN PVOID Parameter
)
{
PEPROCESS LsaProcess;
PAGED_CODE();
UNREFERENCED_PARAMETER(Parameter);
if (EfsData.LsaProcess) {
LsaProcess = EfsData.LsaProcess;
EfsData.LsaProcess = NULL;
ObDereferenceObject(LsaProcess);
}
}
NTSTATUS
EfsInitialization(
void
)
/*++
Routine Description:
This is the initialization routine for the general purpose file system
filter driver. This routine creates the device object that represents this
driver in the system and registers it for watching all file systems that
register or unregister themselves as active file systems.
Arguments:
DriverObject - Pointer to driver object created by the system.
Return Value:
The function value is the final status from the initialization operation.
--*/
{
UNICODE_STRING nameString;
PDEVICE_EXTENSION deviceExtension;
PFILE_OBJECT fileObject;
NTSTATUS status;
HANDLE threadHdl;
ULONG i;
OBJECT_ATTRIBUTES objAttr;
UNICODE_STRING efsInitEventName;
UNICODE_STRING efsBufValue;
ULONG resultLength;
PKEY_VALUE_PARTIAL_INFORMATION pPartialValue = NULL;
HANDLE efsKey;
EFS_INIT_DATAEXG InitDataFromSrv;
PAGED_CODE();
//
// Mark our global data record
//
EfsData.AllocMaxBuffer = FALSE;
EfsData.FipsFileObject = NULL;
EfsData.FipsFunctionTable.Fips3Des = NULL;
EfsData.FipsFunctionTable.Fips3Des3Key = NULL;
EfsData.EfsDriverCacheLength = DefaultTimeExpirePeriod;
RtlInitUnicodeString( &efsBufValue, BUFFER_REG_VAL );
InitializeObjectAttributes(
&objAttr,
&efsBufValue,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
status = ZwOpenKey(
&efsKey,
KEY_READ,
&objAttr);
if (NT_SUCCESS(status)) {
pPartialValue = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePool(NonPagedPool, BUFFER_SIZE);
if (pPartialValue) {
RtlInitUnicodeString(&efsBufValue, MAX_ALLOC_BUFFER);
status = ZwQueryValueKey(
efsKey,
&efsBufValue,
KeyValuePartialInformation,
(PVOID)pPartialValue,
BUFFER_SIZE,
&resultLength
);
if (NT_SUCCESS(status)) {
ASSERT(pPartialValue->Type == REG_DWORD);
if (*((PLONG)&(pPartialValue->Data))){
EfsData.AllocMaxBuffer = TRUE;
}
}
RtlInitUnicodeString(&efsBufValue, EFS_KERNEL_CACHE_PERIOD);
status = ZwQueryValueKey(
efsKey,
&efsBufValue,
KeyValuePartialInformation,
(PVOID)pPartialValue,
BUFFER_SIZE,
&resultLength
);
if (NT_SUCCESS(status)) {
ASSERT(pPartialValue->Type == REG_DWORD);
if (((*((DWORD *)&(pPartialValue->Data))) >= MINCACHEPERIOD) &&
((*((DWORD *)&(pPartialValue->Data))) <= MAXCACHEPERIOD)){
EfsData.EfsDriverCacheLength = *((DWORD *)&(pPartialValue->Data));
EfsData.EfsDriverCacheLength *= 10000000;
}
}
ExFreePool(pPartialValue);
}
ZwClose(efsKey);
}
EfsData.NodeTypeCode = EFS_NTC_DATA_HEADER;
EfsData.NodeByteSize = sizeof( EFS_DATA );
EfsData.EfsInitialized = FALSE;
EfsData.InitEventHandle = NULL;
EfsData.LsaProcess = NULL;
//
// Initialize global data structures.
//
ExInitializeWorkItem( &EfsShutdownCleanupWorkItem,
&EfspShutdownCleanup,
NULL );
status = PoQueueShutdownWorkItem( &EfsShutdownCleanupWorkItem );
if (!NT_SUCCESS(status)) {
return status;
}
InitializeListHead( &(EfsData.EfsOpenCacheList) );
InitializeListHead( &(EfsData.EfsKeyLookAsideList) );
ExInitializeFastMutex( &(EfsData.EfsKeyBlobMemSrcMutex) );
ExInitializeFastMutex( &(EfsData.EfsOpenCacheMutex) );
//
// Initialize the event lookaside list
//
ExInitializeNPagedLookasideList(&(EfsData.EfsEventPool),
NULL,
NULL,
0,
sizeof(KEVENT),
'levE',
EFS_EVENTDEPTH
);
//
// Try to allocate at least one event in the list. This one will be used for
// sure later.
//
{
PVOID pTryEvent;
pTryEvent = ExAllocateFromNPagedLookasideList(&(EfsData.EfsEventPool));
if ( NULL == pTryEvent ){
//
// Free previously allocated memory
//
ExDeleteNPagedLookasideList(&(EfsData.EfsEventPool));
return STATUS_NO_MEMORY;
}
ExFreeToNPagedLookasideList(&(EfsData.EfsEventPool), pTryEvent);
}
//
// Initialize the context lookaside list
//
ExInitializeNPagedLookasideList(&(EfsData.EfsContextPool),
NULL,
NULL,
0,
sizeof(EFS_CONTEXT),
'nocE',
EFS_CONTEXTDEPTH
);
//
// Initialize the cache lookaside list
//
ExInitializePagedLookasideList(&(EfsData.EfsOpenCachePool),
NULL,
NULL,
0,
sizeof(OPEN_CACHE),
'hcoE',
EFS_CACHEDEPTH
);
ExInitializePagedLookasideList(&(EfsData.EfsMemSourceItem),
NULL,
NULL,
0,
sizeof(KEY_BLOB_RAMPOOL),
'msfE',
EFS_ALGDEPTH
);
ExInitializeNPagedLookasideList(&(EfsData.EfsLookAside),
NULL,
NULL,
0,
sizeof(NPAGED_LOOKASIDE_LIST),
'msfE',
EFS_ALGDEPTH
);
status = NtOfsRegisterCallBacks( Encryption, &EFSCallBackTable );
if (!NT_SUCCESS(status)) {
//
// Register callback failed
//
ExDeleteNPagedLookasideList(&(EfsData.EfsEventPool));
ExDeleteNPagedLookasideList(&(EfsData.EfsContextPool));
ExDeletePagedLookasideList(&(EfsData.EfsOpenCachePool));
ExDeletePagedLookasideList(&(EfsData.EfsMemSourceItem));
ExDeleteNPagedLookasideList(&(EfsData.EfsLookAside));
return status;
}
RtlInitUnicodeString(&(EfsData.EfsName), &AttrName[0]);
//
// Create an event
//
RtlInitUnicodeString( &efsInitEventName, L"\\EFSInitEvent" );
InitializeObjectAttributes(
&objAttr,
&efsInitEventName,
0,
NULL,
NULL
);
//
// Try to create an event. If the event was not created, the EFS
// server is not loaded yet. We will create a thread waiting for
// EFS server to be loaded. If the event was already created, we
// will just go ahead and get the session key from the EFS server.
//
status = ZwCreateEvent(
&(EfsData.InitEventHandle),
EVENT_MODIFY_STATE,
&objAttr,
NotificationEvent,
FALSE
);
if (!NT_SUCCESS(status)) {
if ( STATUS_OBJECT_NAME_COLLISION == status ){
//
// EFS server has been loaded. This is the normal case.
// Call server to get the session key.
//
status = GenerateSessionKey(
&InitDataFromSrv
);
if (NT_SUCCESS( status )) {
//
// Set session key
//
RtlCopyMemory( &(EfsData.SessionKey[0]), InitDataFromSrv.Key, DES_KEYSIZE );
deskey( (DESTable*)&(EfsData.SessionDesTable[0]),
&(EfsData.SessionKey[0]));
status = PsLookupProcessByProcessId(
InitDataFromSrv.LsaProcessID,
&(EfsData.LsaProcess)
);
RtlSecureZeroMemory(&InitDataFromSrv, sizeof(EFS_INIT_DATAEXG));
if (NT_SUCCESS( status )) {
EfsData.EfsInitialized = TRUE;
if ( PsGetCurrentProcess() != EfsData.LsaProcess ){
KAPC_STATE ApcState;
KeStackAttachProcess (
EfsData.LsaProcess,
&ApcState
);
InitSecurityInterface();
KeUnstackDetachProcess(&ApcState);
} else {
InitSecurityInterface();
}
EfsInitFips();
} else {
#if DBG
if ( (EFSTRACEALL | EFSTRACELIGHT) & EFSDebug ){
DbgPrint("PsLookupProcessByProcessId failed, status = %x\n",status);
}
#endif
//
// Failed to get the process pointer
//
ExDeleteNPagedLookasideList(&(EfsData.EfsEventPool));
ExDeleteNPagedLookasideList(&(EfsData.EfsContextPool));
ExDeletePagedLookasideList(&(EfsData.EfsOpenCachePool));
ExDeletePagedLookasideList(&(EfsData.EfsMemSourceItem));
ExDeleteNPagedLookasideList(&(EfsData.EfsLookAside));
}
} else {
#if DBG
if ( (EFSTRACEALL | EFSTRACELIGHT) & EFSDebug ){
DbgPrint("GenerateSessionKey failed, status = %x\n",status);
}
#endif
//
// Failed to get the session key
//
ExDeleteNPagedLookasideList(&(EfsData.EfsEventPool));
ExDeleteNPagedLookasideList(&(EfsData.EfsContextPool));
ExDeletePagedLookasideList(&(EfsData.EfsOpenCachePool));
ExDeletePagedLookasideList(&(EfsData.EfsMemSourceItem));
ExDeleteNPagedLookasideList(&(EfsData.EfsLookAside));
}
} else {
//
// Unexpected error occured. EFS cannot be loaded
//
#if DBG
if ( (EFSTRACEALL | EFSTRACELIGHT ) & EFSDebug ){
DbgPrint("EFSFILTER: Efs init event creation failed.%x\n", status);
}
#endif
ExDeleteNPagedLookasideList(&(EfsData.EfsEventPool));
ExDeleteNPagedLookasideList(&(EfsData.EfsContextPool));
ExDeletePagedLookasideList(&(EfsData.EfsOpenCachePool));
ExDeletePagedLookasideList(&(EfsData.EfsMemSourceItem));
ExDeleteNPagedLookasideList(&(EfsData.EfsLookAside));
}
} else {
//
// The server is not ready yet.
// Create a thread and wait for the server in that thread
//
status = PsCreateSystemThread(
&threadHdl,
GENERIC_ALL,
NULL,
NULL,
NULL,
EfsGetSessionKey,
NULL
);
if ( NT_SUCCESS( status ) ){
ZwClose( threadHdl );
} else {
ExDeleteNPagedLookasideList(&(EfsData.EfsEventPool));
ExDeleteNPagedLookasideList(&(EfsData.EfsContextPool));
ExDeletePagedLookasideList(&(EfsData.EfsOpenCachePool));
ExDeletePagedLookasideList(&(EfsData.EfsMemSourceItem));
ExDeleteNPagedLookasideList(&(EfsData.EfsLookAside));
}
}
return status;
}
VOID
EfsUninitialization(
VOID
)
{
PLIST_ENTRY pLink;
PKEY_BLOB_RAMPOOL pTmpItem;
PNPAGED_LOOKASIDE_LIST MemSrcList;
while (!IsListEmpty (&EfsData.EfsKeyLookAsideList)) {
pLink = RemoveHeadList (&EfsData.EfsKeyLookAsideList);
pTmpItem = CONTAINING_RECORD(pLink, KEY_BLOB_RAMPOOL, MemSourceChain);
MemSrcList = pTmpItem->MemSourceList;
ExDeleteNPagedLookasideList(MemSrcList);
ExFreeToNPagedLookasideList(&(EfsData.EfsLookAside), MemSrcList );
ExFreeToPagedLookasideList(&(EfsData.EfsMemSourceItem), pTmpItem );
}
ExDeleteNPagedLookasideList(&(EfsData.EfsEventPool));
ExDeleteNPagedLookasideList(&(EfsData.EfsContextPool));
ExDeletePagedLookasideList(&(EfsData.EfsOpenCachePool));
ExDeletePagedLookasideList(&(EfsData.EfsMemSourceItem));
ExDeleteNPagedLookasideList(&(EfsData.EfsLookAside));
if (EfsData.FipsFileObject) {
ObDereferenceObject(EfsData.FipsFileObject);
EfsData.FipsFileObject = NULL;
}
}
VOID
EfsGetSessionKey(
IN PVOID StartContext
)
/*++
Routine Description:
This routine is invoked in DriverEntry. It runs in a seperate thread.
The purpose of this routine is to wait for the EFS server. And Get the session key.
Arguments:
StartContext - Start context of the thread.
Return Value:
None.
--*/
{
SECURITY_DESCRIPTOR efsInitEventSecurityDescriptor;
NTSTATUS status;
EFS_INIT_DATAEXG InitDataFromSrv;
#if DBG
if ( EFSTRACEALL & EFSDebug ){
DbgPrint( "EFSFILTER: Thread started. %x\n", EfsData.NodeTypeCode );
}
#endif
status = ZwWaitForSingleObject (
EfsData.InitEventHandle,
FALSE,
(PLARGE_INTEGER)NULL
);
ZwClose( EfsData.InitEventHandle );
//
// Call server to get the session key
//
status = GenerateSessionKey(
&InitDataFromSrv
);
if (!NT_SUCCESS( status )) {
#if DBG
if ( (EFSTRACEALL | EFSTRACELIGHT) & EFSDebug ){
DbgPrint("GenerateSessionKey failed, status = %x\n",status);
}
#endif
return;
}
//
// Set session key
//
RtlCopyMemory( &(EfsData.SessionKey[0]), InitDataFromSrv.Key, DES_KEYSIZE );
deskey( (DESTable*)&(EfsData.SessionDesTable[0]),
&(EfsData.SessionKey[0]));
status = PsLookupProcessByProcessId(
InitDataFromSrv.LsaProcessID,
&(EfsData.LsaProcess)
);
RtlSecureZeroMemory(&InitDataFromSrv, sizeof(EFS_INIT_DATAEXG));
if (NT_SUCCESS( status )) {
EfsData.EfsInitialized = TRUE;
if ( PsGetCurrentProcess() != EfsData.LsaProcess ){
KAPC_STATE ApcState;
//KeAttachProcess(EfsData.LsaProcess);
KeStackAttachProcess (
EfsData.LsaProcess,
&ApcState
);
InitSecurityInterface();
//KeDetachProcess();
KeUnstackDetachProcess(&ApcState);
} else {
InitSecurityInterface();
}
EfsInitFips();
} else {
#if DBG
if ( (EFSTRACEALL | EFSTRACELIGHT) & EFSDebug ){
DbgPrint("PsLookupProcessByProcessId failed, status = %x\n",status);
}
#endif
}
return;
}
ULONG GetKeyBlobLength(
ULONG AlgID
)
{
if (EfsData.AllocMaxBuffer) {
return AES_KEY_BLOB_LENGTH_256;
}
switch (AlgID){
case CALG_DESX:
return DESX_KEY_BLOB_LENGTH;
case CALG_3DES:
return DES3_KEY_BLOB_LENGTH;
case CALG_AES_256:
return AES_KEY_BLOB_LENGTH_256;
case CALG_DES:
default:
return DES_KEY_BLOB_LENGTH;
}
return 0;
}
PKEY_BLOB
GetKeyBlobBuffer(
ULONG AlgID
)
{
PNPAGED_LOOKASIDE_LIST MemSrcList = NULL;
PKEY_BLOB_RAMPOOL KeyBlobPoolListItem = NULL;
PKEY_BLOB_RAMPOOL pTmpItem = NULL;
ULONG KeyBlobLength;
PLIST_ENTRY pLink = NULL;
PKEY_BLOB NewKeyBlob;
KeyBlobLength = GetKeyBlobLength(AlgID);
if (!KeyBlobLength){
ASSERT(KeyBlobLength);
return NULL;
}
ExAcquireFastMutex( &(EfsData.EfsKeyBlobMemSrcMutex));
for (pLink = EfsData.EfsKeyLookAsideList.Flink; pLink != &(EfsData.EfsKeyLookAsideList); pLink = pLink->Flink) {
pTmpItem = CONTAINING_RECORD(pLink, KEY_BLOB_RAMPOOL, MemSourceChain);
if (pTmpItem->AlgorithmID == AlgID) {
//
// The lookaside list already exists
//
MemSrcList = pTmpItem->MemSourceList;
break;
}
}
ExReleaseFastMutex( &(EfsData.EfsKeyBlobMemSrcMutex) );
if ( MemSrcList == NULL ) {
//
// No lookaside for this type of key. Go and create one item.
//
MemSrcList = (PNPAGED_LOOKASIDE_LIST)ExAllocateFromNPagedLookasideList(&(EfsData.EfsLookAside));
KeyBlobPoolListItem = (PKEY_BLOB_RAMPOOL) ExAllocateFromPagedLookasideList(&(EfsData.EfsMemSourceItem));
if ( (NULL == MemSrcList) || (NULL == KeyBlobPoolListItem) ){
if (MemSrcList) {
ExFreeToNPagedLookasideList(&(EfsData.EfsLookAside), MemSrcList );
}
if (KeyBlobPoolListItem){
ExFreeToPagedLookasideList(&(EfsData.EfsMemSourceItem), KeyBlobPoolListItem );
}
return NULL;
}
RtlZeroMemory( KeyBlobPoolListItem, sizeof( KEY_BLOB_RAMPOOL ) );
KeyBlobPoolListItem->MemSourceList = MemSrcList;
KeyBlobPoolListItem->AlgorithmID = AlgID;
ExInitializeNPagedLookasideList(
MemSrcList,
NULL,
NULL,
0,
KeyBlobLength,
'msfE',
EFS_KEYDEPTH
);
ExAcquireFastMutex( &(EfsData.EfsKeyBlobMemSrcMutex));
InsertHeadList( &(EfsData.EfsKeyLookAsideList), &(KeyBlobPoolListItem->MemSourceChain));
ExReleaseFastMutex( &(EfsData.EfsKeyBlobMemSrcMutex) );
}
//
// Allocate the Key Blob
//
NewKeyBlob = (PKEY_BLOB)ExAllocateFromNPagedLookasideList(MemSrcList);
if (NewKeyBlob){
NewKeyBlob->AlgorithmID = AlgID;
NewKeyBlob->KeyLength = KeyBlobLength;
NewKeyBlob->MemSource = MemSrcList;
}
return NewKeyBlob;
}
BOOLEAN
SetKeyTable(
PKEY_BLOB KeyBlob,
PEFS_KEY EfsKey
)
{
char DesXTmpKey[DESX_KEYSIZE];
switch ( EfsKey->Algorithm ){
case CALG_3DES:
if (EfsData.AllocMaxBuffer) {
RtlZeroMemory( &(KeyBlob->Key[0]) + DES3_TABLESIZE, KeyBlob->KeyLength - DES3_KEY_BLOB_LENGTH);
}
if (EfsData.FipsFunctionTable.Fips3Des3Key) {
EfsData.FipsFunctionTable.Fips3Des3Key(
(DES3TABLE*) &(KeyBlob->Key[0]),
((char *)EfsKey) + sizeof ( EFS_KEY )
);
} else {
return FALSE;
}
//tripledes3key(
// (DES3TABLE*) &(KeyBlob->Key[0]),
// ((char *)EfsKey) + sizeof ( EFS_KEY )
// );
break;
case CALG_DESX:
//
// Flush the non used area.
//
if (EfsData.AllocMaxBuffer) {
RtlZeroMemory( &(KeyBlob->Key[0]) + DESX_TABLESIZE, KeyBlob->KeyLength - DESX_KEY_BLOB_LENGTH);
}
desexpand128to192(
((char *)EfsKey) + sizeof ( EFS_KEY ),
DesXTmpKey
);
desxkey(
(DESXTable*) &(KeyBlob->Key[0]),
DesXTmpKey
);
break;
case CALG_AES_256:
aeskey(
(AESTable*) &(KeyBlob->Key[0]),
((char *)EfsKey) + sizeof ( EFS_KEY ),
AES_ROUNDS_256
);
break;
case CALG_DES:
default:
if (EfsData.AllocMaxBuffer) {
RtlZeroMemory( &(KeyBlob->Key[0]) + DES_TABLESIZE, KeyBlob->KeyLength - DES_KEY_BLOB_LENGTH);
}
deskey(
(DESTable*) &(KeyBlob->Key[0]),
((char *)EfsKey) + sizeof ( EFS_KEY )
);
break;
}
return TRUE;
}
BOOLEAN
EfsInitFips(VOID)
/*++
Routine Description:
Initialize the FIPS library table.
Arguments:
Return Value:
TRUE/FALSE.
--*/
{
UNICODE_STRING deviceName;
NTSTATUS status;
PDEVICE_OBJECT pDeviceObject;
// PFILE_OBJECT pFileObject = NULL;
PIRP pIrp;
IO_STATUS_BLOCK IoStatusBlock;
PAGED_CODE();
RtlInitUnicodeString(&deviceName, FIPS_DEVICE_NAME);
//
// Get the file and device objects for FIPS.
//
status = IoGetDeviceObjectPointer( &deviceName,
FILE_ALL_ACCESS,
&EfsData.FipsFileObject,
&pDeviceObject);
if (status != STATUS_SUCCESS) {
return FALSE;
}
//
// Build the request to send to FIPS to get library table.
//
pIrp = IoBuildDeviceIoControlRequest( IOCTL_FIPS_GET_FUNCTION_TABLE,
pDeviceObject,
NULL,
0,
&EfsData.FipsFunctionTable,
sizeof(FIPS_FUNCTION_TABLE),
FALSE,
NULL,
&IoStatusBlock
);
if (pIrp == NULL) {
#if DBG
DbgPrint("EfsInitFips: IoBuildDeviceIoControlRequest IOCTL_FIPS_GET_FUNCTION_TABLE failed.\n");
#endif
ObDereferenceObject(EfsData.FipsFileObject);
EfsData.FipsFileObject = NULL;
return FALSE;
}
status = IoCallDriver(pDeviceObject, pIrp);
if (status != STATUS_SUCCESS) {
ObDereferenceObject(EfsData.FipsFileObject);
EfsData.FipsFileObject = NULL;
#if DBG
DbgPrint("EfsInitFips: IoCallDriver failed, status = %x\n",status);
#endif
return FALSE;
}
return TRUE;
}