//+----------------------------------------------------------------------- // // 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 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); }