2637 lines
62 KiB
C++
2637 lines
62 KiB
C++
//+-----------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (c) Microsoft Corporation 1991 - 1992
|
|
//
|
|
// File: sphelp.c
|
|
//
|
|
// Contents: Security Package Helper functions (see isecpkg.doc)
|
|
//
|
|
// Functions LsapUnloadPackage
|
|
// LsapAllocate
|
|
// LsapFree
|
|
// LsapClientAllocate
|
|
// LsapCopyToClient
|
|
// LsapCopyFromClient
|
|
// LsapClientFree
|
|
// LsapOpenClientProcess
|
|
// LsapOpenClientThread
|
|
// LsapDuplicateHandle
|
|
// LsapSaveSupplementalCredentials
|
|
// LsapGetWindow
|
|
// LsapCreateThread
|
|
// LsapMapClientBuffer
|
|
//
|
|
//
|
|
// Notes: By defining TRACK_MEM, we will track all use of memory
|
|
// allocated through the LsapAllocate. DBG_MEM will track
|
|
// memory leaks.
|
|
//
|
|
// History: 20 May 92 RichardW Created
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
#include <lsapch.hxx>
|
|
|
|
extern "C"
|
|
{
|
|
#include "sesmgr.h"
|
|
#include "spdebug.h"
|
|
#include "klpcstub.h"
|
|
|
|
}
|
|
|
|
|
|
typedef struct _LSAP_THREAD_START {
|
|
LPTHREAD_START_ROUTINE lpStart;
|
|
LPVOID lpParm;
|
|
ULONG_PTR dwPackageID;
|
|
} LSAP_THREAD_START, *PLSAP_THREAD_START;
|
|
|
|
extern LSA_CALL_INFO LsapDefaultCallInfo ;
|
|
|
|
|
|
ULONG_PTR LsapUserModeLimit ;
|
|
|
|
//
|
|
// private heaps defines.
|
|
//
|
|
|
|
// HEAP_HEADER should always be size even multiple of heap allocation granularity
|
|
//
|
|
typedef struct {
|
|
HANDLE hHeap;
|
|
SIZE_T Magic;
|
|
} HEAP_HEADER_LSA, *PHEAP_HEADER_LSA;
|
|
|
|
#define HEAP_COUNT_MAX 32
|
|
#define HEAP_MAGIC_TAG 0x66677766
|
|
|
|
HANDLE gHeaps[ HEAP_COUNT_MAX ];
|
|
DWORD gcHeaps;
|
|
|
|
|
|
|
|
#if DBG
|
|
//
|
|
// Failure simulation parameters
|
|
//
|
|
|
|
ULONG TotalAllocations;
|
|
ULONG_PTR PackageToFail = SPMGR_ID;
|
|
SpmDbg_MemoryFailure MemFail;
|
|
|
|
#endif // DBG
|
|
|
|
|
|
|
|
void
|
|
CacheMachineInReg(GUID *);
|
|
|
|
|
|
|
|
#define MEM_MAGIC 0x0feedbed
|
|
#define MEM_FREED 0x0b00b00b
|
|
#define MEM_MASK 0x0FFFFFFF
|
|
#define MEM_NEVER 0x10000000
|
|
|
|
LSA_SECPKG_FUNCTION_TABLE LsapSecpkgFunctionTable = {
|
|
LsapCreateLogonSession,
|
|
LsapDeleteLogonSession,
|
|
LsapAddCredential,
|
|
LsapGetCredentials,
|
|
LsapDeleteCredential,
|
|
LsapAllocateLsaHeap,
|
|
LsapFreeLsaHeap,
|
|
LsapAllocateClientBuffer,
|
|
LsapFreeClientBuffer,
|
|
LsapCopyToClientBuffer,
|
|
LsapCopyFromClientBuffer,
|
|
LsapImpersonateClient,
|
|
LsapUnloadPackage,
|
|
LsapDuplicateHandle,
|
|
NULL, // LsapSaveSupplementalCredentials,
|
|
LsapCreateThread,
|
|
LsapGetClientInfo,
|
|
LsaIRegisterNotification,
|
|
LsaICancelNotification,
|
|
LsapMapClientBuffer,
|
|
LsapCreateToken,
|
|
LsapAuditLogon,
|
|
LsaICallPackage,
|
|
LsaIFreeReturnBuffer,
|
|
LsapGetCallInfo,
|
|
LsaICallPackageEx,
|
|
LsaCreateSharedMemory,
|
|
LsaAllocateSharedMemory,
|
|
LsaFreeSharedMemory,
|
|
LsaDeleteSharedMemory,
|
|
LsaOpenSamUser,
|
|
LsaGetUserCredentials,
|
|
LsaGetUserAuthData,
|
|
LsaCloseSamUser,
|
|
LsaConvertAuthDataToToken,
|
|
LsaClientCallback,
|
|
LsapUpdateCredentials,
|
|
LsaGetAuthDataForUser,
|
|
LsaCrackSingleName,
|
|
LsaIAuditAccountLogon,
|
|
LsaICallPackagePassthrough,
|
|
CrediRead,
|
|
CrediReadDomainCredentials,
|
|
CrediFreeCredentials,
|
|
LsaProtectMemory,
|
|
LsaUnprotectMemory,
|
|
LsapOpenTokenByLogonId,
|
|
LsaExpandAuthDataForDomain,
|
|
LsapAllocatePrivateHeap,
|
|
LsapFreePrivateHeap,
|
|
LsapCreateTokenEx
|
|
};
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: LsapOpenCaller
|
|
//
|
|
// Synopsis: Opens the calling process
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: phProcess -- receives handle to process
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
NTSTATUS
|
|
LsapOpenCaller(
|
|
IN OUT PSession pSession
|
|
)
|
|
{
|
|
HANDLE hProcess;
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
CLIENT_ID ClientId;
|
|
PVOID Ignored ;
|
|
|
|
ClientId.UniqueThread = NULL;
|
|
ClientId.UniqueProcess = (HANDLE) LongToHandle(pSession->dwProcessID);
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status = NtOpenProcess(
|
|
&hProcess,
|
|
PROCESS_DUP_HANDLE | // Duplicate Handles
|
|
PROCESS_QUERY_INFORMATION | // Get token
|
|
PROCESS_VM_OPERATION | // Allocate
|
|
PROCESS_VM_READ | // Read memory
|
|
PROCESS_VM_WRITE, // Write memory
|
|
&ObjectAttributes,
|
|
&ClientId
|
|
);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DebugLog((DEB_ERROR, "Did not open process %08x, error %08x\n",
|
|
pSession->dwProcessID, Status));
|
|
|
|
return( Status );
|
|
}
|
|
|
|
pSession->hProcess = hProcess;
|
|
|
|
Status = NtQueryInformationProcess(
|
|
hProcess,
|
|
ProcessSessionInformation,
|
|
&pSession->SessionId,
|
|
sizeof( ULONG ),
|
|
NULL );
|
|
|
|
#if _WIN64
|
|
Status = NtQueryInformationProcess(
|
|
hProcess,
|
|
ProcessWow64Information,
|
|
&Ignored,
|
|
sizeof( Ignored ),
|
|
NULL );
|
|
|
|
if ( NT_SUCCESS( Status ) )
|
|
{
|
|
if ( Ignored != 0 )
|
|
{
|
|
pSession->fSession |= SESFLAG_WOW_PROCESS ;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return( STATUS_SUCCESS );
|
|
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: CheckCaller
|
|
//
|
|
// Synopsis: Checks if calling process has been opened, opens if it
|
|
// hasn't.
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: pSession - Current session
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
CheckCaller(
|
|
IN PSession pSession
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
if (!pSession->hProcess)
|
|
{
|
|
Status = LsapOpenCaller(pSession);
|
|
if (FAILED(Status))
|
|
{
|
|
DebugLog((DEB_ERROR, "Could not open client (%x)\n", Status));
|
|
return(Status);
|
|
}
|
|
|
|
}
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: LsapUnloadPackage
|
|
//
|
|
// Synopsis: Unloads the calling package in case of catastrophic problems
|
|
//
|
|
// Effects: Unloads the DLL that generated this call.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes: Calling thread is terminated through a special exception.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
NTSTATUS NTAPI
|
|
LsapUnloadPackage(
|
|
VOID
|
|
)
|
|
{
|
|
ULONG_PTR PackageId;
|
|
PSession pSession = GetCurrentSession();
|
|
|
|
PackageId = GetCurrentPackageId();
|
|
|
|
|
|
//
|
|
// If this is an autonomous thread, we should interrupt any other threads
|
|
// that are currently executing in the DLL. At this time, I do not know
|
|
// what will happen if the virtual address space of a thread suddenly
|
|
// becomes invalid, or even if that will happen. We'll find out...
|
|
//
|
|
|
|
if (pSession->fSession & SESFLAG_AUTONOMOUS)
|
|
{
|
|
DebugLog((DEB_WARN, "Autonomous thread executed LsapUnloadPackage\n"));
|
|
}
|
|
|
|
pSession->fSession |= SESFLAG_UNLOADING;
|
|
|
|
RaiseException((ULONG) SEC_E_BAD_PKGID, 0, 0, NULL);
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
LsapHeapInitialize(
|
|
IN BOOLEAN Server
|
|
)
|
|
{
|
|
|
|
if( !Server )
|
|
{
|
|
NT_PRODUCT_TYPE ProductType;
|
|
|
|
if ( RtlGetNtProductType( &ProductType ) &&
|
|
(ProductType == NtProductServer || ProductType == NtProductLanManNt)
|
|
)
|
|
{
|
|
Server = TRUE;
|
|
}
|
|
}
|
|
|
|
if ( Server )
|
|
{
|
|
SYSTEM_INFO si;
|
|
DWORD Heaps;
|
|
DWORD i, cHeapsCreated;
|
|
RTL_HEAP_PARAMETERS HeapParameters;
|
|
|
|
GetSystemInfo( &si );
|
|
|
|
if( si.dwNumberOfProcessors == 0 ) {
|
|
Heaps = 1;
|
|
} else if( si.dwNumberOfProcessors > HEAP_COUNT_MAX )
|
|
{
|
|
Heaps = HEAP_COUNT_MAX;
|
|
} else {
|
|
Heaps = si.dwNumberOfProcessors;
|
|
}
|
|
|
|
ZeroMemory( &HeapParameters, sizeof(HeapParameters) );
|
|
HeapParameters.Length = sizeof(HeapParameters);
|
|
HeapParameters.DeCommitTotalFreeThreshold = 8 * LsapPageSize ;
|
|
|
|
cHeapsCreated = 0;
|
|
|
|
for( i = 0 ; i < Heaps ; i++ )
|
|
{
|
|
gHeaps[ cHeapsCreated ] = RtlCreateHeap(
|
|
HEAP_GROWABLE,
|
|
NULL,
|
|
0,
|
|
0,
|
|
NULL,
|
|
&HeapParameters
|
|
);
|
|
|
|
if( gHeaps[ cHeapsCreated ] != NULL )
|
|
{
|
|
cHeapsCreated++;
|
|
}
|
|
}
|
|
|
|
gcHeaps = cHeapsCreated;
|
|
}
|
|
|
|
|
|
if( gHeaps[ 0 ] == NULL )
|
|
{
|
|
gHeaps[ 0 ] = RtlProcessHeap();
|
|
gcHeaps = 1;
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: LsapAllocateLsaHeap
|
|
//
|
|
// Synopsis: Allocates memory on process heap
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: cbMemory -- Size of block needed
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: ptr to memory
|
|
//
|
|
// Notes: if DBGMEM or TRACK_MEM defined, extra work is done for
|
|
// tracking purposes.
|
|
//
|
|
// Can raise the exception STATUS_NO_MEMORY
|
|
//
|
|
// Per object reuse rules of C2 and above, we zero any memory
|
|
// allocated through this function
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
PVOID NTAPI
|
|
LsapAllocateLsaHeap(
|
|
IN ULONG cbMemory
|
|
)
|
|
{
|
|
|
|
#if DBG
|
|
if (MemFail.fSimulateFailure)
|
|
{
|
|
TotalAllocations++;
|
|
if ((TotalAllocations > MemFail.FailureDelay) &&
|
|
(TotalAllocations < MemFail.FailureLength + MemFail.FailureDelay))
|
|
{
|
|
if ((TotalAllocations % MemFail.FailureInterval) == 0)
|
|
{
|
|
if ((PackageToFail == SPMGR_ID) ||
|
|
(GetCurrentPackageId() == PackageToFail))
|
|
{
|
|
DebugLog((DEB_TRACE,"LsapAllocateLsaHeap: Simulating failure\n"));
|
|
return(NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif // DBG
|
|
|
|
|
|
return(RtlAllocateHeap(
|
|
RtlProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
cbMemory
|
|
));
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: LsapFreeLsaHeap
|
|
//
|
|
// Synopsis: Frees memory allocated by LsapAllocateLsaHeap
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: pvMemory
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void NTAPI
|
|
LsapFreeLsaHeap(
|
|
IN PVOID pvMemory
|
|
)
|
|
{
|
|
|
|
RtlFreeHeap(
|
|
RtlProcessHeap(),
|
|
0,
|
|
pvMemory
|
|
);
|
|
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: LsapAllocatePrivateHeap
|
|
//
|
|
// Synopsis: Allocates memory on private heap(s)
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: cbMemory -- Size of block needed
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: ptr to memory
|
|
//
|
|
// Per object reuse rules of C2 and above, we zero any memory
|
|
// allocated through this function
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
PVOID
|
|
NTAPI
|
|
LsapAllocatePrivateHeap(
|
|
IN SIZE_T cbMemory
|
|
)
|
|
{
|
|
HANDLE hHeap;
|
|
|
|
PHEAP_HEADER_LSA memory;
|
|
|
|
|
|
hHeap = LsapGetCurrentHeap();
|
|
|
|
if( hHeap == NULL )
|
|
{
|
|
static ULONG heapindex;
|
|
ULONG LocalHeapIndex;
|
|
|
|
LocalHeapIndex = (ULONG)InterlockedIncrement( (PLONG)&heapindex );
|
|
LocalHeapIndex %= gcHeaps;
|
|
|
|
hHeap = gHeaps[ LocalHeapIndex ];
|
|
|
|
LsapSetCurrentHeap( hHeap );
|
|
}
|
|
|
|
memory = (PHEAP_HEADER_LSA)RtlAllocateHeap(
|
|
hHeap,
|
|
HEAP_ZERO_MEMORY,
|
|
cbMemory+sizeof(HEAP_HEADER_LSA)
|
|
);
|
|
|
|
if( memory != NULL )
|
|
{
|
|
|
|
memory->hHeap = hHeap;
|
|
memory->Magic = (unsigned char*)HEAP_MAGIC_TAG-(unsigned char*)hHeap;
|
|
|
|
return ( (unsigned char*)memory+sizeof(HEAP_HEADER_LSA) );
|
|
}
|
|
|
|
DebugLog((DEB_ERROR,"LsapAllocatePrivateHeap: %p failed allocate %lu bytes\n", hHeap, cbMemory));
|
|
|
|
return NULL;
|
|
}
|
|
|
|
PVOID
|
|
NTAPI
|
|
LsapAllocatePrivateHeapNoZero(
|
|
IN SIZE_T cbMemory
|
|
)
|
|
{
|
|
HANDLE hHeap;
|
|
|
|
PHEAP_HEADER_LSA memory;
|
|
|
|
|
|
hHeap = LsapGetCurrentHeap();
|
|
|
|
if( hHeap == NULL )
|
|
{
|
|
static ULONG heapindex;
|
|
ULONG LocalHeapIndex;
|
|
|
|
LocalHeapIndex = (ULONG)InterlockedIncrement( (PLONG)&heapindex );
|
|
LocalHeapIndex %= gcHeaps;
|
|
|
|
hHeap = gHeaps[ LocalHeapIndex ];
|
|
|
|
LsapSetCurrentHeap( hHeap );
|
|
}
|
|
|
|
memory = (PHEAP_HEADER_LSA)RtlAllocateHeap(
|
|
hHeap,
|
|
0,
|
|
cbMemory+sizeof(HEAP_HEADER_LSA)
|
|
);
|
|
|
|
if( memory != NULL )
|
|
{
|
|
memory->hHeap = hHeap;
|
|
memory->Magic = (unsigned char*)HEAP_MAGIC_TAG-(unsigned char*)hHeap;
|
|
|
|
return ( (unsigned char*)memory+sizeof(HEAP_HEADER_LSA) );
|
|
}
|
|
|
|
DebugLog((DEB_ERROR,"LsapAllocatePrivateHeapNoZero: %p failed allocate %lu bytes\n", hHeap, cbMemory));
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: LsapFreePrivateHeap
|
|
//
|
|
// Synopsis: Frees memory allocated by LsapAllocatePrivateHeap
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: pvMemory
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void
|
|
NTAPI
|
|
LsapFreePrivateHeap(
|
|
IN PVOID pvMemory
|
|
)
|
|
{
|
|
PHEAP_HEADER_LSA HeapEntry;
|
|
|
|
if( pvMemory == NULL )
|
|
{
|
|
return ;
|
|
}
|
|
|
|
HeapEntry = (PHEAP_HEADER_LSA)((unsigned char*)pvMemory-sizeof(HEAP_HEADER_LSA));
|
|
|
|
if( HeapEntry->Magic + ((unsigned char*)HeapEntry->hHeap) != (unsigned char*)HEAP_MAGIC_TAG )
|
|
{
|
|
DebugLog((DEB_ERROR, "LsapFreePrivateHeap tried to free %p from wrong heap\n",
|
|
pvMemory));
|
|
|
|
DsysAssert( pvMemory == NULL );
|
|
return;
|
|
}
|
|
|
|
RtlFreeHeap(
|
|
HeapEntry->hHeap,
|
|
0,
|
|
HeapEntry
|
|
);
|
|
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: LsapClientAllocate
|
|
//
|
|
// Synopsis: Allocates memory in client process
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: cbMemory -- Size of block to allocate
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: pointer to memory in client address space
|
|
//
|
|
// Notes: pointer is not valid in this process, only in client
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
PVOID NTAPI
|
|
LsapClientAllocate(
|
|
IN ULONG cbMemory
|
|
)
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
PSession pSession;
|
|
void * pClientMemory = NULL;
|
|
SIZE_T cbMem = cbMemory;
|
|
PLSA_CALL_INFO CallInfo ;
|
|
|
|
CallInfo = LsapGetCurrentCall();
|
|
|
|
pSession = GetCurrentSession() ;
|
|
|
|
if ( pSession == NULL )
|
|
{
|
|
pSession = pDefaultSession ;
|
|
}
|
|
|
|
if ( CallInfo == NULL )
|
|
{
|
|
CallInfo = &LsapDefaultCallInfo ;
|
|
}
|
|
|
|
if (FAILED(CheckCaller(pSession)))
|
|
{
|
|
return(NULL);
|
|
}
|
|
|
|
//
|
|
// If the INPROC flag is set, allocate out of the heap. The copy functions
|
|
// will also honor this.
|
|
//
|
|
|
|
if ( pSession->fSession & SESFLAG_INPROC )
|
|
{
|
|
pClientMemory = LsapAllocateLsaHeap( (ULONG) cbMem );
|
|
|
|
return( pClientMemory );
|
|
}
|
|
|
|
if ( CallInfo->Flags & CALL_FLAG_KERNEL_POOL )
|
|
{
|
|
if ( ( CallInfo->Flags & CALL_FLAG_KMAP_USED ) != 0 )
|
|
{
|
|
|
|
pClientMemory = LsapAllocateFromKsecBuffer(
|
|
CallInfo->KMap,
|
|
(ULONG) cbMem );
|
|
|
|
DebugLog((DEB_TRACE_HELPERS, "[%x] LsapClientAllocate(%d) = %p in KMap %p\n",
|
|
pSession->dwProcessID, cbMem,
|
|
pClientMemory, CallInfo->KMap ));
|
|
|
|
return pClientMemory ;
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
Status = NtAllocateVirtualMemory(pSession->hProcess,
|
|
&pClientMemory,
|
|
0,
|
|
&cbMem,
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DebugLog((DEB_ERROR, "[%x] Could not allocate client memory (%x)\n",
|
|
pSession->dwProcessID, Status));
|
|
|
|
pClientMemory = NULL;
|
|
}
|
|
|
|
|
|
DebugLog((DEB_TRACE_HELPERS, "[%x] LsapClientAllocate(%d) = %p\n",
|
|
pSession->dwProcessID, cbMemory, pClientMemory));
|
|
|
|
if ( pClientMemory )
|
|
{
|
|
// Save pointer so that FreeContextBuffer will use
|
|
// correct 'free' function.
|
|
if(CallInfo->Allocs < MAX_BUFFERS_IN_CALL)
|
|
{
|
|
CallInfo->Buffers[ CallInfo->Allocs++ ] = pClientMemory ;
|
|
}
|
|
}
|
|
|
|
return(pClientMemory);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: LsapCopyToClient
|
|
//
|
|
// Synopsis: Copies data into client process
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: pLocalMemory -- pointer to data in this process
|
|
// pClientMemory -- pointer to destination in client process
|
|
// cbMemory -- how much to copy
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
NTSTATUS NTAPI
|
|
LsapCopyToClient(
|
|
IN PVOID pLocalMemory,
|
|
OUT PVOID pClientMemory,
|
|
IN ULONG cbMemory
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
PSession pSession;
|
|
PLSA_CALL_INFO CallInfo;
|
|
PKSEC_LSA_MEMORY_HEADER Header ;
|
|
ULONG i ;
|
|
ULONG_PTR Basis ;
|
|
ULONG_PTR Limit ;
|
|
BOOL Tried = FALSE ;
|
|
|
|
if (cbMemory == 0)
|
|
{
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
pSession = GetCurrentSession();
|
|
|
|
if ( !pSession )
|
|
{
|
|
pSession = pDefaultSession ;
|
|
}
|
|
|
|
CallInfo = LsapGetCurrentCall();
|
|
|
|
if ( ( pLocalMemory == NULL ) ||
|
|
( pClientMemory == NULL ) )
|
|
{
|
|
return STATUS_ACCESS_VIOLATION ;
|
|
}
|
|
|
|
if (FAILED(Status = CheckCaller(pSession)))
|
|
{
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// Cases for a direct copy:
|
|
//
|
|
// - The current session is the default session
|
|
// - This is an inproc call
|
|
// - We're using a KMap buffer
|
|
//
|
|
|
|
|
|
if (CallInfo &&
|
|
CallInfo->Flags & CALL_FLAG_KERNEL_POOL )
|
|
{
|
|
|
|
Header = CallInfo->KMap ;
|
|
|
|
if ( (ULONG_PTR) pClientMemory > LsapUserModeLimit )
|
|
{
|
|
//
|
|
// Someone is trying to deal with a pool address directly.
|
|
// we can handle this if it was copied into the KMap already
|
|
//
|
|
|
|
for ( i = 0 ; i < Header->MapCount ; i++ )
|
|
{
|
|
Limit = (ULONG_PTR) Header->PoolMap[ i ].Pool + Header->PoolMap[ i ].Size ;
|
|
|
|
if ( ((ULONG_PTR) pClientMemory >= (ULONG_PTR) Header->PoolMap[ i ].Pool ) &&
|
|
( (ULONG_PTR) pClientMemory < Limit ) )
|
|
{
|
|
//
|
|
// Found an overlap, this is promising. Check the bounds:
|
|
//
|
|
|
|
Basis = (ULONG_PTR) pClientMemory -
|
|
(ULONG_PTR) Header->PoolMap[ i ].Pool ;
|
|
|
|
if ( Basis + cbMemory <= Header->PoolMap[ i ].Size )
|
|
{
|
|
//
|
|
// Found it!
|
|
//
|
|
__try
|
|
{
|
|
RtlCopyMemory(
|
|
(PUCHAR) Header +
|
|
(Header->PoolMap[ i ].Offset +
|
|
Basis),
|
|
pLocalMemory,
|
|
cbMemory );
|
|
|
|
|
|
Status = STATUS_SUCCESS ;
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
Status = GetExceptionCode();
|
|
}
|
|
|
|
|
|
}
|
|
Tried = TRUE ;
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( !Tried )
|
|
{
|
|
Status = STATUS_ACCESS_VIOLATION ;
|
|
|
|
}
|
|
|
|
}
|
|
else if ( LsapIsBlockInKMap( CallInfo->KMap, pClientMemory ) )
|
|
{
|
|
__try
|
|
{
|
|
|
|
RtlCopyMemory( pClientMemory, pLocalMemory, cbMemory );
|
|
|
|
Status = STATUS_SUCCESS ;
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
Status = GetExceptionCode();
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
Status = NtWriteVirtualMemory(pSession->hProcess,
|
|
pClientMemory,
|
|
pLocalMemory,
|
|
cbMemory,
|
|
NULL);
|
|
}
|
|
|
|
} else if ( (pSession->dwProcessID == pDefaultSession->dwProcessID) ||
|
|
(pSession->fSession & SESFLAG_INPROC) ||
|
|
(CallInfo->Flags & CALL_FLAG_KMAP_USED ) )
|
|
{
|
|
__try
|
|
{
|
|
|
|
RtlCopyMemory( pClientMemory, pLocalMemory, cbMemory );
|
|
|
|
Status = STATUS_SUCCESS ;
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
Status = GetExceptionCode();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
Status = NtWriteVirtualMemory( pSession->hProcess,
|
|
pClientMemory,
|
|
pLocalMemory,
|
|
cbMemory,
|
|
NULL);
|
|
}
|
|
|
|
DebugLog((DEB_TRACE_HELPERS, "[%x] LsapCopyToClient(%p, %p, %d) = %x\n",
|
|
pSession->dwProcessID, pLocalMemory, pClientMemory, cbMemory,
|
|
Status ));
|
|
|
|
return(Status);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: LsapCopyFromClient
|
|
//
|
|
// Synopsis: Copies memory from client to this process
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: pClientMemory -- Pointer to data in client space
|
|
// pLocalMemory -- Pointer to destination in this process
|
|
// cbMemory -- How much
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
NTSTATUS NTAPI
|
|
LsapCopyFromClient(
|
|
IN PVOID pClientMemory,
|
|
OUT PVOID pLocalMemory,
|
|
IN ULONG cbMemory
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
PSession pSession;
|
|
PLSA_CALL_INFO CallInfo ;
|
|
PKSEC_LSA_MEMORY_HEADER Header ;
|
|
ULONG i ;
|
|
ULONG_PTR Basis ;
|
|
ULONG_PTR Limit ;
|
|
BOOL Tried = FALSE ;
|
|
|
|
|
|
|
|
if (cbMemory == 0)
|
|
{
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
if ( ( pClientMemory == NULL ) ||
|
|
( pLocalMemory == NULL ) )
|
|
{
|
|
return STATUS_ACCESS_VIOLATION ;
|
|
}
|
|
|
|
|
|
pSession = GetCurrentSession();
|
|
|
|
if ( pSession == NULL )
|
|
{
|
|
pSession = pDefaultSession ;
|
|
}
|
|
|
|
CallInfo = LsapGetCurrentCall();
|
|
|
|
if (FAILED(Status = CheckCaller(pSession)))
|
|
{
|
|
return(Status);
|
|
}
|
|
|
|
if (CallInfo &&
|
|
CallInfo->Flags & CALL_FLAG_KERNEL_POOL )
|
|
{
|
|
|
|
Header = CallInfo->KMap ;
|
|
|
|
if ( (ULONG_PTR) pClientMemory > LsapUserModeLimit )
|
|
{
|
|
//
|
|
// Someone is trying to deal with a pool address directly.
|
|
// we can handle this if it was copied into the KMap already
|
|
//
|
|
|
|
for ( i = 0 ; i < Header->MapCount ; i++ )
|
|
{
|
|
Limit = (ULONG_PTR) Header->PoolMap[ i ].Pool + Header->PoolMap[ i ].Size ;
|
|
|
|
if ( ((ULONG_PTR) pClientMemory >= (ULONG_PTR) Header->PoolMap[ i ].Pool ) &&
|
|
( (ULONG_PTR) pClientMemory < Limit ) )
|
|
{
|
|
//
|
|
// Found an overlap, this is promising. Check the bounds:
|
|
//
|
|
|
|
Basis = (ULONG_PTR) pClientMemory -
|
|
(ULONG_PTR) Header->PoolMap[ i ].Pool ;
|
|
|
|
if ( Basis + cbMemory <= Header->PoolMap[ i ].Size )
|
|
{
|
|
//
|
|
// Found it!
|
|
//
|
|
__try
|
|
{
|
|
RtlCopyMemory(
|
|
pLocalMemory,
|
|
(PUCHAR) Header +
|
|
(Header->PoolMap[ i ].Offset +
|
|
Basis),
|
|
cbMemory );
|
|
|
|
|
|
Status = STATUS_SUCCESS ;
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
Status = GetExceptionCode();
|
|
}
|
|
|
|
|
|
}
|
|
Tried = TRUE ;
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( !Tried )
|
|
{
|
|
Status = STATUS_ACCESS_VIOLATION ;
|
|
|
|
}
|
|
|
|
}
|
|
else if ( LsapIsBlockInKMap( CallInfo->KMap, pClientMemory ) )
|
|
{
|
|
__try
|
|
{
|
|
|
|
RtlCopyMemory( pLocalMemory, pClientMemory, cbMemory );
|
|
|
|
Status = STATUS_SUCCESS ;
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
Status = GetExceptionCode();
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
Status = NtReadVirtualMemory(pSession->hProcess,
|
|
pClientMemory,
|
|
pLocalMemory,
|
|
cbMemory,
|
|
NULL);
|
|
}
|
|
|
|
}
|
|
else if ( (pSession->dwProcessID == pDefaultSession->dwProcessID) ||
|
|
(pSession->fSession & SESFLAG_INPROC ) )
|
|
{
|
|
__try
|
|
{
|
|
|
|
RtlCopyMemory( pLocalMemory, pClientMemory, cbMemory );
|
|
|
|
Status = STATUS_SUCCESS ;
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
Status = GetExceptionCode();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
Status = NtReadVirtualMemory(pSession->hProcess,
|
|
pClientMemory,
|
|
pLocalMemory,
|
|
cbMemory,
|
|
NULL);
|
|
}
|
|
|
|
DebugLog((DEB_TRACE_HELPERS, "[%x] LsapCopyFromClient(%p, %p, %d) = %x\n",
|
|
pSession->dwProcessID, pClientMemory, pLocalMemory, cbMemory,
|
|
Status));
|
|
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: LsapClientFree
|
|
//
|
|
// Synopsis: Frees memory allocated in client space
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: pClientMemory -- pointer to memory to free
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
NTSTATUS NTAPI
|
|
LsapClientFree(
|
|
IN PVOID pClientMemory
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
SIZE_T cbMem = 0;
|
|
PSession pSession;
|
|
PLSA_CALL_INFO CallInfo ;
|
|
|
|
CallInfo = LsapGetCurrentCall();
|
|
if ( CallInfo == NULL )
|
|
{
|
|
CallInfo = &LsapDefaultCallInfo ;
|
|
}
|
|
|
|
if (!pClientMemory)
|
|
{
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
pSession = GetCurrentSession();
|
|
|
|
if ( pSession == NULL )
|
|
{
|
|
pSession = pDefaultSession ;
|
|
}
|
|
|
|
if (FAILED(Status = CheckCaller(pSession)))
|
|
{
|
|
return(Status);
|
|
}
|
|
|
|
if ( pSession->fSession & SESFLAG_INPROC )
|
|
{
|
|
LsapFreeLsaHeap( pClientMemory );
|
|
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
|
|
#if DBG
|
|
if ( pSession->dwProcessID == pDefaultSession->dwProcessID )
|
|
{
|
|
DebugLog(( DEB_ERROR, "Freeing VM in LSA: %x\n", pClientMemory ));
|
|
}
|
|
#endif
|
|
|
|
Status = NtFreeVirtualMemory(pSession->hProcess,
|
|
&pClientMemory,
|
|
&cbMem,
|
|
MEM_RELEASE);
|
|
|
|
|
|
|
|
if ( pClientMemory )
|
|
{
|
|
ULONG i;
|
|
|
|
// Remove this pointer from our list.
|
|
for(i = 0; i < CallInfo->Allocs; i++)
|
|
{
|
|
if(CallInfo->Buffers[i] == pClientMemory)
|
|
{
|
|
if(i < CallInfo->Allocs - 1)
|
|
{
|
|
memcpy(&CallInfo->Buffers[i],
|
|
&CallInfo->Buffers[i+1],
|
|
sizeof(PVOID) * (CallInfo->Allocs - i - 1));
|
|
}
|
|
CallInfo->Allocs--;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
DebugLog((DEB_TRACE_HELPERS, "[%x] LsapClientFree(%x) == %x\n",
|
|
pSession->dwProcessID, pClientMemory, Status));
|
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: LsapDuplicateHandle
|
|
//
|
|
// Synopsis: Duplicates a handle to an NT object into the calling process
|
|
//
|
|
// Effects: A new handle is generated, referencing the object
|
|
//
|
|
// Arguments: hObject -- handle to the object
|
|
// hNewObject -- New handle valid in calling process
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
NTSTATUS NTAPI
|
|
LsapDuplicateHandle(
|
|
IN HANDLE hObject,
|
|
OUT PHANDLE phNewObject
|
|
)
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
PSession pSession;
|
|
|
|
pSession = GetCurrentSession();
|
|
|
|
if ( pSession == NULL )
|
|
{
|
|
pSession = pDefaultSession ;
|
|
}
|
|
|
|
if (Status = CheckCaller(pSession))
|
|
{
|
|
DebugLog((DEB_ERROR, "CheckCaller returned %d\n", Status));
|
|
return(Status);
|
|
}
|
|
Status = NtDuplicateObject( NtCurrentProcess(),
|
|
hObject,
|
|
pSession->hProcess,
|
|
phNewObject,
|
|
0,
|
|
0,
|
|
DUPLICATE_SAME_ACCESS);
|
|
|
|
|
|
DebugLog((DEB_TRACE_HELPERS, "[%x] LsapDupHandle(%x, %x (@%x)) = %x\n",
|
|
pSession->dwProcessID, hObject, *phNewObject, phNewObject, Status));
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LsapImpersonateClient
|
|
//
|
|
// Synopsis: Impersonate the client of the API call.
|
|
//
|
|
// Arguments: (none)
|
|
//
|
|
// History: 6-05-95 RichardW Created
|
|
//
|
|
// Notes: Threads should call RevertToSelf() when done.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
NTSTATUS NTAPI
|
|
LsapImpersonateClient(
|
|
VOID
|
|
)
|
|
{
|
|
PSession pSession;
|
|
PLSA_CALL_INFO CallInfo ;
|
|
PSPM_LPC_MESSAGE pApiMessage;
|
|
NTSTATUS Status;
|
|
|
|
|
|
CallInfo = LsapGetCurrentCall() ;
|
|
|
|
if ( CallInfo->InProcCall )
|
|
{
|
|
if ( CallInfo->InProcToken )
|
|
{
|
|
Status = NtSetInformationThread(
|
|
NtCurrentThread(),
|
|
ThreadImpersonationToken,
|
|
(PVOID) &CallInfo->InProcToken,
|
|
sizeof(HANDLE)
|
|
);
|
|
}
|
|
else
|
|
{
|
|
Status = RtlImpersonateSelf(SecurityImpersonation);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pSession = GetCurrentSession() ;
|
|
|
|
if ( !pSession )
|
|
{
|
|
pSession = pDefaultSession ;
|
|
}
|
|
|
|
Status = NtImpersonateClientOfPort(
|
|
pSession->hPort,
|
|
(PPORT_MESSAGE) CallInfo->Message);
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: LsapDuplicateString
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
NTSTATUS
|
|
LsapDuplicateString(
|
|
OUT PUNICODE_STRING pDest,
|
|
IN PUNICODE_STRING pSrc
|
|
)
|
|
|
|
{
|
|
pDest->Length = 0;
|
|
if (pSrc == NULL)
|
|
{
|
|
pDest->Buffer = NULL;
|
|
pDest->MaximumLength = 0;
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
pDest->Buffer = (LPWSTR) LsapAllocateLsaHeap(pSrc->Length + sizeof(WCHAR));
|
|
if (pDest->Buffer)
|
|
{
|
|
pDest->MaximumLength = pSrc->Length + sizeof(WCHAR);
|
|
RtlCopyMemory(
|
|
pDest->Buffer,
|
|
pSrc->Buffer,
|
|
pSrc->Length
|
|
);
|
|
pDest->Buffer[pSrc->Length/sizeof(WCHAR)] = L'\0';
|
|
pDest->Length = pSrc->Length;
|
|
return(STATUS_SUCCESS);
|
|
|
|
} else
|
|
{
|
|
pDest->MaximumLength = 0;
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
LsapDuplicateString2(
|
|
OUT PUNICODE_STRING pDest,
|
|
IN PUNICODE_STRING pSrc
|
|
)
|
|
/*++
|
|
|
|
Same as LsapDuplicateString(), but uses LsapPrivateHeap routines.
|
|
|
|
--*/
|
|
{
|
|
pDest->Length = 0;
|
|
if (pSrc == NULL)
|
|
{
|
|
pDest->Buffer = NULL;
|
|
pDest->MaximumLength = 0;
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
pDest->Buffer = (LPWSTR) LsapAllocatePrivateHeap(pSrc->Length + sizeof(WCHAR));
|
|
if (pDest->Buffer)
|
|
{
|
|
pDest->MaximumLength = pSrc->Length + sizeof(WCHAR);
|
|
RtlCopyMemory(
|
|
pDest->Buffer,
|
|
pSrc->Buffer,
|
|
pSrc->Length
|
|
);
|
|
pDest->Buffer[pSrc->Length/sizeof(WCHAR)] = L'\0';
|
|
pDest->Length = pSrc->Length;
|
|
return(STATUS_SUCCESS);
|
|
|
|
} else
|
|
{
|
|
pDest->MaximumLength = 0;
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: LsapFreeString
|
|
//
|
|
// Synopsis: Frees a string allocated by LsapDuplicateString
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: String - Optionally points to a UNICODE_STRING
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
VOID
|
|
LsapFreeString(
|
|
IN OPTIONAL PUNICODE_STRING String
|
|
)
|
|
{
|
|
if (ARGUMENT_PRESENT(String) && String->Buffer != NULL)
|
|
{
|
|
LsapFreeLsaHeap(String->Buffer);
|
|
String->Buffer = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: LsapThreadBase
|
|
//
|
|
// Synopsis: Thread start routine
|
|
//
|
|
// Effects: Sets up all the TLS data for a thread, then executes
|
|
// the "real" base function.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
void
|
|
LsapThreadBase(
|
|
PLSAP_THREAD_START pThread)
|
|
{
|
|
NTSTATUS Status;
|
|
PSession pSession;
|
|
LSAP_THREAD_START tStart = *pThread;
|
|
|
|
LsapFreePrivateHeap(pThread);
|
|
|
|
SetCurrentSession( pDefaultSession );
|
|
|
|
SpmpReferenceSession( pDefaultSession );
|
|
|
|
// Initialize Session information:
|
|
|
|
SetCurrentPackageId(tStart.dwPackageID);
|
|
|
|
|
|
DebugLog((DEB_TRACE, "Thread start @%x\n", tStart.lpStart));
|
|
|
|
// If this is a debug build, all threads are started in a protective
|
|
// try-except block. For retail, only threads started by packages
|
|
// will be run this way. Retail builds, we assume that the SPM is
|
|
// debugged and running correctly, and threads started this way can
|
|
// be trusted.
|
|
|
|
#if DBG == 0
|
|
if (tStart.dwPackageID != SPMGR_ID)
|
|
#endif
|
|
{
|
|
__try
|
|
{
|
|
tStart.lpStart(tStart.lpParm);
|
|
}
|
|
__except (SP_EXCEPTION)
|
|
{
|
|
Status = GetExceptionCode();
|
|
Status = SPException(Status, tStart.dwPackageID);
|
|
}
|
|
}
|
|
#if DBG == 0
|
|
else
|
|
{
|
|
tStart.lpStart(tStart.lpParm);
|
|
}
|
|
#endif
|
|
|
|
pSession = GetCurrentSession();
|
|
|
|
SpmpDereferenceSession( pSession );
|
|
|
|
if ( pSession != pDefaultSession )
|
|
{
|
|
DebugLog(( DEB_ERROR, "Thread completing in session other than default!\n" ));
|
|
}
|
|
|
|
DebugLog((DEB_TRACE, "Thread exit\n" ));
|
|
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: LsapCreateThread
|
|
//
|
|
// Synopsis: Creates a thread with all the proper Tls stuff
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: same as CreateThread
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HANDLE NTAPI
|
|
LsapCreateThread(
|
|
IN LPSECURITY_ATTRIBUTES lpSA,
|
|
IN ULONG cbStack,
|
|
IN LPTHREAD_START_ROUTINE lpStart,
|
|
IN LPVOID lpvThreadParm,
|
|
IN ULONG fCreate,
|
|
OUT PULONG lpTID
|
|
)
|
|
{
|
|
PLSAP_THREAD_START pThread;
|
|
HANDLE hThread;
|
|
|
|
pThread = (PLSAP_THREAD_START) LsapAllocatePrivateHeap(sizeof(LSAP_THREAD_START));
|
|
if (pThread == NULL)
|
|
{
|
|
DebugLog((DEB_ERROR, "LsapCreateThread, memory allocation failed.\n"));
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return(NULL);
|
|
}
|
|
|
|
pThread->lpStart = lpStart;
|
|
pThread->lpParm = lpvThreadParm;
|
|
pThread->dwPackageID = GetCurrentPackageId();
|
|
|
|
hThread = CreateThread(
|
|
lpSA,
|
|
cbStack,
|
|
(LPTHREAD_START_ROUTINE) LsapThreadBase,
|
|
pThread,
|
|
fCreate,
|
|
lpTID
|
|
);
|
|
|
|
if( hThread == NULL )
|
|
{
|
|
DebugLog((DEB_ERROR, "LsapCreateThread, failed thread creation (%lu)\n", GetLastError()));
|
|
|
|
LsapFreePrivateHeap( pThread );
|
|
}
|
|
|
|
return hThread;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: LsapGetClientInfo
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
NTSTATUS NTAPI
|
|
LsapGetClientInfo(
|
|
OUT PSECPKG_CLIENT_INFO ClientInfo
|
|
)
|
|
{
|
|
PSession pSession = GetCurrentSession();
|
|
PPORT_MESSAGE pMessage;
|
|
HANDLE ClientToken;
|
|
NTSTATUS Status;
|
|
NTSTATUS ExtraStatus ;
|
|
TOKEN_STATISTICS TokenStats;
|
|
ULONG TokenStatsSize = sizeof(TOKEN_STATISTICS);
|
|
PLSA_CALL_INFO CallInfo ;
|
|
HANDLE Thread = NULL ;
|
|
OBJECT_ATTRIBUTES NullAttributes = { 0 };
|
|
KERNEL_USER_TIMES Times ;
|
|
|
|
|
|
RtlZeroMemory(
|
|
ClientInfo,
|
|
sizeof(SECPKG_CLIENT_INFO)
|
|
);
|
|
|
|
if ( !pSession )
|
|
{
|
|
pSession = pDefaultSession ;
|
|
}
|
|
|
|
//
|
|
// First, fill in the easy stuff from the session record. If we are
|
|
// running with the LSA session then we want to ignore the LPC message
|
|
// because it may be referring to somebody elses message (we may be
|
|
// being called on behalf of someone doing authenticated RPC in response
|
|
// to an LPC request)
|
|
//
|
|
|
|
CallInfo = LsapGetCurrentCall();
|
|
|
|
if ( CallInfo )
|
|
{
|
|
ClientInfo->ProcessID = CallInfo->CallInfo.ProcessId ;
|
|
ClientInfo->ThreadID = CallInfo->CallInfo.ThreadId ;
|
|
|
|
if (((pSession->fSession & SESFLAG_TCB_PRIV) != 0) ||
|
|
((pSession->fSession & SESFLAG_KERNEL) != 0))
|
|
{
|
|
ClientInfo->HasTcbPrivilege = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ClientInfo->HasTcbPrivilege = FALSE;
|
|
}
|
|
|
|
if(CallInfo->CachedTokenInfo)
|
|
{
|
|
ClientInfo->LogonId = CallInfo->LogonId;
|
|
ClientInfo->Restricted = CallInfo->Restricted;
|
|
ClientInfo->Impersonating = CallInfo->Impersonating;
|
|
ClientInfo->ImpersonationLevel = CallInfo->ImpersonationLevel;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
Status = LsapImpersonateClient();
|
|
|
|
|
|
if ( !NT_SUCCESS( Status ) )
|
|
{
|
|
if ( Status == STATUS_BAD_IMPERSONATION_LEVEL )
|
|
{
|
|
Status = NtOpenThread(
|
|
&Thread,
|
|
THREAD_QUERY_INFORMATION,
|
|
&NullAttributes,
|
|
&CallInfo->Message->pmMessage.ClientId );
|
|
}
|
|
else if ( ( Status == STATUS_REPLY_MESSAGE_MISMATCH ) ||
|
|
( Status == STATUS_INVALID_CID ) ||
|
|
( Status == STATUS_PORT_DISCONNECTED ) )
|
|
{
|
|
//
|
|
// This is a special status returned by the LPC layer to indicate
|
|
// that the client thread has disappeared, or the process is
|
|
// terminating. Set a flag to indicate this:
|
|
//
|
|
|
|
ClientInfo->ClientFlags |= SECPKG_CLIENT_THREAD_TERMINATED ;
|
|
|
|
CallInfo->CallInfo.Attributes |= SECPKG_CALL_THREAD_TERM ;
|
|
//
|
|
// Check the process. If the process has started to exit, set that
|
|
// flag as well.
|
|
//
|
|
|
|
ExtraStatus = NtQueryInformationProcess(
|
|
pSession->hProcess,
|
|
ProcessTimes,
|
|
&Times,
|
|
sizeof( Times ),
|
|
NULL );
|
|
|
|
if ( NT_SUCCESS( ExtraStatus ) )
|
|
{
|
|
if ( Times.ExitTime.QuadPart != 0 )
|
|
{
|
|
ClientInfo->ClientFlags |= SECPKG_CLIENT_PROCESS_TERMINATED ;
|
|
CallInfo->CallInfo.Attributes |= SECPKG_CALL_PROCESS_TERM ;
|
|
}
|
|
}
|
|
|
|
DebugLog(( DEB_TRACE, "Client %x.%x has terminated\n",
|
|
ClientInfo->ProcessID, ClientInfo->ThreadID ));
|
|
|
|
return STATUS_SUCCESS ;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
Thread = NtCurrentThread();
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DebugLog((DEB_WARN,"Failed to impersonate client: 0x%x\n",Status));
|
|
return(Status);
|
|
}
|
|
|
|
Status = NtOpenThreadToken(
|
|
Thread,
|
|
TOKEN_QUERY,
|
|
TRUE, // use LSA security context
|
|
&ClientToken
|
|
);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
ClientInfo->Restricted = ( IsTokenRestricted(ClientToken) != 0 );
|
|
|
|
Status = NtQueryInformationToken(
|
|
ClientToken,
|
|
TokenStatistics,
|
|
(PVOID) &TokenStats,
|
|
TokenStatsSize,
|
|
&TokenStatsSize
|
|
);
|
|
NtClose(ClientToken);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
ClientInfo->LogonId = TokenStats.AuthenticationId;
|
|
ClientInfo->Impersonating = (TokenStats.TokenType == TokenPrimary) ? FALSE : TRUE;
|
|
if( ClientInfo->Impersonating )
|
|
{
|
|
ClientInfo->ImpersonationLevel = TokenStats.ImpersonationLevel;
|
|
} else {
|
|
ClientInfo->ImpersonationLevel = SecurityImpersonation;
|
|
}
|
|
}
|
|
}
|
|
RevertToSelf();
|
|
if ( Thread != NtCurrentThread() )
|
|
{
|
|
NtClose( Thread );
|
|
}
|
|
|
|
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
CallInfo->LogonId = ClientInfo->LogonId;
|
|
CallInfo->Restricted = ClientInfo->Restricted;
|
|
CallInfo->Impersonating = ClientInfo->Impersonating;
|
|
CallInfo->ImpersonationLevel = ClientInfo->ImpersonationLevel;
|
|
CallInfo->CachedTokenInfo = TRUE;
|
|
}
|
|
|
|
return(Status);
|
|
|
|
}
|
|
else
|
|
{
|
|
ClientInfo->ProcessID = GetCurrentProcessId();
|
|
ClientInfo->ThreadID = GetCurrentThreadId();
|
|
ClientInfo->HasTcbPrivilege = TRUE;
|
|
ClientInfo->Impersonating = FALSE;
|
|
ClientInfo->ImpersonationLevel = SecurityImpersonation;
|
|
ClientInfo->LogonId = SystemLogonId;
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LsapGetCallInfo
|
|
//
|
|
// Synopsis: Gets call information
|
|
//
|
|
// Arguments: [Info] --
|
|
//
|
|
// History: 10-06-96 RichardW Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOLEAN
|
|
LsapGetCallInfo(
|
|
PSECPKG_CALL_INFO Info
|
|
)
|
|
{
|
|
PLSA_CALL_INFO CallInfo ;
|
|
|
|
CallInfo = LsapGetCurrentCall() ;
|
|
|
|
if ( CallInfo )
|
|
{
|
|
*Info = CallInfo->CallInfo ;
|
|
if ( CallInfo->InProcCall )
|
|
{
|
|
Info->Attributes |= SECPKG_CALL_IN_PROC ;
|
|
}
|
|
|
|
return TRUE ;
|
|
} else {
|
|
Info->ProcessId = GetCurrentProcessId();
|
|
Info->ThreadId = GetCurrentThreadId();
|
|
Info->Attributes = SECPKG_CALL_IN_PROC |
|
|
SECPKG_CALL_IS_TCB ;
|
|
Info->CallCount = 0;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: LsapMapClientBuffer
|
|
//
|
|
// Synopsis: Maps a client's SecBuffer into the caller's address space
|
|
//
|
|
// Effects: Clears the SECBUFFER_UNMAPPED field of the BufferType of
|
|
// the return SecBuffer
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes: Doesn't modify pOutput until the end, so it is o.k. to pass
|
|
// the same thing for pInput and pOutput.
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
NTSTATUS
|
|
LsapMapClientBuffer(
|
|
IN PSecBuffer pInput,
|
|
OUT PSecBuffer pOutput
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS ;
|
|
SecBuffer Output ;
|
|
Output = *pInput ;
|
|
PLSA_CALL_INFO CallInfo = LsapGetCurrentCall();
|
|
|
|
//
|
|
// If the buffer is already mapped or it doesn't exist (is NULL) we
|
|
// are done.
|
|
//
|
|
|
|
if (!(pInput->BufferType & SECBUFFER_UNMAPPED) ||
|
|
!pInput->pvBuffer)
|
|
{
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
else
|
|
{
|
|
Output.BufferType &= ~SECBUFFER_UNMAPPED;
|
|
}
|
|
|
|
if ( pInput->BufferType & SECBUFFER_KERNEL_MAP )
|
|
{
|
|
//
|
|
// This one is already in process space
|
|
//
|
|
|
|
if ( ( CallInfo->CallInfo.Attributes & SECPKG_CALL_KERNEL_MODE ) == 0 )
|
|
{
|
|
//
|
|
// If this call did not come from kernel mode with
|
|
// the kernel-pool flag set, then this is an attempted
|
|
// hack on the LSA. Reject it.
|
|
//
|
|
|
|
Status = STATUS_ACCESS_VIOLATION ;
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The buffer is already in memory. Mark the call as
|
|
// using kernel-pool memory, so we allocate correctly
|
|
// on the return.
|
|
//
|
|
|
|
CallInfo->Flags |= CALL_FLAG_KERNEL_POOL ;
|
|
DebugLog((DEB_TRACE_SPECIAL, "Kernel Pool Map at %p [%x,%x]\n",
|
|
Output.pvBuffer, Output.BufferType, Output.cbBuffer ));
|
|
}
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
Output.pvBuffer = LsapAllocateLsaHeap( Output.cbBuffer );
|
|
|
|
if ( Output.pvBuffer != NULL )
|
|
{
|
|
Status = LsapCopyFromClient(
|
|
pInput->pvBuffer,
|
|
Output.pvBuffer,
|
|
Output.cbBuffer );
|
|
|
|
if ( !NT_SUCCESS( Status ) )
|
|
{
|
|
LsapFreeLsaHeap(Output.pvBuffer);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
Status = STATUS_NO_MEMORY ;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
if ( NT_SUCCESS( Status ) )
|
|
{
|
|
*pOutput = Output ;
|
|
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: LsaICallPackage
|
|
//
|
|
// Synopsis: Function to call another security package
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
extern "C"
|
|
NTSTATUS
|
|
LsaICallPackage(
|
|
IN PUNICODE_STRING AuthenticationPackage,
|
|
IN PVOID ProtocolSubmitBuffer,
|
|
IN ULONG SubmitBufferLength,
|
|
OUT PVOID *ProtocolReturnBuffer,
|
|
OUT PULONG ReturnBufferLength,
|
|
OUT PNTSTATUS ProtocolStatus
|
|
)
|
|
{
|
|
|
|
return LsaICallPackageEx( AuthenticationPackage,
|
|
ProtocolSubmitBuffer, // client buffer base is same as local buffer
|
|
ProtocolSubmitBuffer,
|
|
SubmitBufferLength,
|
|
ProtocolReturnBuffer,
|
|
ReturnBufferLength,
|
|
ProtocolStatus );
|
|
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: LsaICallPackageEx
|
|
//
|
|
// Synopsis: Function to call another security package
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
extern "C"
|
|
NTSTATUS
|
|
LsaICallPackageEx(
|
|
IN PUNICODE_STRING AuthenticationPackage,
|
|
IN PVOID ClientBufferBase,
|
|
IN PVOID ProtocolSubmitBuffer,
|
|
IN ULONG SubmitBufferLength,
|
|
OUT PVOID *ProtocolReturnBuffer,
|
|
OUT PULONG ReturnBufferLength,
|
|
OUT PNTSTATUS ProtocolStatus
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PLSAP_SECURITY_PACKAGE Package;
|
|
PSession OldSession;
|
|
|
|
Package = SpmpLookupPackageAndRequest(
|
|
AuthenticationPackage,
|
|
SP_ORDINAL_CALLPACKAGE
|
|
);
|
|
|
|
if (Package == NULL)
|
|
{
|
|
DebugLog((DEB_WARN,"LsapCallPackage failed: package %wZ not found\n",
|
|
AuthenticationPackage ));
|
|
Status = STATUS_NO_SUCH_PACKAGE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Set the session to be the LSA's so calls to allocate memory
|
|
// will allocate in the correct process
|
|
//
|
|
|
|
OldSession = GetCurrentSession();
|
|
SetCurrentSession( pDefaultSession );
|
|
|
|
Status = Package->FunctionTable.CallPackage(
|
|
NULL,
|
|
ProtocolSubmitBuffer,
|
|
ClientBufferBase,
|
|
SubmitBufferLength,
|
|
ProtocolReturnBuffer,
|
|
ReturnBufferLength,
|
|
ProtocolStatus
|
|
);
|
|
|
|
//
|
|
// Restore our original session
|
|
//
|
|
|
|
SetCurrentSession( OldSession );
|
|
|
|
|
|
Cleanup:
|
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: LsaICallPackagePassthrough
|
|
//
|
|
// Synopsis: Function to call another security package for pass-through request
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
extern "C"
|
|
NTSTATUS
|
|
LsaICallPackagePassthrough(
|
|
IN PUNICODE_STRING AuthenticationPackage,
|
|
IN PVOID ClientBufferBase,
|
|
IN PVOID ProtocolSubmitBuffer,
|
|
IN ULONG SubmitBufferLength,
|
|
OUT PVOID *ProtocolReturnBuffer,
|
|
OUT PULONG ReturnBufferLength,
|
|
OUT PNTSTATUS ProtocolStatus
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PLSAP_SECURITY_PACKAGE Package;
|
|
PSession OldSession;
|
|
|
|
Package = SpmpLookupPackageAndRequest(
|
|
AuthenticationPackage,
|
|
SP_ORDINAL_CALLPACKAGE
|
|
);
|
|
|
|
if (Package == NULL)
|
|
{
|
|
DebugLog((DEB_WARN,"LsapCallPackage failed: package %wZ not found\n",
|
|
AuthenticationPackage ));
|
|
Status = STATUS_NO_SUCH_PACKAGE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Set the session to be the LSA's so calls to allocate memory
|
|
// will allocate in the correct process
|
|
//
|
|
|
|
OldSession = GetCurrentSession();
|
|
SetCurrentSession( pDefaultSession );
|
|
|
|
Status = Package->FunctionTable.CallPackagePassthrough(
|
|
NULL,
|
|
ProtocolSubmitBuffer,
|
|
ClientBufferBase,
|
|
SubmitBufferLength,
|
|
ProtocolReturnBuffer,
|
|
ReturnBufferLength,
|
|
ProtocolStatus
|
|
);
|
|
|
|
//
|
|
// Restore our original session
|
|
//
|
|
|
|
SetCurrentSession( OldSession );
|
|
|
|
|
|
Cleanup:
|
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
extern "C"
|
|
VOID
|
|
LsaIFreeReturnBuffer(
|
|
IN PVOID Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Some of the LSA authentication services allocate memory buffers to
|
|
hold returned information. This service is used to free those buffers
|
|
when no longer needed.
|
|
|
|
Arguments:
|
|
|
|
Buffer - Supplies a pointer to the return buffer to be freed.
|
|
|
|
Return Status:
|
|
|
|
STATUS_SUCCESS - Indicates the service completed successfully.
|
|
|
|
Others - returned by NtFreeVirtualMemory().
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
SIZE_T Length;
|
|
|
|
Length = 0;
|
|
|
|
DebugLog(( DEB_TRACE_HELPERS, "LsaIFreeReturnBuffer - freeing VM at %x\n", Buffer ));
|
|
if (((ULONG_PTR) Buffer & 0xfff) != 0)
|
|
{
|
|
DbgPrint("Freeing non-page address: %p\n",Buffer);
|
|
DbgBreakPoint();
|
|
}
|
|
|
|
NtFreeVirtualMemory(
|
|
NtCurrentProcess(),
|
|
&Buffer,
|
|
&Length,
|
|
MEM_RELEASE
|
|
);
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
LsaClientCallback(
|
|
PCHAR Callback,
|
|
ULONG_PTR Argument1,
|
|
ULONG_PTR Argument2,
|
|
PSecBuffer Input,
|
|
PSecBuffer Output
|
|
)
|
|
{
|
|
PSession Session ;
|
|
ULONG Type ;
|
|
|
|
Session = GetCurrentSession();
|
|
|
|
if ( !Session )
|
|
{
|
|
Session = pDefaultSession ;
|
|
}
|
|
if ( !Session->hPort &&
|
|
((Session->fSession & SESFLAG_DEFAULT) == 0) )
|
|
{
|
|
return SEC_E_INVALID_HANDLE ;
|
|
}
|
|
|
|
if ( (ULONG_PTR) Callback < 0x00010000 )
|
|
{
|
|
Type = SPM_CALLBACK_PACKAGE ;
|
|
}
|
|
else
|
|
{
|
|
Type = SPM_CALLBACK_EXPORT ;
|
|
}
|
|
|
|
return LsapClientCallback( Session,
|
|
Type,
|
|
Callback,
|
|
(PVOID) Argument1,
|
|
(PVOID) Argument2,
|
|
Input,
|
|
Output );
|
|
}
|
|
|
|
|
|
#if 0
|
|
BOOL
|
|
LsapCaptureAuthData(
|
|
PVOID pvAuthData,
|
|
BOOLEAN DesiredAnsi,
|
|
PSEC_WINNT_AUTH_IDENTITY * AuthData
|
|
)
|
|
{
|
|
SEC_WINNT_AUTH_IDENTITY Auth ;
|
|
PSEC_WINNT_AUTH_IDENTITY pAuth ;
|
|
SECURITY_STATUS Status ;
|
|
ULONG TotalSize ;
|
|
|
|
PWSTR CurrentW ;
|
|
PSTR CurrentA ;
|
|
PVOID Current ;
|
|
|
|
PWSTR ConvertBufferW ;
|
|
PSTR ConvertBufferA ;
|
|
PVOID Convert;
|
|
|
|
ULONG Longest ;
|
|
|
|
|
|
ZeroMemory( &Auth, sizeof( Auth ) );
|
|
|
|
Status = LsapCopyFromClientBuffer(
|
|
NULL,
|
|
sizeof( SEC_WINNT_AUTH_IDENTITY ),
|
|
& Auth,
|
|
pvAuthData );
|
|
|
|
if ( !NT_SUCCESS( Status ) )
|
|
{
|
|
return FALSE ;
|
|
}
|
|
|
|
Longest = Auth.UserLength ;
|
|
Longest = max( Longest, Auth.DomainLength );
|
|
Longest = max( Longest, Auth.PasswordLength );
|
|
|
|
Longest = (Longest + 1) * sizeof(WCHAR);
|
|
|
|
//
|
|
// Always go with the extra, so we can handle DBCS
|
|
//
|
|
|
|
TotalSize = sizeof( SEC_WINNT_AUTH_IDENTITY ) +
|
|
( Auth.UserLength + 1 +
|
|
Auth.DomainLength + 1 +
|
|
Auth.PasswordLength + 1 ) * sizeof( WCHAR );
|
|
|
|
|
|
pAuth = (PSEC_WINNT_AUTH_IDENTITY) LsapAllocateLsaHeap( TotalSize );
|
|
|
|
if ( !pAuth )
|
|
{
|
|
return FALSE ;
|
|
}
|
|
|
|
ConvertBufferW = NULL ;
|
|
ConvertBufferA = NULL ;
|
|
Convert = NULL ;
|
|
CurrentA = NULL ;
|
|
CurrentW = NULL ;
|
|
|
|
if ( Auth.Flags & SEC_WINNT_AUTH_IDENTITY_ANSI )
|
|
{
|
|
if ( !DesiredAnsi )
|
|
{
|
|
ConvertBufferA = (PSTR) LocalAlloc( LMEM_FIXED, Longest );
|
|
Convert = ConvertBufferA ;
|
|
CurrentW = (PWSTR) (pAuth + 1);
|
|
}
|
|
else
|
|
{
|
|
CurrentA = (PSTR) (pAuth + 1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( DesiredAnsi )
|
|
{
|
|
ConvertBufferW = (PWSTR) LocalAlloc( LMEM_FIXED, Longest );
|
|
CurrentA = (PSTR) (pAuth + 1);
|
|
}
|
|
else
|
|
{
|
|
CurrentW = (PWSTR) pAuth + 1);
|
|
}
|
|
}
|
|
|
|
pAuth->Flags = Auth.Flags ;
|
|
|
|
CurrentW = (PWSTR) (pAuth + 1);
|
|
CurrentA = (PSTR) (pAuth + 1);
|
|
Current = CurrentW ;
|
|
|
|
if ( Auth.User )
|
|
{
|
|
pAuth->User = Current ;
|
|
|
|
Status = LsapCopyFromClientBuffer(
|
|
NULL,
|
|
(Auth.Flags & SEC_WINNT_AUTH_IDENTITY_ANSI ?
|
|
( Auth.UserLength + 1 ) :
|
|
( (Auth.UserLength + 1 ) * sizeof( WCHAR ) ) ),
|
|
(Convert ? Convert : Current ),
|
|
Auth.User );
|
|
|
|
if ( Convert )
|
|
{
|
|
if ( ConvertBufferA )
|
|
{
|
|
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
pAuth->UserLength = Auth.UserLength ;
|
|
}
|
|
|
|
Status = LsaTable->CopyFromClientBuffer(
|
|
NULL,
|
|
(Auth.UserLength + 1) * sizeof(WCHAR) ,
|
|
pAuth->User,
|
|
Auth.User );
|
|
|
|
if ( !NT_SUCCESS( Status ) )
|
|
{
|
|
goto Error_Cleanup ;
|
|
}
|
|
|
|
Current += Auth.UserLength + 1;
|
|
}
|
|
|
|
if ( Auth.Domain )
|
|
{
|
|
pAuth->Domain = Current ;
|
|
pAuth->DomainLength = Auth.DomainLength ;
|
|
|
|
Status = LsaTable->CopyFromClientBuffer(
|
|
NULL,
|
|
(Auth.DomainLength + 1) * sizeof( WCHAR ),
|
|
pAuth->Domain,
|
|
Auth.Domain );
|
|
|
|
if ( !NT_SUCCESS( Status ) )
|
|
{
|
|
goto Error_Cleanup ;
|
|
}
|
|
|
|
Current += Auth.DomainLength + 1;
|
|
|
|
}
|
|
|
|
if ( Auth.Password )
|
|
{
|
|
pAuth->Password = Current ;
|
|
pAuth->PasswordLength = Auth.PasswordLength ;
|
|
|
|
Status = LsaTable->CopyFromClientBuffer(
|
|
NULL,
|
|
(Auth.PasswordLength + 1) * sizeof( WCHAR ),
|
|
pAuth->Password,
|
|
Auth.Password );
|
|
|
|
if ( !NT_SUCCESS( Status ) )
|
|
{
|
|
goto Error_Cleanup ;
|
|
}
|
|
|
|
Current += Auth.PasswordLength + 1;
|
|
|
|
}
|
|
|
|
*AuthData = pAuth ;
|
|
|
|
return TRUE ;
|
|
|
|
Error_Cleanup:
|
|
|
|
LocalFree( pAuth );
|
|
|
|
return FALSE ;
|
|
|
|
}
|
|
#endif
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: LsapUpdateCredentials
|
|
//
|
|
// Synopsis: This function provides a mechanism for one package to notify
|
|
// another package that the credentials for a logon session
|
|
// have changed.
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: PrimaryCredentials - Primary information about the user.
|
|
// All fields may be NULL but the LogonId
|
|
// Credentials - Array of credentials for different packages
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
LsapUpdateCredentials(
|
|
IN PSECPKG_PRIMARY_CRED PrimaryCredentials,
|
|
IN OPTIONAL PSECPKG_SUPPLEMENTAL_CRED_ARRAY Credentials
|
|
)
|
|
{
|
|
return(LsapUpdateCredentialsWorker(
|
|
(SECURITY_LOGON_TYPE) 0, // no logon type
|
|
NULL, // no account name
|
|
PrimaryCredentials,
|
|
Credentials ));
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: LsapUpdateCredentialsWorker
|
|
//
|
|
// Synopsis: Worker function for updated credentials - calls all package
|
|
// with specified credentials
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
NTSTATUS
|
|
LsapUpdateCredentialsWorker(
|
|
IN SECURITY_LOGON_TYPE LogonType,
|
|
IN PUNICODE_STRING AccountName,
|
|
IN PSECPKG_PRIMARY_CRED PrimaryCredentials,
|
|
IN OPTIONAL PSECPKG_SUPPLEMENTAL_CRED_ARRAY Credentials
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG_PTR CurrentPackageId;
|
|
PLSAP_SECURITY_PACKAGE SupplementalPackage;
|
|
SupplementalPackage = SpmpIteratePackagesByRequest( NULL, SP_ORDINAL_ACCEPTCREDS );
|
|
|
|
CurrentPackageId = GetCurrentPackageId();
|
|
while (SupplementalPackage)
|
|
{
|
|
|
|
if (SupplementalPackage->dwPackageID != CurrentPackageId)
|
|
{
|
|
ULONG Index;
|
|
PSECPKG_SUPPLEMENTAL_CRED SuppCreds;
|
|
|
|
//
|
|
// For all packages, do the accept call so the
|
|
// package can associate the credentials with
|
|
// the logon session.
|
|
//
|
|
|
|
DebugLog((DEB_TRACE_WAPI, "Whacking package %ws with %x:%x = %wZ\n",
|
|
SupplementalPackage->Name.Buffer,
|
|
PrimaryCredentials->LogonId.HighPart, PrimaryCredentials->LogonId.LowPart,
|
|
AccountName));
|
|
|
|
|
|
SetCurrentPackageId( SupplementalPackage->dwPackageID );
|
|
|
|
//
|
|
// Find any supplmental credentials
|
|
//
|
|
|
|
SuppCreds = NULL;
|
|
if (Credentials != NULL)
|
|
{
|
|
for (Index = 0; Index < Credentials->CredentialCount ; Index++ ) {
|
|
if (RtlEqualUnicodeString(
|
|
&Credentials->Credentials[Index].PackageName,
|
|
&SupplementalPackage->Name,
|
|
TRUE))
|
|
{
|
|
SuppCreds = &Credentials->Credentials[Index];
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
__try
|
|
{
|
|
Status = SupplementalPackage->FunctionTable.AcceptCredentials(
|
|
LogonType,
|
|
AccountName,
|
|
PrimaryCredentials,
|
|
SuppCreds
|
|
);
|
|
}
|
|
__except (SP_EXCEPTION)
|
|
{
|
|
Status = GetExceptionCode();
|
|
Status = SPException(Status, SupplementalPackage->dwPackageID);
|
|
}
|
|
|
|
|
|
// Note: if an exception occurs, we don't fail the logon, we just
|
|
// do the magic on the package that blew. If the package blows,
|
|
// the other packages may succeed, and so the user may not be able
|
|
// to use that provider.
|
|
|
|
}
|
|
|
|
SupplementalPackage = SpmpIteratePackagesByRequest(
|
|
SupplementalPackage,
|
|
SP_ORDINAL_ACCEPTCREDS
|
|
);
|
|
|
|
}
|
|
return(STATUS_SUCCESS);
|
|
}
|